Android开发之OpenCV实战:开发环境的搭建(⾝份证号码识别为例)Android开发之OpenCV实战:开发环境的搭建(⾝份证号码识别为例)
声明
开发环境
1. Android Studio Arctic Fox | 2020.3.1(官⽹下载安装)
2. OpenCV-android-sdk 版本4.5.5(下载后解压到⼀个⽂件夹⾥,不⽤进⾏配置)
3. NDK(Android Studio⾃⼰安装)
环境配置步骤
1. 新建项⽬IDReg
2. 新建IDRecon模块,我们将在这个模块中进⾏OpenCV相关的开发。
3. 在IDRecon模块的src/main⽬录下新建⽂件夹cpp,⽤于存放NDK开发相关的代码。在cpp⽂件夹下新建⽂件夹libs,⽤于存
放OpenCV的动态链接库。将 解压路径/OpenCV-android-sdk/sdk/native/libs ⽂件夹下的四个⽂件夹拷贝到libs中。因为打包成时需要把OpenCV中的.so库⼀起打包。在CPP⽂件夹下新建⽂件,⽤来编写编译的配置信息;新
建OpenCVHelper.cpp⽂件,⽤来编写C++的代码。
4. 最重要的第⼀步: 在IDRecon模块的adle⽂件中添加NDK相关的配置。
⾸先在defaultConfig闭包中添加externalNativeBuild闭包,增加编译d的参数配置。
然后在android闭包中添加externalNativeBuild 闭包,指出⽂件的路径和CMake的版本
最后在android闭包中添加sourceSets 闭包,指明OpenCV的动态链接库的存放位置。
//****//
android{
//****//
defaultConfig{
//****//
externalNativeBuild {
cmake {
cppFlags ''
arguments "-DANDROID_STL=c++_shared"
}
}
}
//****//
externalNativeBuild {
cmake {
path file('src/main/')
version '3.10.2'
}
}
sourceSets{
main{
jniLibs.srcDirs =["src/main/cpp/opencv/libs"]
}
}
}
//****//
5. 最重要的⼆步: 编写 src/main/,代码如下(说明见注释):
# cmake版本
# cmake版本
cmake_minimum_required(VERSION 3.10.2)
#替换,相当于宏定义
set(PROJECT_NAME opencv)
#项⽬名称,⾮必选
project(${PROJECT_NAME})
# 很重要,设置OpenCV_DIR,让项⽬能到OpenCV的库
set(OpenCV_DIR opencv的解压地址\\OpenCV-android-sdk\\sdk\\native\\jni)
find_package(OpenCV REQUIRED)
if(OpenCV_FOUND)
# 把OpenCV的库引⼊项⽬
include_directories(${OpenCV_INCLUDE_DIRS})
message(STATUS "OpenCV library status:")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
else(OpenCV_FOUND)
message(FATAL_ERROR "OpenCV library not found")
endif(OpenCV_FOUND)
add_library(
#库的名称
${PROJECT_NAME}
# 将库设置为.so动态连接库
SHARED
# 添加动态库⾥包含的所有cpp⽂件,包括引⽤的lib⾥的cpp
OpenCVHelper.cpp
)
find_library(
#库位置对应的名称,给其他地⽅使⽤
log-lib
#库⽣成的中间⽂件的位置
log)
#链接对应的⽂件,很重要,要连接jni图像库,OpenCV的库和⾃⼰编写的⽂件(${log-lib})
target_link_libraries(
${PROJECT_NAME}
jnigraphics
${OpenCV_LIBRARIES}
${log-lib})
6. 令app模块依赖IDRecon模块,在app模块的adle⽂件中的dependencies闭包下添加依赖
//****//
dependencies{
implementation project(":IDRecong")
}
7. 环境配置完毕,剩下的按NDK开发的流程编写代码即可
代码编写
1. 在IDRecon模块下的/src/main⽂件夹下新建asserts⽂件夹,⽂件夹下存放⾝份证数字匹配的模板(0-9⼗个数字的图⽚,资源见源
码)
2. 在IDRecon模块下的/src/main/java/包名⽂件夹下新建IDRecong.kt⽂件,代码如下:
package com.cam.idrecong
t.Context
aphics.Bitmap
aphics.BitmapFactory
aphics.BitmapFactory
class OpenCVUtils {
companion object{
init{
System.loadLibrary("opencv")
}
private external fun idRecognise(bitmap: Bitmap, list:List<Bitmap>): String
fun idRecognise(bitmap: Bitmap,context: Context): String{
val list = ArrayList<Bitmap>()
for(i in0..9){
list.add(BitmapFactory.decodeStream(context.assets.open("$i.jpg")))
}
return idRecognise(bitmap,list);
}
}
}
3. 编写OpenCVHelper.cpp代码,代码如下:
#include<jni.h>
#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/imgcodecs/imgcodecs.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/core.hpp>
#include<opencv2/imgproc.hpp>
#include<string>
#include<opencv2/opencv.hpp>
#include<android/bitmap.h>
using namespace std;
using namespace cv;
Size numSize =Size(16,24);
void BitmapToMat2(JNIEnv *env, jobject &bitmap, Mat &mat, jboolean needUnPremultiplyAlpha){ AndroidBitmapInfo info;
void*pixels =0;
Mat &dst = mat;
try{
CV_Assert(AndroidBitmap_getInfo(env, bitmap,&info)>=0);
CV_Assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 || info.format == ANDROID_BITMAP_FORMAT_RGB_565);
CV_Assert(AndroidBitmap_lockPixels(env, bitmap,&pixels)>=0);
CV_Assert(pixels);
if(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888){
Mat tmp(info.height, info.width, CV_8UC4, pixels);
if(needUnPremultiplyAlpha)cvtColor(tmp, dst, COLOR_mRGBA2RGBA);
pyTo(dst);
}else{
// info.format == ANDROID_BITMAP_FORMAT_RGB_565
Mat tmp(info.height, info.width, CV_8UC2, pixels);
cvtColor(tmp, dst, COLOR_BGR5652RGBA);
}
AndroidBitmap_unlockPixels(env, bitmap);
return;
}catch(const cv::Exception &e){
AndroidBitmap_unlockPixels(env, bitmap);
jclass je = env->FindClass("java/lang/Exception");
env->ThrowNew(je, e.what());
return;
}catch(...){
AndroidBitmap_unlockPixels(env, bitmap);
jclass je = env->FindClass("java/lang/Exception");
env->ThrowNew(je,"Unknown exception in JNI code {nBitmapToMat}");
return;
return;
}
}
bool compareFacesByHist(const Mat &srcImage,const Mat &tempalteImage){
int sums =0;
for(int i =0; i < ws; i++){
for(int j =0; j < ls; j++){
sums +=abs(srcImage.at<uchar>(i, j)- tempalteImage.at<uchar>(i, j));
}
}
float s = sums /(ws * ls +0.0);
return s <20;
}
string getNums(Mat src, vector<Mat> oriMats){
pty()){
return"";
}
androidsdk安装步骤resize(src, src,Size(640,400));
// 灰度图
cvtColor(src, src, COLOR_BGR2GRAY);
Mat dst;
// ⼆值化
threshold(src, dst,150,255, THRESH_BINARY);
Mat erodeElement =getStructuringElement(MORPH_RECT,Size(20,10));
erode(dst, dst, erodeElement);
vector<vector<Point>> contours;
findContours(dst, contours, RETR_TREE, CHAIN_APPROX_SIMPLE,Point(0,0));
for(auto&contour: contours){
Rect rect =boundingRect(contour);
if(rect.width > rect.height *9){
dst =src(rect);
}
}
threshold(dst, dst,150,255, THRESH_BINARY);
Mat erods;
erodeElement =getStructuringElement(MORPH_RECT,Size(2,2));
dilate(dst, erods, erodeElement);
erode(erods, erods, erodeElement);
erode(erods, erods, erodeElement);
erode(erods, erods, erodeElement);
erode(erods, erods, erodeElement);
contours.clear();
findContours(erods, contours, RETR_TREE, CHAIN_APPROX_SIMPLE,Point(0,0)); vector<Mat> mats;
for(auto&contour: contours){
Rect rect =boundingRect(contour);
if(rect.width >5&& rect.height >5&& rect.height >= rect.width &&
rect.width * rect.height >=200){
mats.push_back(dst(rect));
}
}
vector<int> result;
for(int i =0; i < mats.size(); i++){
Mat m = mats.at(i);
resize(m, m, numSize);
for(int j =0; j < oriMats.size(); j++){
if(compareFacesByHist(m, oriMats.at(j))){
result.push_back(j);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论