当前位置:网站首页>Android NDK development and actual combat WeChat official account 2-D code detection
Android NDK development and actual combat WeChat official account 2-D code detection
2020-11-09 12:12:00 【open_tei3s15d】
On two dimensional code recognition , We usually use them Zxing perhaps Zbar , But their recognition rate is not very high , In some cases, it fails , Take the following two pictures for example :
Using open source libraries Zxing Scan the above two QR codes , There's a dead or alive one . Wechat is OK , You can try Alipay. ( no way ), What should we do in this situation ? ha-ha , This time, it has a place , We're trying to optimize it .
We used this function in WeChat official account. , Press a picture , If the picture contains a QR code , The QR code in the identification map will pop up , If the picture does not contain a QR code , The option to identify the QR code will not pop up . At this point, we should know , There are two steps to recognize QR code , The first step is to find the intercepted QR code area , The second step is to identify the intercepted QR code area . that zxing What is the problem with Alipay? ? First of all, let's take a look at the first step to find the intercepted QR code region .
QR code example
The above figure is a common example of two-dimensional code , There are three important areas , It's the top left , Top right and bottom left , We just need to find these three areas , It can be determined that there is a QR code in the picture . Next, let's analyze the ideas :
1. Find the contour of it
2. The initial filtering is carried out for the found contour
3. Judge whether it conforms to the feature rules of QR code
4. Intercept QR code area
5. Identify QR code
// Judge X Is the direction in line with the rules
bool isXVerify(const Mat& qrROI){
... Code ellipsis
// Judge x Direction left to right pixel scale
// black : white : black : white : black = 1:1:3:1:1
}
// Judge Y Is the direction in line with the rules
bool isYVerify(const Mat& qrROI){
... Code ellipsis
// y You can also follow the isXVerify Methods to judge
// But we can also write it simply
// White pixels * 2 < Black pixels && Black image < 4 * White pixels
}
int main(){
Mat src = imread("C:/Users/hcDarren/Desktop/android/code1.png");
if (!src.data){
printf("imread error!");
return -1;
}
imshow("src", src);
// Gray scale conversion of image
Mat gary;
cvtColor(src, gary, COLOR_BGR2GRAY);
// Two valued
threshold(gary, gary, 0, 255, THRESH_BINARY | THRESH_OTSU);
imshow("threshold", gary);
// 1. Find the contour of it
vector<vector<Point> > contours;
findContours(gary, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); i++)
{
// 2. The initial filtering is carried out for the found contour
double area = contourArea(contours[i]);
// 2.1 Preliminary filtration area 7*7 = 49
if (area < 49){
continue;
}
RotatedRect rRect = minAreaRect(contours[i]);
float w = rRect.size.width;
float h = rRect.size.height;
float ratio = min(w, h) / max(w, h);
// 2.2 Preliminary filter aspect ratio
if (ratio > 0.9 && w< gary.cols/2 && h< gary.rows/2){
Mat qrROI = warpTransfrom(gary, rRect);
// 3. Judge whether it conforms to the feature rules of QR code
if (isYVerify(qrROI) && isXVerify(qrROI)) {
drawContours(src, contours, i, Scalar(0, 0, 255), 4);
}
}
}
imshow("src", src);
imwrite("C:/Users/hcDarren/Desktop/android/code_result.jpg", src);
waitKey(0);
return 0;
}
Processing results
The code is very simple , The key is that we should be good at learning to analyze , Develop problem solving skills , As long as you know how to realize it , Nothing else is a problem . So here comes the interesting one , When scanning the second image , We found that we couldn't recognize life or death . So careful students may understand , The code above is identified according to the characteristics of the square , And the second picture is the feature of a circle , therefore Zxing It's normal to be unrecognized , Because we didn't think about it when we wrote the code . So how can we recognize the features of a circle ? It's time to test us , We can think of three solutions :
1. Write another set of code to recognize circular features
2. Draw lessons from the scheme of face recognition , Training samples are used to identify
3. Change the inspection plan , Write only one set of code
Face recognition will be written in the next article , The way of training samples is more troublesome , If you haven't touched it before , So it takes a certain time cost , But it should be the best . Write another set of Circle Recognition code , Feel difficult to maintain , As an engineer with a soul, I always feel uncomfortable . So here we'll take the third option , In fact, there are so many knowledge points , Or that sentence Cultivate our ability to analyze and solve problems .
Let's watch carefully , They still have a lot in common , When we filter the contour, we will find that , It's a big outline with two small outlines inside . The specific process is as follows :
1. Find the contour of it
2. The initial filtering is carried out for the found contour
3. Judge whether it is a large profile with two small profiles and conform to the feature rules ( Area proportion judgment )
4. Intercept QR code area
5. Identify QR code
extern "C"
JNIEXPORT jobject JNICALL
Java_com_darren_ndk_day76_MainActivity_clipQrBitmap(JNIEnv *env, jobject instance, jobject bitmap) {
Mat src;
cv_helper::bitmap2mat(env, bitmap, src);
// Gray scale conversion of image
Mat gary;
cvtColor(src, gary, COLOR_BGR2GRAY);
// Two valued
threshold(gary, gary, 0, 255, THRESH_BINARY | THRESH_OTSU);
// 1. Find the contour of it
vector<Vec4i> hierarchy;
vector<vector<Point> > contours;
vector<vector<Point> > contoursRes;
/*
Parameter description :https://blog.csdn.net/guduruyu/article/details/69220296
The input image image Must be a 2 Value single channel image
contours The parameter is the detected Contour array , Each profile uses one point Type of vector Express
hiararchy The number of parameters and contours is the same , Every contour contours[ i ] Corresponding 4 individual hierarchy Elements hierarchy[ i ][ 0 ] ~hierarchy[ i ][ 3 ],
Each represents the next contour 、 The previous profile 、 The outline of the father 、 Index number of the embedded contour , If there is no counterpart , The value is set to a negative number .
mode Represents the retrieval mode of the contour
CV_RETR_EXTERNAL Indicates that only the outer contour is detected
CV_RETR_LIST The detected contour does not establish a hierarchical relationship
CV_RETR_CCOMP Build two levels of outline , The upper layer is the outer boundary , The inner layer is the boundary information of the inner hole . If there is a connected object in the inner hole , The boundary of this object is also at the top .
CV_RETR_TREE Create a hierarchical tree structure outline . Specific reference contours.c This demo
method An approximation of the outline
CV_CHAIN_APPROX_NONE Store all contour points , The pixel position difference between two adjacent points shall not exceed 1, namely max(abs(x1-x2),abs(y2-y1))==1
CV_CHAIN_APPROX_SIMPLE Compress the horizontal direction , vertical direction , Diagonal elements , Only the coordinates of the end point in this direction are reserved , For example, a rectangular outline only needs 4 Points to save profile information
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS Use teh-Chinl chain The approximate algorithm
offset Represents the offset representing the contour point , Can be set to any value . Yes ROI Outline found in image , And to be analyzed in the whole image , This parameter is still useful .
*/
findContours(gary, contours, hierarchy, CV_RETR_TREE, CHAIN_APPROX_NONE, Point(0, 0));
int tCC = 0; // Sub contour counter for temporary accumulation
int pId = -1;// Parent profile index
for (int i = 0; i < contours.size(); i++) {
if (hierarchy[i][2] != -1 && tCC == 0) {
pId = i;
tCC++;
} else if (hierarchy[i][2] != -1) {// Parent profile
tCC++;
} else if (hierarchy[i][2] == -1) {// There is no parent profile
tCC = 0;
pId = -1;
}
// Two sub contours were found
if (tCC >= 2) {
contoursRes.push_back(contours[pId]);
tCC = 0;
pId = -1;
}
}
// Too many matching feature contours were found , Filter them
if (contoursRes.size() > FEATURE_NUMBER) {
contoursRes = filterContours(gary, contoursRes);
}
// No matching conditions were found
if (contoursRes.size() < FEATURE_NUMBER) {
return NULL;
}
for (int i = 0; i < contoursRes.size(); ++i) {
drawContours(src, contoursRes, i, Scalar(255, 0, 0), 2);
}
// Cut QR code , hand zxing perhaps zbar Processing can be
cv_helper::mat2bitmap(env, src, bitmap);
return bitmap;
}
Processing results
What we like most in development is to take it and use it directly , But it's better to understand the principle , Because we can't tell what's going to happen in development . Big companies like wechat naturally have their own way , In fact, a good framework can be taken to optimize , I think it's almost the same . Of course, the above method is used in some specific situations , There may still be some loopholes , This depends on our constant thinking and optimization .
PS: About me
I am a Have 6 Years of experience in development Android Siege lions , Remember to read a little like it , Develop habits , Search on wechat 「 Program ape Development Center 」 Focus on this programmer who likes to write dry goods .
in addition It took two years Sorting and collecting Android Interview for large factories PDF Baked , Information 【 Full version 】 Updated on my 【Github】, Yes Friends for interview We can refer to it , If it helps you , You can order Star Oh !
Address :【https://github.com/733gh/xiongfan】
版权声明
本文为[open_tei3s15d]所创,转载请带上原文链接,感谢
边栏推荐
- 20201107第16课,使用Apache服务部署静态网站;使用Vsftpd服务传输文件
- Aren't you curious about how the CPU performs tasks?
- 在嵌入式设备中实现webrtc的第三种方式③
- 阿里、腾讯、百度、网易、美团Android面试经验分享,拿到了百度、腾讯offer
- SQL statement to achieve the number of daffodils
- iPhone“连到系统上的设备没有发挥作用”原因分析及解决方法 20200105
- Biden wins the US election! Python developers in Silicon Valley make fun of Ku Wang in this way
- Analysis of the source code of ThinkPHP facade
- 实现商品CRUD操作
- Fedora 33 Workstation 的新功能
猜你喜欢
Tidb x micro banking reduces time consumption by 58%, and distributed architecture helps to realize inclusive finance
技美那么贵,不如找顾问 | AALab企业顾问业务
Three practical skills of Medical Project Management
20201107第16课,使用Apache服务部署静态网站;使用Vsftpd服务传输文件
理解 OC 中 RunLoop
开源ERP招聘了
EFF 认为 RIAA 正在“滥用 DMCA”来关闭 YouTube-DL
Impact of libssl on CentOS login
【golang】GC详解
Pay attention to the request forwarding problem of. Net core
随机推荐
20201107第16课,使用Apache服务部署静态网站;使用Vsftpd服务传输文件
Fedora 33 Workstation 的新功能
如何用函数框架快速开发大型 Web 应用 | 实战
大型项目Objective-C - NSURLSession接入短信验证码应用实例分享
inet_ Pton () and INET_ Detailed explanation of ntop() function
为wget命令设置代理
AI应届生年薪涨到40万了,你现在转行还来得及!
Large scale project Objective-C - nsurlsession access SMS verification code application example sharing
An attempt to read or write to protected memory occurred using the CopyMemory API. This usually indicates that other memory is corrupted.
Android 复选框 以及回显
Reading design patterns adapter patterns
注意.NET Core进行请求转发问题
Using stream to read and write files to process large files
In the future, China Telecom will make cloud computing service the main business of China Telecom
接口测试如何在post请求中传递文件
android studio创建平板模拟器方法
Oh, my God! Printing log only knows log4j?
配置交换机Trunk接口流量本地优先转发(集群/堆叠)
阿里、腾讯、百度、网易、美团Android面试经验分享,拿到了百度、腾讯offer
嗯,查询滑动窗口最大值的这4种方法不错....