1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > [Android编程心得] Camera(OpenCV)自动对焦和触摸对焦的实现

[Android编程心得] Camera(OpenCV)自动对焦和触摸对焦的实现

时间:2019-05-24 16:42:15

相关推荐

[Android编程心得] Camera(OpenCV)自动对焦和触摸对焦的实现

/candycat1992/article/details/21617741

实现

以OpenCV的JavaCameraView为例,首先需要定制自己的Camera,主要代码如下:[java]view plaincopy print? importjava.util.ArrayList;importjava.util.List;importorg.opencv.android.JavaCameraView;importandroid.R.integer;importandroid.content.Context;importandroid.graphics.Rect;importandroid.graphics.RectF;importandroid.hardware.Camera;importandroid.hardware.Camera.AutoFocusCallback;importandroid.util.AttributeSet;importandroid.view.MotionEvent;importandroid.widget.Toast;publicclassMTCameraViewextendsJavaCameraViewimplementsAutoFocusCallback{publicMTCameraView(Contextcontext,intattrs){super(context,attrs);//TODOAuto-generatedconstructorstub}publicList<Camera.Size>getResolutionList(){returnmCamera.getParameters().getSupportedPreviewSizes();}publicCamera.SizegetResolution(){Camera.Parametersparams=mCamera.getParameters();Camera.Sizes=params.getPreviewSize();returns;}publicvoidsetResolution(Camera.Sizeresolution){disconnectCamera();connectCamera((int)resolution.width,(int)resolution.height);}publicvoidfocusOnTouch(MotionEventevent){RectfocusRect=calculateTapArea(event.getRawX(),event.getRawY(),1f);RectmeteringRect=calculateTapArea(event.getRawX(),event.getRawY(),1.5f);Camera.Parametersparameters=mCamera.getParameters();parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);if(parameters.getMaxNumFocusAreas()>0){List<Camera.Area>focusAreas=newArrayList<Camera.Area>();focusAreas.add(newCamera.Area(focusRect,1000));parameters.setFocusAreas(focusAreas);}if(parameters.getMaxNumMeteringAreas()>0){List<Camera.Area>meteringAreas=newArrayList<Camera.Area>();meteringAreas.add(newCamera.Area(meteringRect,1000));parameters.setMeteringAreas(meteringAreas);}mCamera.setParameters(parameters);mCamera.autoFocus(this);}/***Converttouchpositionx:yto{@linkCamera.Area}position-1000:-1000to1000:1000.*/privateRectcalculateTapArea(floatx,floaty,floatcoefficient){floatfocusAreaSize=300;intareaSize=Float.valueOf(focusAreaSize*coefficient).intValue();intcenterX=(int)(x/getResolution().width*2000-1000);intcenterY=(int)(y/getResolution().height*2000-1000);intleft=clamp(centerX-areaSize/2,-1000,1000);intright=clamp(left+areaSize,-1000,1000);inttop=clamp(centerY-areaSize/2,-1000,1000);intbottom=clamp(top+areaSize,-1000,1000);returnnewRect(left,top,right,bottom);}privateintclamp(intx,intmin,intmax){if(x>max){returnmax;}if(x<min){returnmin;}returnx;}publicvoidsetFocusMode(Contextitem,inttype){Camera.Parametersparams=mCamera.getParameters();List<String>FocusModes=params.getSupportedFocusModes();switch(type){case0:if(FocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO))params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);elseToast.makeText(item,"AutoModenotsupported",Toast.LENGTH_SHORT).show();break;case1:if(FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);elseToast.makeText(item,"ContinuousModenotsupported",Toast.LENGTH_SHORT).show();break;case2:if(FocusModes.contains(Camera.Parameters.FOCUS_MODE_EDOF))params.setFocusMode(Camera.Parameters.FOCUS_MODE_EDOF);elseToast.makeText(item,"EDOFModenotsupported",Toast.LENGTH_SHORT).show();break;case3:if(FocusModes.contains(Camera.Parameters.FOCUS_MODE_FIXED))params.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);elseToast.makeText(item,"FixedModenotsupported",Toast.LENGTH_SHORT).show();break;case4:if(FocusModes.contains(Camera.Parameters.FOCUS_MODE_INFINITY))params.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);elseToast.makeText(item,"InfinityModenotsupported",Toast.LENGTH_SHORT).show();break;case5:if(FocusModes.contains(Camera.Parameters.FOCUS_MODE_MACRO))params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);elseToast.makeText(item,"MacroModenotsupported",Toast.LENGTH_SHORT).show();break;}mCamera.setParameters(params);}publicvoidsetFlashMode(Contextitem,inttype){Camera.Parametersparams=mCamera.getParameters();List<String>FlashModes=params.getSupportedFlashModes();switch(type){case0:if(FlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO))params.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);elseToast.makeText(item,"AutoModenotsupported",Toast.LENGTH_SHORT).show();break;case1:if(FlashModes.contains(Camera.Parameters.FLASH_MODE_OFF))params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);elseToast.makeText(item,"OffModenotsupported",Toast.LENGTH_SHORT).show();break;case2:if(FlashModes.contains(Camera.Parameters.FLASH_MODE_ON))params.setFlashMode(Camera.Parameters.FLASH_MODE_ON);elseToast.makeText(item,"OnModenotsupported",Toast.LENGTH_SHORT).show();break;case3:if(FlashModes.contains(Camera.Parameters.FLASH_MODE_RED_EYE))params.setFlashMode(Camera.Parameters.FLASH_MODE_RED_EYE);elseToast.makeText(item,"RedEyeModenotsupported",Toast.LENGTH_SHORT).show();break;case4:if(FlashModes.contains(Camera.Parameters.FLASH_MODE_TORCH))params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);elseToast.makeText(item,"TorchModenotsupported",Toast.LENGTH_SHORT).show();break;}mCamera.setParameters(params);}@OverridepublicvoidonAutoFocus(booleanarg0,Cameraarg1){}}

在MainActivity中需要初始化MTCamera,并且实现OnTouchListener接口,以便在触摸屏幕时可以调用onTouch函数。其中主要代码如下:[java]view plaincopy print? privateMTCameraViewmOpenCvCameraView;publicvoidinit(){mOpenCvCameraView=newMTCameraView(this,-1);mOpenCvCameraView.setCvCameraViewListener(this);mOpenCvCameraView.setFocusable(true);mOpenCvCameraView.setOnTouchListener(MainActivity.this);mOpenCvCameraView.enableView();FrameLayoutframe=newFrameLayout(this);frame.addView(mOpenCvCameraView);setContentView(frame);}@OverridepublicbooleanonTouch(Viewarg0,MotionEventarg1){//TODOAuto-generatedmethodstubmOpenCvCameraView.focusOnTouch(arg1);returntrue;}

init()函数是自定义的初始化函数,可以在onCreate时使用。由于这里需要使用OpenCV库,所以本项目是在加载完OpenCV库并判断成功后才调用init()函数的。

解释

在发生触摸事件时,MainActivity由于实现了OnTouchListener接口,因此会调用重写的onTouch函数,并把它的第二个参数MotionEvent传递给MTCamera,以便定位触摸位置。 MTCamera的focusOnTouch函数继续工作。它首先根据触摸位置计算对焦和测光(metering)区域的大小(通过calculateTapArea函数),然后创建新的Camera.Parameters,并设置摄像机的对焦模式为Auto。 然后,它分别判断该设备的相机是否支持设置对焦区域和测光区域,如果支持就分别为parameters设置之前计算好的聚焦和测光区域。 最后,让Camera自动对焦。 calculateTapArea函数

这个函数主要实现从屏幕坐标系到对焦坐标系的转换。由MotionEvent.getRowX()得到的是以屏幕坐标系(即屏幕左上角为原点,右下角为你的当前屏幕分辨率,单位是一个像素)为准的坐标,而setFocusAreas接受的List<Area>中的每一个Area的范围是(-1000,-1000)到(1000, 1000),也就是说屏幕中心为原点,左上角为(-1000,-1000),右下角为(1000,1000)。注意,如果超出这个范围的话,会报setParemeters failed的错误哦!除此之外,我们还提前定义了一个对焦框(测光框)的大小,并且接受一个参数(第三个参数coefficient)作为百分比进行调节。

至此完成了触摸对焦的功能。 但是,可以发现MTCamera里还有很大部分代码,主要是两个函数setFocusMode和setFlashMode。这两个函数,主要是因为在项目中我的图像经常是模糊的,但不知道系统支持那么对焦模式。这时,就可以使用这两个函数进行测试。这还需要在MainActivity中添加菜单栏的代码,以便进行选择。代码如下:[java]view plaincopy print? privateList<Camera.Size>mResolutionList;privateMenuItem[]mResolutionMenuItems;privateMenuItem[]mFocusListItems;privateMenuItem[]mFlashListItems;privateSubMenumResolutionMenu;privateSubMenumFocusMenu;privateSubMenumFlashMenu;@OverridepublicbooleanonCreateOptionsMenu(Menumenu){Log.i(TAG,"calledonCreateOptionsMenu");List<String>mFocusList=newLinkedList<String>();intidx=0;mFocusMenu=menu.addSubMenu("Focus");mFocusList.add("Auto");mFocusList.add("ContinuousVideo");mFocusList.add("EDOF");mFocusList.add("Fixed");mFocusList.add("Infinity");mFocusList.add("Makro");mFocusList.add("ContinuousPicture");mFocusListItems=newMenuItem[mFocusList.size()];ListIterator<String>FocusItr=mFocusList.listIterator();while(FocusItr.hasNext()){//addtheelementtothemDetectorMenusubmenuStringelement=FocusItr.next();mFocusListItems[idx]=mFocusMenu.add(2,idx,Menu.NONE,element);idx++;}List<String>mFlashList=newLinkedList<String>();idx=0;mFlashMenu=menu.addSubMenu("Flash");mFlashList.add("Auto");mFlashList.add("Off");mFlashList.add("On");mFlashList.add("Red-Eye");mFlashList.add("Torch");mFlashListItems=newMenuItem[mFlashList.size()];ListIterator<String>FlashItr=mFlashList.listIterator();while(FlashItr.hasNext()){//addtheelementtothemDetectorMenusubmenuStringelement=FlashItr.next();mFlashListItems[idx]=mFlashMenu.add(3,idx,Menu.NONE,element);idx++;}mResolutionMenu=menu.addSubMenu("Resolution");mResolutionList=mOpenCvCameraView.getResolutionList();mResolutionMenuItems=newMenuItem[mResolutionList.size()];ListIterator<Camera.Size>resolutionItr=mResolutionList.listIterator();idx=0;while(resolutionItr.hasNext()){Camera.Sizeelement=resolutionItr.next();mResolutionMenuItems[idx]=mResolutionMenu.add(1,idx,Menu.NONE,Integer.valueOf((int)element.width).toString()+"x"+Integer.valueOf((int)element.height).toString());idx++;}returntrue;}publicbooleanonOptionsItemSelected(MenuItemitem){Log.i(TAG,"calledonOptionsItemSelected;selecteditem:"+item);if(item.getGroupId()==1){intid=item.getItemId();Camera.Sizeresolution=mResolutionList.get(id);mOpenCvCameraView.setResolution(resolution);resolution=mOpenCvCameraView.getResolution();Stringcaption=Integer.valueOf((int)resolution.width).toString()+"x"+Integer.valueOf((int)resolution.height).toString();Toast.makeText(this,caption,Toast.LENGTH_SHORT).show();}elseif(item.getGroupId()==2){intfocusType=item.getItemId();mOpenCvCameraView.setFocusMode(this,focusType);}elseif(item.getGroupId()==3){intflashType=item.getItemId();mOpenCvCameraView.setFlashMode(this,flashType);}returntrue;}

这样运行后,点击菜单就可以看见有三个菜篮列表:Focus(对焦模式),Flash(视频模式),Resolution(支持的分辨率)。对焦模式和视频模式中提供了几种常见的模式供选择,代码会判断当前设备是否支持该模式。而分辨率菜单栏会显示出当前设备支持的所有分辨率种类。

参考

StackOverFlow上关于触摸对焦的讨论Android多媒体和相机讲解十解读Android 4.0 Camera原生应用程序的设计思路OpenCV上的提问:ANDROID: Use autofocus with CameraBridgeViewBase?

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。