Android calls OpenCV2.4. 10 to locate the two dimensional code area
- 2021-08-21 21:36:18
- OfStack
On Android, call OpenCV 2.4. 10 to realize 2-D code area positioning (Z-xing code). This article is mainly used for the summary of the author's own study, and the code part is posted temporarily, and the detailed details of the algorithm will be supplemented later.
Activity class Java File
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 The callback function after the class library is loaded and initialized successfully, so we don't do anything here
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{
// We're in SurfaceView When creating, it is necessary to open the camera and set the preview framing place SurfaceView Set the parameters of taking pictures, start preview framing and other operations
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera = Camera.open();// Turn on the camera
camera.setPreviewDisplay(picSV.getHolder());// Settings picSV To preview and framing
Parameters params = camera.getParameters();// Get the parameters of the camera
params.setPictureSize(800, 480);// Set the size of the photo to 800*480
params.setPreviewSize(800, 480);// Set the size of preview framing to 800*480
params.setFlashMode("auto");// Turn on the flash
params.setJpegQuality(50);// Set the picture quality to 50
camera.setParameters(params);// Set the above parameters as camera parameters
camera.startPreview();
}
catch (IOException e) { // Start previewing and framing, and then we can take pictures
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// When SurfaceView When destroying, we do stop preview, release camera, garbage collection and so on
camera.stopPreview();
camera.release();
camera = null;
}
}
public void takepic(View v){
// Before we start taking pictures, realize auto-focus
camera.autoFocus(new MyAutoFocusCallback());
}
private class MyAutoFocusCallback implements AutoFocusCallback{
@Override
public void onAutoFocus(boolean success, Camera camera) {
// Start taking pictures
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();
// Pass OpenCV Engine service loads and initializes OpenCV Class library, so-called OpenCV The engine service is
//OpenCV_2.4.3.2_Manager_2.4_*.apk Package that exists in the OpenCV Installation package's apk In the directory
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();
//2 Valuation plus contour finding
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";
// Contour drawing
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();
}
}
};
}
File 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 file
<resources>
<string name="app_name">Code</string>
<string name="desc">Take picture button</string>
</resources>
style. xml file (theoretically, it can be generated automatically. If the content of automatic generation is wrong, please refer to it)
<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 file
<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>