Android调用OpenCV2.4.10实现二维码区域定位

Android上使调用OpenCV 2.4.10 实现二维码区域定位(Z-xing 码),该文章主要用于笔者自己学习中的总结,暂贴出代码部分,待以后有时间再补充算法的详细细节。

Activity class Java 文件

package cn.hjq.android_capture; 
 
import java.io.BufferedWriter; 
import java.io.File; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.OutputStreamWriter; 
import java.util.ArrayList; 
import java.util.List; 
 
import org.opencv.android.BaseLoaderCallback; 
import org.opencv.android.LoaderCallbackInterface; 
import org.opencv.android.OpenCVLoader; 
import org.opencv.core.*; 
import org.opencv.highgui.*; 
import org.opencv.imgproc.*; 
import org.opencv.utils.Converters; 
 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Matrix; 
import android.hardware.Camera; 
import android.hardware.Camera.AutoFocusCallback; 
import android.hardware.Camera.Parameters; 
import android.hardware.Camera.PictureCallback; 
import android.os.Bundle; 
import android.os.Environment; 
import android.os.Handler; 
import android.app.Activity; 
import android.content.pm.ActivityInfo; 
import android.view.MotionEvent; 
import android.view.SurfaceHolder; 
import android.view.SurfaceHolder.Callback; 
import android.view.SurfaceView; 
import android.view.View; 
 
public class capture extends Activity { 
 private SurfaceView picSV; 
 private Camera camera; 
 private String strPicPath; 
  
 //OpenCV类库加载并初始化成功后的回调函数,在此我们不进行任何操作 
 private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { 
  @Override 
  public void onManagerConnected(int status) { 
   switch (status) { 
    case LoaderCallbackInterface.SUCCESS:{ 
    } break; 
    default:{ 
     super.onManagerConnected(status); 
    } break; 
   } 
  } 
 }; 
  
 @SuppressWarnings("deprecation") 
 @Override 
 protected void onCreate(Bundle savedInstanceState) { 
  super.onCreate(savedInstanceState); 
  this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 
  setContentView(R.layout.main); 
  picSV = (SurfaceView) findViewById(R.id.picSV); 
  picSV.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
  picSV.getHolder().addCallback(new MyCallback()); 
 } 
 
 private class MyCallback implements Callback{ 
 //我们在SurfaceView创建的时候就要进行打开摄像头、设置预览取景所在的SurfaceView、设置拍照的参数、开启预览取景等操作 
  @Override 
  public void surfaceCreated(SurfaceHolder holder) { 
   try { 
    camera = Camera.open();//打开摄像头 
    camera.setPreviewDisplay(picSV.getHolder());//设置picSV来进行预览取景 
    Parameters params = camera.getParameters();//获取照相机的参数 
    params.setPictureSize(800, 480);//设置照片的大小为800*480 
    params.setPreviewSize(800, 480);//设置预览取景的大小为800*480 
    params.setFlashMode("auto");//开启闪光灯 
    params.setJpegQuality(50);//设置图片质量为50   
    camera.setParameters(params);//设置以上参数为照相机的参数 
    camera.startPreview(); 
   } 
   catch (IOException e) {    //开始预览取景,然后我们就可以拍照了 
    e.printStackTrace(); 
   } 
  } 
  
  @Override 
  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 
  } 
  
