improving the Touch To Focus functionality

This commit is contained in:
tibbi 2018-06-01 11:59:37 +02:00
parent 94488adb24
commit 67b3b50fa8
2 changed files with 87 additions and 17 deletions

View File

@ -0,0 +1,5 @@
package com.simplemobiletools.camera.models
import android.graphics.Rect
data class FocusArea(val rect: Rect, val weight: Int)

View File

@ -3,9 +3,7 @@ package com.simplemobiletools.camera.views
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.content.Context
import android.graphics.ImageFormat
import android.graphics.Point
import android.graphics.SurfaceTexture
import android.graphics.*
import android.hardware.camera2.*
import android.hardware.camera2.params.MeteringRectangle
import android.media.ImageReader
@ -21,6 +19,7 @@ import android.view.ViewGroup
import com.simplemobiletools.camera.activities.MainActivity
import com.simplemobiletools.camera.helpers.*
import com.simplemobiletools.camera.interfaces.MyPreview
import com.simplemobiletools.camera.models.FocusArea
import java.util.*
import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit
@ -57,6 +56,8 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
private var mCaptureSession: CameraCaptureSession? = null
private var mPreviewRequestBuilder: CaptureRequest.Builder? = null
private var mPreviewRequest: CaptureRequest? = null
private val mCameraToPreviewMatrix = Matrix()
private val mPreviewToCameraMatrix = Matrix()
private val mCameraOpenCloseLock = Semaphore(1)
constructor(context: Context) : super(context)
@ -379,9 +380,6 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
private fun focusArea() {
mActivity.drawFocusCircle(mLastClickX, mLastClickY)
val characteristics = getCameraManager().getCameraCharacteristics(mCameraId)
val sensorArraySize = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE)
val captureCallbackHandler = object : CameraCaptureSession.CaptureCallback() {
override fun onCaptureCompleted(session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult) {
super.onCaptureCompleted(session, request, result)
@ -399,18 +397,14 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF)
mCaptureSession!!.capture(build(), captureCallbackHandler, mBackgroundHandler)
if (characteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF) >= 1) {
val x = (mLastClickX / mTextureView.width) * sensorArraySize.height()
val y = (mLastClickY / mTextureView.height) * sensorArraySize.width()
val halfTouchWidth = 150
val halfTouchHeight = 150
val focusAreaTouch = MeteringRectangle(Math.max(x - halfTouchWidth, 0f).toInt(),
Math.max(y - halfTouchHeight, 0f).toInt(),
halfTouchWidth * 2,
halfTouchHeight * 2,
MeteringRectangle.METERING_WEIGHT_MAX - 1)
val characteristics = getCameraManager().getCameraCharacteristics(mCameraId)
set(CaptureRequest.CONTROL_AF_REGIONS, arrayOf(focusAreaTouch))
// touch-to-focus inspired by OpenCamera
if (characteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF) >= 1) {
val focusArea = getFocusArea()
val sensorRect = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE)
val meteringRect = convertAreaToMeteringRectangle(sensorRect, focusArea)
set(CaptureRequest.CONTROL_AF_REGIONS, arrayOf(meteringRect))
}
set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO)
@ -421,6 +415,77 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
}
}
private fun convertAreaToMeteringRectangle(sensorRect: Rect, focusArea: FocusArea): MeteringRectangle {
val camera2Rect = convertRectToCamera2(sensorRect, focusArea.rect)
return MeteringRectangle(camera2Rect, focusArea.weight)
}
private fun convertRectToCamera2(cropRect: Rect, rect: Rect): Rect {
val leftF = (rect.left + 1000) / 2000.0
val topF = (rect.top + 1000) / 2000.0
val rightF = (rect.right + 1000) / 2000.0
val bottomF = (rect.bottom + 1000) / 2000.0
var left = (cropRect.left + leftF * (cropRect.width() - 1)).toInt()
var right = (cropRect.left + rightF * (cropRect.width() - 1)).toInt()
var top = (cropRect.top + topF * (cropRect.height() - 1)).toInt()
var bottom = (cropRect.top + bottomF * (cropRect.height() - 1)).toInt()
left = Math.max(left, cropRect.left)
right = Math.max(right, cropRect.left)
top = Math.max(top, cropRect.top)
bottom = Math.max(bottom, cropRect.top)
left = Math.min(left, cropRect.right)
right = Math.min(right, cropRect.right)
top = Math.min(top, cropRect.bottom)
bottom = Math.min(bottom, cropRect.bottom)
return Rect(left, top, right, bottom)
}
private fun getFocusArea(): FocusArea {
val coords = floatArrayOf(mLastClickX, mLastClickY)
calculateCameraToPreviewMatrix()
mPreviewToCameraMatrix.mapPoints(coords)
val focusX = coords[0].toInt()
val focusY = coords[1].toInt()
val focusSize = 50
val rect = Rect()
rect.left = focusX - focusSize
rect.right = focusX + focusSize
rect.top = focusY - focusSize
rect.bottom = focusY + focusSize
if (rect.left < -1000) {
rect.left = -1000
rect.right = rect.left + 2 * focusSize
} else if (rect.right > 1000) {
rect.right = 1000
rect.left = rect.right - 2 * focusSize
}
if (rect.top < -1000) {
rect.top = -1000
rect.bottom = rect.top + 2 * focusSize
} else if (rect.bottom > 1000) {
rect.bottom = 1000
rect.top = rect.bottom - 2 * focusSize
}
return FocusArea(rect, MeteringRectangle.METERING_WEIGHT_MAX)
}
private fun calculateCameraToPreviewMatrix() {
val yScale = if (getIsUsingFrontCamera()) -1 else 1
mCameraToPreviewMatrix.apply {
reset()
setScale(1f, yScale.toFloat())
postRotate(mSensorOrientation.toFloat())
postScale(mTextureView.width / 2000f, mTextureView.height / 2000f)
postTranslate(mTextureView.width / 2f, mTextureView.height / 2f)
invert(mPreviewToCameraMatrix)
}
}
private fun lockFocus() {
try {
mPreviewRequestBuilder!!.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START)