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

作者:BusyMonkey 时间:2023-06-05 10:17:32 

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>

来源:http://blog.csdn.net/Dopamy_BusyMonkey/article/details/42639169

标签:Android,OpenCV2.4.10,二维码
0
投稿

猜你喜欢

  • C#表达式树讲解

    2023-02-23 19:22:52
  • Android编程实现获取新浪天气预报数据的方法

    2022-08-15 22:14:44
  • 带你了解Java数据结构和算法之队列

    2022-07-03 12:45:34
  • 深入了解Java核心类库--BigDecimal和System类

    2023-12-18 01:50:28
  • 使用C语言编写基于TCP协议的Socket通讯程序实例分享

    2023-07-05 03:30:03
  • java 安全 ysoserial CommonsCollections6 分析

    2021-06-04 01:58:14
  • Android实现EditText的富文本编辑

    2022-04-14 21:44:29
  • 为什么rest接口返回json建议采用下划线形式,不要用驼峰

    2023-06-24 23:23:16
  • 基于Mybatis plus 自动代码生成器的实现代码

    2023-11-24 10:40:51
  • Java 定时任务技术趋势详情

    2021-10-29 14:48:13
  • 使用java8 API遍历过滤文件目录及子目录和隐藏文件示例详解

    2023-08-29 02:42:29
  • 利用Kotlin开发你的第一个Android应用

    2022-04-23 14:39:53
  • Java try catch finally异常处理组合详解

    2021-07-04 18:19:51
  • SpringAOP切点函数实现原理详解

    2021-09-05 11:00:59
  • C#中的多播委托和泛型委托

    2022-03-23 19:17:28
  • C# 8.0中的范围类型(Range Type)示例详解

    2023-04-11 22:26:10
  • C++如何通过ostringstream实现任意类型转string

    2022-06-27 16:23:06
  • Android如何获取系统通知的开启状态详解

    2021-12-28 05:45:09
  • 防止未登录用户操作—基于struts2拦截器的简单实现

    2021-06-11 13:21:00
  • Java Socket实现多人聊天系统

    2023-08-08 04:44:35
  • asp之家 软件编程 m.aspxhome.com