微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > 嵌入式系统设计讨论 > 7.MTX20开发板Android Studio+车牌识别算法解析(1)

7.MTX20开发板Android Studio+车牌识别算法解析(1)

时间:10-02 整理:3721RD 点击:
      首先说明所有车牌识别算法,我都是参考其他人的文章加上自己的一点点理解,希望通过这些文章让自己对车牌的原理、算法,Android版本实现、Android Studio的使用,Opencv一些变量、函数和调用库等有一些了解。因为目前车牌识别的整体算法尚未完全搞明白,所以先说说自己的一些研究后面在整体总结。【EasyPR,特意感谢其作者和其他贡献者。】
一)Android Studio2.2.2上加载Opencv库开发NDK。
第一步:新建工程app目录下build.gradle文件中添加下面的代码

  1.     sourceSets {
  2.         main {
  3.             jniLibs.srcDirs=['/home/gzh/AndroidStudioProjects/MyPlateLocate/app/src/main/opencv310_libs']
  4.         }
  5.     }

复制代码

第二步:新建工程app目录下CMakeLists.txt文件中添加下面的代码,注意路径要修改为自己使用的路径,也要创建对应的目录和文件。

  1. # Sets the minimum version of CMake required to build the native
  2. # library. You should either keep the default value or only pass a
  3. # value of 3.4.0 or lower.

  4. cmake_minimum_required(VERSION 3.4.1)
  5. #
  6. set(pathToProject ~/AndroidStudioProjects/MyPlateLocate)
  7. #OpenCV-android-sdk
  8. set(pathToOpenCv ~/linux-tools/OpenCV-android-sdk)
  9. #支持-std=gnu++11
  10. set(CMAKE_VERBOSE_MAKEFILE on)
  11. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
  12. include_directories(${pathToOpenCv}/sdk/native/jni/include)
  13. include_directories(${pathToProject}//app/src/main/cpp/platelocate/include)

  14. # Creates and names a library, sets it as either STATIC
  15. # or SHARED, and provides the relative paths to its source code.
  16. # You can define multiple libraries, and CMake builds it for you.
  17. # Gradle automatically packages shared libraries with your APK.

  18. add_library( # Sets the name of the library.
  19.              native-lib
  20.              #lib_opencv

  21.              # Sets the library as a shared library.
  22.              SHARED

  23.              # Provides a relative path to your source file(s).
  24.              # Associated headers in the same location as their source
  25.              # file are automatically included.
  26.              src/main/cpp/platelocate/src/platelocate.cpp
  27.              src/main/cpp/native-lib.cpp
  28.              )
  29. add_library( lib_opencv SHARED IMPORTED )
  30. #引入libopencv_java3.so
  31. set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION ${pathToProject}/app/src/main/opencv310_libs/${ANDROID_ABI}/libopencv_java3.so)
  32. # Searches for a specified prebuilt library and stores the path as a
  33. # variable. Because system libraries are included in the search path by
  34. # default, you only need to specify the name of the public NDK library
  35. # you want to add. CMake verifies that the library exists before
  36. # completing its build.

  37. find_library( # Sets the name of the path variable.
  38.               log-lib

  39.               # Specifies the name of the NDK library that
  40.               # you want CMake to locate.
  41.               log )

  42. # Specifies libraries CMake should link to your target library. You
  43. # can link multiple libraries, such as libraries you define in the
  44. # build script, prebuilt third-party libraries, or system libraries.

  45. target_link_libraries( # Specifies the target library.
  46.                        native-lib

  47.                        # Links the target library to the log library
  48.                        # included in the NDK.
  49.                        ${log-lib}
  50.                        lib_opencv
  51.                        )

复制代码


第三步:添加合适的代码,可以参考下面的灰度图转换实例,不过必须符合自己的实际情况。
二)Opencv  Mat类型如何在Java和NDK之间传递。
1)Mat在Java中定义,传递给NDK。
Mat rgbMat = new Mat();
myCvtColor(rgbMat.getNativeObjAddr(), grayMat.getNativeObjAddr(), COLOR_RGB2GRAY);


2)Mat在Java中获取,传递给Java。
Mat& mGr  = *(Mat*)imageGray;
Mat& mRgb = *(Mat*)faces;
3)在NDK中创建,然后作为函数返回值返回 ************方法未经验证
Mat *hist = new Mat();
// ...
return (jlong) hist;
此时Java中也要做相应转换才可以使用
long address = generateHistogram(bitmapMat.nativeObj);
Mat histogram = new Mat(address);************方法未经验证

