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>

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

02-07 15:39
查看更多