Preface
I recently wrote a mobile AR system from scratch. There are too many pitfalls !!! The entire project uses the OpenCV third-party library, but for cameras, the method is basically the same as that of native Camera.
Implementation
Taking JavaCameraView of OpenCV as an example, you must first customize your own Camera. The main code is as follows:
import java.util.ArrayList;import java.util.List;import org.opencv.android.JavaCameraView;import android.R.integer;import android.content.Context;import android.graphics.Rect;import android.graphics.RectF;import android.hardware.Camera;import android.hardware.Camera.AutoFocusCallback;import android.util.AttributeSet;import android.view.MotionEvent;import android.widget.Toast;public class MTCameraView extends JavaCameraView implements AutoFocusCallback {public MTCameraView(Context context, int attrs) {super(context, attrs);// TODO Auto-generated constructor stub}public List
getResolutionList() { return mCamera.getParameters().getSupportedPreviewSizes(); }public Camera.Size getResolution() { Camera.Parameters params = mCamera.getParameters(); Camera.Size s = params.getPreviewSize(); return s;}public void setResolution(Camera.Size resolution) { disconnectCamera(); connectCamera((int)resolution.width, (int)resolution.height); }public void focusOnTouch(MotionEvent event) { Rect focusRect = calculateTapArea(event.getRawX(), event.getRawY(), 1f); Rect meteringRect = calculateTapArea(event.getRawX(), event.getRawY(), 1.5f); Camera.Parameters parameters = mCamera.getParameters(); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); if (parameters.getMaxNumFocusAreas() > 0) { List
focusAreas = new ArrayList
(); focusAreas.add(new Camera.Area(focusRect, 1000)); parameters.setFocusAreas(focusAreas); } if (parameters.getMaxNumMeteringAreas() > 0) { List
meteringAreas = new ArrayList
(); meteringAreas.add(new Camera.Area(meteringRect, 1000)); parameters.setMeteringAreas(meteringAreas); } mCamera.setParameters(parameters); mCamera.autoFocus(this);}/** * Convert touch position x:y to {@link Camera.Area} position -1000:-1000 to 1000:1000. */private Rect calculateTapArea(float x, float y, float coefficient) {float focusAreaSize = 300; int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue(); int centerX = (int) (x / getResolution().width - 1000); int centerY = (int) (y / getResolution().height - 1000); int left = clamp(centerX - areaSize / 2, -1000, 1000); int top = clamp(centerY - areaSize / 2, -1000, 1000); RectF rectF = new RectF(left, top, left + areaSize, top + areaSize); return new Rect(Math.round(rectF.left), Math.round(rectF.top), Math.round(rectF.right), Math.round(rectF.bottom));}private int clamp(int x, int min, int max) { if (x > max) { return max; } if (x < min) { return min; } return x;}public void setFocusMode (Context item, int type){ Camera.Parameters params = mCamera.getParameters(); List
FocusModes = params.getSupportedFocusModes(); switch (type){ case 0: if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); else Toast.makeText(item, "Auto Mode not supported", Toast.LENGTH_SHORT).show(); break; case 1: if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); else Toast.makeText(item, "Continuous Mode not supported", Toast.LENGTH_SHORT).show(); break; case 2: if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_EDOF)) params.setFocusMode(Camera.Parameters.FOCUS_MODE_EDOF); else Toast.makeText(item, "EDOF Mode not supported", Toast.LENGTH_SHORT).show(); break; case 3: if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) params.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED); else Toast.makeText(item, "Fixed Mode not supported", Toast.LENGTH_SHORT).show(); break; case 4: if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) params.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY); else Toast.makeText(item, "Infinity Mode not supported", Toast.LENGTH_SHORT).show(); break; case 5: if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_MACRO)) params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO); else Toast.makeText(item, "Macro Mode not supported", Toast.LENGTH_SHORT).show(); break; } mCamera.setParameters(params);}public void setFlashMode (Context item, int type){ Camera.Parameters params = mCamera.getParameters(); List
FlashModes = params.getSupportedFlashModes(); switch (type){ case 0: if (FlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)) params.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO); else Toast.makeText(item, "Auto Mode not supported", Toast.LENGTH_SHORT).show(); break; case 1: if (FlashModes.contains(Camera.Parameters.FLASH_MODE_OFF)) params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); else Toast.makeText(item, "Off Mode not supported", Toast.LENGTH_SHORT).show(); break; case 2: if (FlashModes.contains(Camera.Parameters.FLASH_MODE_ON)) params.setFlashMode(Camera.Parameters.FLASH_MODE_ON); else Toast.makeText(item, "On Mode not supported", Toast.LENGTH_SHORT).show(); break; case 3: if (FlashModes.contains(Camera.Parameters.FLASH_MODE_RED_EYE)) params.setFlashMode(Camera.Parameters.FLASH_MODE_RED_EYE); else Toast.makeText(item, "Red Eye Mode not supported", Toast.LENGTH_SHORT).show(); break; case 4: if (FlashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); else Toast.makeText(item, "Torch Mode not supported", Toast.LENGTH_SHORT).show(); break; } mCamera.setParameters(params);}@Overridepublic void onAutoFocus(boolean arg0, Camera arg1) { }}
MTCamera needs to be initialized in MainActivity and the OnTouchListener interface must be implemented to call the onTouch function when you touch the screen. The main code is as follows:
private MTCameraView mOpenCvCameraView;public void init() {mOpenCvCameraView = new MTCameraView(this, -1);mOpenCvCameraView.setCvCameraViewListener(this);mOpenCvCameraView.setFocusable(true);mOpenCvCameraView.setOnTouchListener(MainActivity.this);mOpenCvCameraView.enableView();FrameLayout frame = new FrameLayout(this);frame.addView(mOpenCvCameraView);setContentView(frame); }@Overridepublic boolean onTouch(View arg0, MotionEvent arg1) {// TODO Auto-generated method stubmOpenCvCameraView.focusOnTouch(arg1);return true;}
The init () function is a custom initialization function that can be used in onCreate. Because the OpenCV library is used here, the init () function is called only after the OpenCV library is loaded and determined successfully.
Explanation
When a touch event occurs, MainActivity implements the OnTouchListener interface, so it calls the override onTouch function and passes the second parameter MotionEvent to MTCamera to locate the Touch Location.
The focusOnTouch function of MTCamera continues to work. It calculates the size of the focus and metering areas based on the touch position (via the calculateTapArea function), creates a new Camera. Parameters, and sets the Camera focus mode to Auto.
Then, it determines whether the camera of the device supports setting the focus area and the metering area. If the camera supports setting the focus area and the metering area calculated previously for parameters respectively.
Finally, let Camera auto focus.
CalculateTapArea Function
This function converts the screen coordinate system to the focus coordinate system. By MotionEvent. getRowX () obtains the coordinates based on the screen coordinate system (that is, the upper-left corner of the screen is the origin, and the lower-right corner is your current screen resolution, in the unit of one pixel, the range of each Area in the List accepted by setFocusAreas is (-1000,-1000) to (1000,100 0), that is, the center of the screen is the origin, and the upper left corner is (-1000,-1000 ), the bottom right corner is ). Note: If this parameter is exceeded, the setParemeters failed error will be reported! In addition, we define the size of a focus frame (metering frame) in advance, and accept a parameter (the third parameter coefficient) as the percentage.
Now the touch focus function has been completed.
However, we can find that there is a lot of code in MTCamera, mainly two functions setFocusMode and setFlashMode. These two functions are mainly because my images are often blurred in projects, but I do not know that the focus mode is supported by the system. You can use these two functions for testing. You need to add the code in the menu bar in MainActivity for selection. The Code is as follows:
private List
mResolutionList; private MenuItem[] mResolutionMenuItems; private MenuItem[] mFocusListItems; private MenuItem[] mFlashListItems; private SubMenu mResolutionMenu; private SubMenu mFocusMenu; private SubMenu mFlashMenu; @Override public boolean onCreateOptionsMenu(Menu menu) { Log.i(TAG, "called onCreateOptionsMenu"); List
mFocusList = new LinkedList
(); int idx =0; mFocusMenu = menu.addSubMenu("Focus"); mFocusList.add("Auto"); mFocusList.add("Continuous Video"); mFocusList.add("EDOF"); mFocusList.add("Fixed"); mFocusList.add("Infinity"); mFocusList.add("Makro"); mFocusList.add("Continuous Picture"); mFocusListItems = new MenuItem[mFocusList.size()]; ListIterator
FocusItr = mFocusList.listIterator(); while(FocusItr.hasNext()){ // add the element to the mDetectorMenu submenu String element = FocusItr.next(); mFocusListItems[idx] = mFocusMenu.add(2,idx,Menu.NONE,element); idx++; } List
mFlashList = new LinkedList
(); idx = 0; mFlashMenu = menu.addSubMenu("Flash"); mFlashList.add("Auto"); mFlashList.add("Off"); mFlashList.add("On"); mFlashList.add("Red-Eye"); mFlashList.add("Torch"); mFlashListItems = new MenuItem[mFlashList.size()]; ListIterator
FlashItr = mFlashList.listIterator(); while(FlashItr.hasNext()){ // add the element to the mDetectorMenu submenu String element = FlashItr.next(); mFlashListItems[idx] = mFlashMenu.add(3,idx,Menu.NONE,element); idx++; } mResolutionMenu = menu.addSubMenu("Resolution"); mResolutionList = mOpenCvCameraView.getResolutionList(); mResolutionMenuItems = new MenuItem[mResolutionList.size()]; ListIterator
resolutionItr = mResolutionList.listIterator(); idx = 0; while(resolutionItr.hasNext()) { Camera.Size element = resolutionItr.next(); mResolutionMenuItems[idx] = mResolutionMenu.add(1, idx, Menu.NONE, Integer.valueOf((int) element.width).toString() + "x" + Integer.valueOf((int) element.height).toString()); idx++; } return true; } public boolean onOptionsItemSelected(MenuItem item) { Log.i(TAG, "called onOptionsItemSelected; selected item: " + item); if (item.getGroupId() == 1) { int id = item.getItemId(); Camera.Size resolution = mResolutionList.get(id); mOpenCvCameraView.setResolution(resolution); resolution = mOpenCvCameraView.getResolution(); String caption = Integer.valueOf((int) resolution.width).toString() + "x" + Integer.valueOf((int) resolution.height).toString(); Toast.makeText(this, caption, Toast.LENGTH_SHORT).show(); } else if (item.getGroupId()==2){ int focusType = item.getItemId(); mOpenCvCameraView.setFocusMode(this, focusType); } else if (item.getGroupId()==3){ int flashType = item.getItemId(); mOpenCvCameraView.setFlashMode(this, flashType); } return true; }
After this operation, you can click the menu to view the three basket lists: Focus (Focus mode), Flash (video mode), and Resolution (Resolution supported ). The focus mode and video mode provide several common modes for selection. The Code determines whether the current device supports this mode. The resolution menu bar displays all resolution types supported by the current device.
Reference
StackOverFlow discussion on touch focus Android multimedia and Camera explanations 10 interpretation of the design concept of Android 4.0 Camera native applications question on OpenCV: ANDROID: Use autofocus with CameraBridgeViewBase?