三)灰度图转换实例
3)PlateRecognizer.java代码实现

  1. package com.example.gzh.myplatelocate;

  2. import android.content.Context;
  3. import android.util.Log;

  4. import org.opencv.core.Mat;

  5. /**
  6. * Created by gzh on 17-2-12.
  7. */

  8. public class PlateRecognizer {
  9.     // Used to load the 'native-lib' library on application startup.
  10.     static String TAG = "PlateRecognizer";
  11.     static {
  12.         System.loadLibrary("native-lib");
  13.        // System.loadLibrary("opencv_java3");
  14.     }
  15.     private Context mContext;
  16.     private String mSvmpath = "svm.xml";
  17.     private String mAnnpath = "ann.xml";
  18.     private boolean mRecognizerInited = false;
  19.     private long mRecognizerPtr = 0;

  20.     public PlateRecognizer(Context context) {
  21.         mContext = context;
  22.              mRecognizerPtr = initPR();
  23.             if (0 != mRecognizerPtr) {
  24.                 mRecognizerInited = true;

  25.         }
  26.     }

  27.     public void finalize() {
  28.         uninitPR(mRecognizerPtr);
  29.         mRecognizerPtr = 0;
  30.         mRecognizerInited = false;
  31.     }
  32.     public void my_SobelOper(Mat rgbMat, Mat grayMat, int COLOR_RGB2GRAY) {
  33.         Log.i(TAG, "my_SobelOper=1=");
  34.         mySobelOper(mRecognizerPtr, rgbMat.getNativeObjAddr(), grayMat.getNativeObjAddr());//rgbMat to gray grayMat
  35.         Log.i(TAG, "my_SobelOper=2=");
  36.     }
  37.     public void my_CvtColor(Mat rgbMat, Mat grayMat, int COLOR_RGB2GRAY) {
  38.         Log.i(TAG, "my_CvtColor=1=");
  39.         myCvtColor(rgbMat.getNativeObjAddr(), grayMat.getNativeObjAddr(), COLOR_RGB2GRAY);//rgbMat to gray grayMat
  40.         Log.i(TAG, "my_CvtColor=2=");
  41.     }
  42.     /**
  43.      * A native method that is implemented by the 'native-lib' native library,
  44.      * which is packaged with this application.
  45.      */
  46.     public static native String stringFromJNI();

  47.     //public static native String validate(long matAddrGr, long matAddrRgba);

  48.     //图像处理
  49.     private static native void myCvtColor(long thiz, long inputImage, long faces);
  50.     public static native int[] getGrayImage(int[] pixels, int w, int h);
  51.     public static native long initPR();
  52.     public static native long uninitPR(long recognizerPtr);
  53.     public static native void mySobelOper(long recognizerPtr, long inputImage, long faces);
  54. }

复制代码

4)PlateRecognizer.java函数调用代码

  1.     public void procSrc2Gray(){
  2.         int nFalg_test = 2;
  3.         Mat rgbMat = new Mat();
  4.         Mat grayMat = new Mat();
  5.         srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.heidfk640);
  6.         grayBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), Bitmap.Config.RGB_565);
  7.         Utils.bitmapToMat(srcBitmap, rgbMat);//convert original bitmap to Mat, R G B.
  8.           if(nFalg_test == 1)
  9.           {
  10.               String str1 = null;
  11.               str1 = String.format("call my_CvtColor rgbMat.channels()=%d", rgbMat.channels());
  12.               Log.i(TAG, str1);
  13.               mPlateRecognizer.my_CvtColor(rgbMat, grayMat, COLOR_RGB2GRAY);//rgbMat to gray grayMat
  14.               // Then convert the processed Mat to Bitmap
  15.               Log.i(TAG, "call my_CvtColor sucess...=2=");
  16.           }
  17.           else {
  18.               String str1 = null;
  19.               str1 = String.format("call my_SobelOper rgbMat.channels()=%d", rgbMat.channels());
  20.               Log.i(TAG, str1);
  21.               mPlateRecognizer.my_SobelOper(rgbMat, grayMat, COLOR_RGB2GRAY);//rgbMat to gray grayMat
  22.               // Then convert the processed Mat to Bitmap
  23.               Log.i(TAG, "call my_SobelOper sucess...=2=");
  24.           }

  25.         Utils.matToBitmap(grayMat, grayBitmap);
  26.         Log.i(TAG, "procSrc2Gray sucess...=3=");

  27.         show_image.setImageBitmap(grayBitmap);

  28.         Log.i(TAG, "procSrc2Gray sucess...");
  29.     }

复制代码