  @Override 
  public void surfaceDestroyed(SurfaceHolder holder) { 
   //当SurfaceView销毁时,我们进行停止预览、释放摄像机、垃圾回收等工作 
   camera.stopPreview(); 
   camera.release(); 
   camera = null; 
  } 
 } 
 
 public void takepic(View v){ 
  //在我们开始拍照前,实现自动对焦 
  camera.autoFocus(new MyAutoFocusCallback()); 
 } 
 
 private class MyAutoFocusCallback implements AutoFocusCallback{ 
  @Override 
  public void onAutoFocus(boolean success, Camera camera) { 
   //开始拍照 
   camera.takePicture(null, null, null, new MyPictureCallback()); 
  } 
 } 
 
 private class MyPictureCallback implements PictureCallback{ 
  @Override 
  public void onPictureTaken(byte[] data, Camera camera) { 
   try { 
    Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 
    Matrix matrix = new Matrix(); 
    matrix.preRotate(90); 
    bitmap = Bitmap.createBitmap(bitmap ,0,0, bitmap.getWidth(), 
            bitmap.getHeight(),matrix,true); 
    strPicPath = 
     Environment.getExternalStorageDirectory()+"/1Zxing/"+System.currentTimeMillis()+".jpg"; 
    FileOutputStream fos = new FileOutputStream( strPicPath ); 
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); 
    fos.close(); 
    Handler mHandler = new Handler(); 
    mHandler.post(mRunnable); 
    camera.startPreview(); 
   } 
   catch (Exception e) { 
    e.printStackTrace(); 
   } 
  } 
 } 
  
 public boolean onTouchEvent (MotionEvent event) 
 { 
  int Action = event.getAction(); 
  if ( 1 == Action ) { 
   camera.autoFocus(new MyAutoFocusCallback1()); 
  } 
  return true; 
 } 
  
 private class MyAutoFocusCallback1 implements AutoFocusCallback { 
  @Override 
  public void onAutoFocus(boolean success, Camera camera) { 
  } 
 } 
  
 @Override 
 public void onResume(){ 
  super.onResume(); 
  //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 
  //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存在于OpenCV安装包的apk目录中 
  OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_10, this, mLoaderCallback); 
 } 
 
 Runnable mRunnable = new Runnable() { 
  public void run() { 
   List<MatOfPoint> contours = new ArrayList<MatOfPoint>(); 
   String strMissingTime = null; 
   Mat srcColor = new Mat(), srcColorResize = new Mat(); 
   Mat srcGray = new Mat(), srcGrayResize = new Mat(), srcGrayResizeThresh = new Mat(); 
   srcGray = Highgui.imread(strPicPath, 0); 
   srcColor = Highgui.imread(strPicPath, 1); 
   Imgproc.resize(srcGray, srcGrayResize, new Size(srcGray.cols()*0.2,srcGray.rows()*0.2)); 
   Imgproc.resize(srcColor, srcColorResize, new Size(srcGray.cols()*0.2,srcGray.rows()*0.2)); 
   long start = System.currentTimeMillis(); 
   //二值化加轮廓寻找 
   Imgproc.adaptiveThreshold(srcGrayResize, srcGrayResizeThresh, 255, 
          Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, 
          Imgproc.THRESH_BINARY, 35, 5); 
   Imgproc.findContours(srcGrayResizeThresh, contours, new Mat(), 
         Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_NONE); 
   long end = System.currentTimeMillis(); 
   strMissingTime = String.valueOf( end - start ); 
   strMissingTime = strMissingTime + "\r"; 
   //轮廓绘制 
   for ( int i = contours.size()-1; i >= 0; i-- ) 
   { 
    MatOfPoint2f NewMtx = new MatOfPoint2f( contours.get(i).toArray() ); 
    RotatedRect rotRect = Imgproc.minAreaRect( NewMtx ); 
    Point vertices[] = new Point[4]; 
    rotRect.points(vertices); 
    List<Point> rectArea = new ArrayList<Point>(); 
    for ( int n = 0; n < 4; n ++ ) 
    { 
     Point temp = new Point(); 
     temp.x = vertices[n].x; 
     temp.y = vertices[n].y; 
     rectArea.add(temp); 
    } 
    Mat rectMat = Converters.vector_Point_to_Mat(rectArea); 
    double minRectArea = Imgproc.contourArea( rectMat ); 
    Point center = new Point(); 
    float radius[] = {0}; 
    Imgproc.minEnclosingCircle(NewMtx, center, radius); 
    if( 
     Imgproc.contourArea( contours.get(i)) < 300 || 
     Imgproc.contourArea( contours.get(i)) > 3000 
     || minRectArea < radius[0]*radius[0]*1.57 
    ) contours.remove(i); 
   } 
   Imgproc.drawContours(srcColorResize, contours, -1, new Scalar(255,0,0)); 
   Highgui.imwrite(Environment.getExternalStorageDirectory()+"/1Zxing/" 
       +System.currentTimeMillis()+"contour.jpg", srcColorResize);   
   File file=new File(Environment.getExternalStorageDirectory()+"/1Zxing/","log.txt"); 
   BufferedWriter out = null; 
   try { 
    out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true))); 
    out.write(strMissingTime); 
    out.close(); 
   } 
   catch (Exception e) { 
    e.printStackTrace(); 
   }    
  } 
 }; 
} 

layout.xml 文件

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 xmlns:tools="http://schemas.android.com/tools" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 tools:context=".MainActivity" > 
  
 <SurfaceView 
  android:id="@+id/picSV" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" 
  > 
 </SurfaceView> 
  
 <ImageButton 
  android:contentDescription="@string/desc" 
  android:onClick="takepic" 
  android:layout_width="wrap_content" 
  android:layout_height="wrap_content" 
  android:layout_gravity="right|top" 
  android:src="@android:drawable/ic_menu_camera" /> 
  
</FrameLayout> 

string.xml 文件

<resources> 
 <string name="app_name">Code</string> 
 <string name="desc">Take picture button</string> 
</resources> 

style.xml 文件(理论上是可以自动生成,若自动生成内容有错,可以参考)

<resources> 
 
 <!-- 
  Base application theme, dependent on API level. This theme is replaced 
  by AppBaseTheme from res/values-vXX/styles.xml on newer devices. 
 --> 
 <style name="AppBaseTheme" parent="android:Theme.Light"> 
  <!-- 
   Theme customizations available in newer API levels can go in 
   res/values-vXX/styles.xml, while customizations related to 
   backward-compatibility can go here. 
  --> 
 </style> 
 
 <!-- Application theme. --> 
 <style name="AppTheme" parent="AppBaseTheme"> 
  <!-- All customizations that are NOT specific to a particular API-level can go here. --> 
  <item name="android:windowNoTitle">true</item> 
  <item name="android:windowFullscreen">true</item> 
 </style> 
 
 
</resources> 

AndroidManifest.xml 文件

<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
 package="cn.hjq.android_capture" 
 android:versionCode="1" 
 android:versionName="1.0" > 
  
 <uses-permission 
  android:name="android.permission.CAMERA"/> 
 <uses-permission 
  android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
 
 <uses-sdk 
  android:minSdkVersion="8" 
  android:targetSdkVersion="19" /> 
 
 <application 
  android:allowBackup="true" 
  android:icon="@drawable/ic_launcher" 
  android:label="@string/app_name" 
  android:theme="@style/AppTheme" > 
  <activity 
   android:name=".capture" > 
   <intent-filter > 
    <action android:name="android.intent.action.MAIN" /> 
    <category android:name="android.intent.category.LAUNCHER" /> 
   </intent-filter> 
  </activity> 
 </application> 
 
</manifest> 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

代码技巧

转载请关注公众号:代码技巧 回复:授权

本文链接地址:https://www.oudahe.com/p/51978/