5)mySobelOper函数NDK调用

  1. extern "C"
  2. JNIEXPORT void JNICALL
  3. Java_com_example_gzh_myplatelocate_PlateRecognizer_mySobelOper
  4.         (JNIEnv * jenv,
  5.          jlong thiz,
  6.          jlong recognizerPtr,
  7.          jlong imageGray, jlong faces)
  8. {

  9.     Mat imgData_out;


  10.     Mat& mGr  = *(Mat*)imageGray;
  11.     Mat& mRgb = *(Mat*)faces;

  12.     LOGE("=1= Java_com_example_gzh_myplatelocate_PlateRecognizer_mySobelOper");
  13. LOGE("=2= mGr.cols=%d", mGr.cols);
  14. LOGE("=2= mGr.rows=%d", mGr.rows);
  15. LOGE("=2= mGr.dims=%d", mGr.dims);
  16. LOGE("=2= mGr.channels=%d", mGr.channels());
  17. //    cv:cvtColor(mGr, mRgb, CV_RGB2GRAY);
  18.     //mRgb = mRgb /255.0;
  19.     CPlateLocate *pr = (CPlateLocate *)recognizerPtr;
  20. #if 1
  21. <b>    pr->sobelOper(mGr, imgData_out, m_GaussianBlurSize, m_MorphSizeWidth,m_MorphSizeHeight);//注意此时会有type==CV_8UC1的错误,尚未解决。</b>
  22. #else
  23.     #if 1
  24.         pr->cvtgray(mGr, mRgb, CV_RGB2GRAY);
  25.     #else
  26.         cv:cvtColor(mGr, mRgb, CV_RGB2GRAY);//运行ok
  27.     #endif
  28. #endif
  29. LOGE("=2= imgData_out.cols=%d", imgData_out.cols);
  30. LOGE("=2= imgData_out.rows=%d", imgData_out.rows);
  31. imgData_out.dims = 0;
  32. LOGE("=2= imgData_out.dims=%d", imgData_out.dims);
  33. LOGE("=2= imgData_out.channels=%d", imgData_out.channels());
  34. // imgData_out = imgData_out / 255.0;
  35. //   imgData_out.copyTo(*hist);

  36.     LOGE("=3= imgData_outJava_com_example_gzh_myplatelocate_PlateRecognizer_mySobelOper");
  37. }

复制代码

6)mySobelOper函数C++代码代码

  1. int CPlateLocate::sobelOper(const Mat &in, Mat &out, int blurSize, int morphW,int morphH)
  2. {
  3.   Mat mat_blur;
  4.     LOGE("=1= sobelOper");
  5.   mat_blur = in.clone();
  6.   GaussianBlur(in, mat_blur, Size(blurSize, blurSize), 0, 0, BORDER_DEFAULT);
  7.     LOGE("=2= sobelOper");

  8.     Mat mat_gray;
  9.   if (mat_blur.channels() == 3)
  10.     cvtColor(mat_blur, mat_gray, CV_RGB2GRAY);
  11.   else
  12.     mat_gray = mat_blur;
  13.     LOGE("=3= sobelOper");

  14.     int scale = SOBEL_SCALE;
  15.   int delta = SOBEL_DELTA;
  16.   int ddepth = SOBEL_DDEPTH;

  17.   Mat grad_x, grad_y;
  18.   Mat abs_grad_x, abs_grad_y;
  19.     LOGE("=4= sobelOper");


  20.     Sobel(mat_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
  21.   convertScaleAbs(grad_x, abs_grad_x);
  22.     LOGE("=5= sobelOper");

  23.     Mat grad;
  24.   addWeighted(abs_grad_x, SOBEL_X_WEIGHT, 0, 0, 0, grad);

  25.   Mat mat_threshold;
  26.   double otsu_thresh_val =
  27.       threshold(grad, mat_threshold, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);

  28.     LOGE("=6= sobelOper");
  29. #if 0
  30.     out = mat_threshold;
  31. #else
  32.     Mat element = getStructuringElement(MORPH_RECT, Size(morphW, morphH));
  33.   morphologyEx(mat_threshold, mat_threshold, MORPH_CLOSE, element);

  34.   out = mat_threshold;
  35. #endif
  36.     LOGE("=71= sobelOper");

  37.     return 0;
  38. }

复制代码


四)Opencv310帮助文件使用方法http://docs.opencv.org/3.1.0/index.html是opencv310帮助的主页,可以在搜索框中搜索所需关键字,会详细的说明,甚至示例代码。
五)总结
1.上面的实例中为了学习Opencv特意将图片数据通过Mat这样的数据结构传递,其实最好是将文件句柄传递给NDK处理,只返回车牌识别后的信息,这样我们就可以把注意力专注到车牌识别的算法和代码实现上。
2.PlateRecognizer.java文件与MainActivity.java文件放置到一起,可以将PlateRecognizer.java单独编译成一个Java库,而在其他Java文件中调用。
3.下面可以考虑把USB Camera预览的数据传递给NDK部分,将处理过的图像传递回来并显示。

大神,很完整的分享啊

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top