Image extraction of ID card number--connected domain detection algorithm based on canny edge detection

Source: Internet
Author: User

after scanning the QR Code extraction task, it is necessary to extract the ID number from the ID image and then call the colleague to identify it. the previous connected-domain detection algorithm compares "brute force" because once it detects a large area, all the inner areas of the area will no longer exist. Therefore, in the connected domain detection, the first step is to remove the possible white edges around, otherwise it will fail. Later, the author changed a train of thought, if the detection of an area to save the corresponding generation of the point of the region, the region does not meet the requirements of the point to erase these points, so that the internal area will not be affected. So there is the birth of the algorithm:

(1) from the upper left corner, starting from the first white point encountered to detect the largest connected domain, get away from the point less than Max_dis all points, put into a list .

(2) then traverse the list and place the points that are less than max_dis from each point in the listing.

(3) At the end of the traversal, calculate the smallest rect area that contains a bit of the list.

(4) According to the set target area characteristics, such as length and width, aspect ratio, to determine whether the area meets the requirements, if satisfied, then put into the rectlist. Then all the dots in the list are black. Go to (1) execute.

(5) If the rectlist is empty, the target rect is not obtained. If >=1 sorts it according to a rule (which should be the most important feature), then output the most likely rect.

The algorithm process is demonstrated as follows:

Original:

Color filtering (to get a better effect on the canny chart):

Canny chart:

Detect picture frames and erase:

First time frame:

First erase:

Second time frame:

Second erase

Nth times Picture frame:

nth Erase:

There is nothing left in the end:

Results:

The detailed algorithm code is as follows:

FindIdCode.h


#include "opencv2/core/core.hpp" #include "opencv2/imgproc/imgproc_c.h" #include "opencv2/imgproc/imgproc.hpp" # Include "opencv2/highgui/highgui.hpp" #include <iostream> #include < io.h> #include <algorithm># Include <stdio.h> #include "opencv/cv.h" #include "opencv/cxcore.h" #include "opencv2/highgui/highgui_c.h" # Include "Direct.h" using namespace cv;using namespace Std;class cgetidcode{public:cgetidcode ();//delete file and return string value string GetFilePath (const char * szbuf);//Get File length long getfilelength (const char * filepath);//Filter color void Filtercolor (String STRIMGF Ilename);//Locate the target connected domain rect findtargetconnecteddomain ();//Set the points in the list to a certain color void Setpointlistcolor (Mat & srcimg, std: : VECTOR&LT;CV::P oint> pointlist, int ncolor);//Gets the minimum inclusive area void Getrectfrompointlist (STD::VECTOR&LT;CV::P oint based on the point list) >& pointlist, RECT & Rtrect);//Gets the point near the point void Getnearpoint (Mat & SRCIMG,CV::P oint currentpoint, std:: VECTOR&LT;CV::P oint> & Pointlist);//Draw a box frame into a color void Drowboxcolor (Mat &srCIMG, std::vector<rect> &boxlist, int ncolor);//Get a unicom area bool Getoneconnecteddomain (Mat & srcimg, std:: VECTOR&LT;CV::P oint>& pointlist, RECT &rect);//save one area of an image as an image void Savepicwithdestrect (String strsource, String strdest, rect destrect);//Get the ID number image area RECT getidcode (const char * szsourcefile);//edge detection int outLinePic2 (); Char Szcurrentpath[max_path]; String strorigin;string strsave1;string strsave1_1;string strsave2;string strsave3;string strSave4;string strSave5; String strsave3_0;string strsave3_1;string strsave3_2;string strsave3_3;string strsave6;string strSave7;string StrSave8;};

FindIdCode.cpp

#include "FindIdCode.h" int mmax_dis = 0; Double fscale = 0.0; #define Box_width 50#define BLACK 0#define mid_black_white 128#define white 255#define rate 0. 2//sorted By Box width BOOL SortByM5 (rect &v1, rect &v2) {int nWidth1 = V1.right-v1.left;int nHeight1 = v1.bottom-v1.top;i NT NWidth2 = v2.right-v2.left;int nHeight2 = v2.bottom-v2.top;float fRate1 = 1.0 * Nwidth1/nheight1;float FRate2 = 1 .0 * NWIDTH2/NHEIGHT2;IF (fRate1 > FRate2) {return TRUE;} Else{return FALSE;}} String Cgetidcode::getfilepath (const char * szbuf) {string str;str = szcurrentpath;str + = "\"; str + = szbuf;//Delete the existing file Del Etefile (Str.c_str ()); return str;}  Long cgetidcode::getfilelength (const char * filepath) {file* FILE = fopen (filepath, "RB");  if (file) {Long size = Filelength (Fileno (file)); return size;} Else{return 0;}} Color filter void Cgetidcode::filtercolor (String strimgfilename) {Uchar Udiffermax = 80;uchar RMax = 100;uchar Bmax = 150;uchar GM Ax = 150;uchar Uwhite = 255;uchar r,b,g;iplimage *workimg = Cvloadimage (Strimgfilename.c_str (), cv_load_image_unchanged);//pixels too high for scaling if (Workimg->width >) {int Ntargetwidth = 600;fscale = 1.0 * workimg->width/ntargetwidth; Cvsize czsize;//Compute the target image size Czsize.width = Ntargetwidth;czsize.height = workimg->height/fscale; Iplimage *psrcimage = Cvloadimage (Strsave2.c_str (), cv_load_image_unchanged); Iplimage *pdstimage = Cvcreateimage (Czsize, workimg->depth, workimg->nchannels); Cvresize (workimg, Pdstimage, Cv_inter_area); Cvreleaseimage (&AMP;WORKIMG); Cvsaveimage (Strsave1_1.c_str (), pdstimage); workimg = Pdstimage;} for (int x=0;x<workimg->height;x++) {for (int y=0;y<workimg->width;y++) {b= (uchar*) (workimg->  Imagedata+x*workimg->widthstep)) [y*3+0];  G= ((uchar*) (Workimg->imagedata+x*workimg->widthstep)) [y*3+1]; R= ((uchar*) (Workimg->imagedata+x*workimg->widthstep)) [y*3+2];//bias more severe//uchar UMax = max (b,g), r);// Uchar umin = min (min (b,g), R);//if (Umax-umin > Udiffermax) int nabove = 0;if (b >= Udiffermax) {nabove + +;} if (g >= Udiffermax) {nabove + +;} if (r >= Udiffermax) {nabove + +;} There are two greater than if (Nabove >= 2 | | b > Bmax | | g > GMax | | r > RMax) {((uchar*) (Workimg->imagedata+x*workimg->wi Dthstep)) [y*3+0] = Uwhite; ((uchar*) (Workimg->imagedata+x*workimg->widthstep)) [y*3+1] = Uwhite; ((uchar*) (  Workimg->imagedata+x*workimg->widthstep)) [y*3+2] = Uwhite;}} } cvsaveimage (Strsave1.c_str (), workimg);} int Cgetidcode::outlinepic2 () {Mat src = imread (strsave1.c_str ()); Mat dst;if (!src.empty ()) {///input image//output image//input Image Color channel number//x Direction order//y Direction Order Sobel (Src,dst,src.depth (),);//imwrite (" Sobel.jpg ", DST);//input image//output image//input Image Color channel number Laplacian (Src,dst,src.depth ()); Imwrite (" Laplacian.jpg ", DST);//input image//  Output image//color turn grayscale cvtcolor (Src,src,cv_bgr2gray); Canny processing only grayscale map//input image//output image//low threshold//High threshold value, OPENCV recommended is low threshold value of 3 times times//internal Sobel filter size//threshold1 and threshold2 small threshold value to control the edge connection, A large threshold is used to control the initial segmentation of strong edges. 150Canny (src,dst,220,240,3); Imwrite (Strsave2.c_str (), DST); return 0;} else{cout<< "IMG is not exist!"; Return-1;}}  void Cgetidcode::setpointlistcolor (Mat & Srcimg, STD::VECTOR&LT;CV::P oint> pointlist, int ncolor) {for (int i = 0; i < Pointlist.size (); i + +) {int x = Pointlist[i].x;int y = pointlist[i].y;* (srcimg.data + srcimg.step[0] * y + srcimg.step[1] * x) = Ncolor;}} RECT Cgetidcode::findtargetconnecteddomain () {Mat srcimg = Imread (Strsave2.c_str (), cv_load_image_grayscale);// Set maximum Distance Mmax_dis = Srcimg.cols * (1.0 * 9/400) + 1;int nmaxwidth = 0.6 * Srcimg.cols;int nmaxheight = 1.0 * 5 * srcimg.ro WS/36; STD::VECTOR&LT;CV::P oint> pointlist;//detects a rectangular connected field, determines whether the target characteristics are met, and does not conform to the deletion to find the next. Find one to put in the vector. Std::vector<rect> Targetrectlist;while (TRUE) {rect rect; Getoneconnecteddomain (srcimg, pointlist,rect);//Determine if the RECT meets the requirements.  int nwidth = Rect.right-rect.left;int nheight = rect.bottom-rect.top;//Float Frate = 1.0 * nwidth/nheight;if (Nheight > 5 && nheight < nmaxheight && nwidth > && nwidth < nmaxwidth &&am  P Frate > 8 && FRAte <) {//savepicwithdestrect (Strorigin, StrSave8, rect); Targetrectlist.push_back (rect);//break;} Else{if (Pointlist.empty ()) {break;}} Black and then find the next Setpointlistcolor (Srcimg, Pointlist, Black), Imwrite (Strsave3_3.c_str (), srcimg);p ointlist.clear ();} There are multiple sort if (targetrectlist.size () > 0) {sort (Targetrectlist.begin (), Targetrectlist.end (), SortByM5);//Find extract image to save. Rect rect = targetrectlist[0];rect.left-= mmax_dis;if (Rect.left < 0) {rect.left = 0;} Rect.top-= mmax_dis;if (Rect.top < 0) {rect.top = 0;} Rect.right + = mmax_dis;if (Rect.right > Srcimg.cols) {rect.right = Srcimg.cols;} Rect.bottom + = mmax_dis;if (Rect.bottom > Srcimg.rows) {rect.bottom = srcimg.rows;} if (Fscale > 0.0) {rect.left *= fscale;rect.right*= fscale;rect.bottom *= fscale;rect.top *= Fscale;} Return Rect;//savepicwithdestrect (Strorigin, StrSave8, rect);} else{//cout<< "Find no numbers!"; /getchar (); Rect rect;rect.bottom = Rect.top = Rect.left = Rect.right = 0;return rect;}} Save image void Cgetidcode::savepicwithdEstrect (String strsource, String strdest, RECT destrect) {iplimage* src;  iplimage* dst;src = Cvloadimage (Strsource.c_str (), 1); if (!SRC) {return;} Cvsetimageroi (Src,cvrect (Destrect.left,destrect.top, Destrect.right-destrect.left, Destrect.bottom-destrect.top)  ); DST = Cvcreateimage (Cvsize (Destrect.right-destrect.left, Destrect.bottom-destrect.top), IPL_DEPTH_8U, Src->nChan  Nels);  Cvcopy (src,dst,0);   Cvresetimageroi (SRC); Cvsaveimage (Strdest.c_str (), DST); Cvreleaseimage (&AMP;DST); Cvreleaseimage (&AMP;SRC);} BOOL Cgetidcode::getoneconnecteddomain (Mat & Srcimg, STD::VECTOR&LT;CV::P oint>& pointlist, RECT &rect) {int nwidth = Srcimg.cols;int nheight = srcimg.rows;int Nxstart = 0;int Nystart = 0; BOOL bblack = TRUE; BOOL Bbreak = False;int Nwhite = 0;//Find the first top corner of the white point for (int y = 0; y < nheight; y + +) {for (int x = 0; x < nwidth; + +) { int npixel = (int) (* (Srcimg.data + srcimg.step[0] * y + srcimg.step[1] * x)); if (Npixel > Mid_black_white) {nxstart = x; Nystart =Y;CV::P oint temppint (nxstart,nystart);p ointlist.push_back (temppint); bbreak = True;break;}} if (Bbreak) {break;}} int nSize = Pointlist.size ();//Probe next point. for (int i = 0; i < nSize; i + +) {CV::P oint currentpoint = pointlist[i]; Getnearpoint (srcimg, Currentpoint, pointlist); nSize = Pointlist.size ();//If more than 4,000 points are deleted then re-come to if (NSize > +) {break ;}} The minimum containing rectangle for the pointlist is obtained. Getrectfrompointlist (pointlist, rect);std::vector<rect> temptect;temptect.push_back (rect);D Rowboxcolor ( Srcimg,temptect, white); Imwrite (Strsave3_2.c_str (), srcimg);D Rowboxcolor (Srcimg,temptect, BLACK); return TRUE;} void Cgetidcode::getrectfrompointlist (STD::VECTOR&LT;CV::P oint>& pointlist, RECT & rtrect) {int nLeft = 0; int NTop = 0;int Nright = 0;int Nbottom = 0;for (int i = 0; i < pointlist.size (); i + +) {CV::P oint temppoint = pointlist[ I];if (i = = 0) {nleft = Nright = Temppoint.x;ntop = Nbottom = Temppoint.y;} Else{if (Temppoint.x < nleft) {nleft = Temppoint.x;} if (Temppoint.x > Nright) {nright = Temppoint.x;}if (Temppoint.y < NTop) {nTop = Temppoint.y;} if (Temppoint.y > Nbottom) {nbottom = Temppoint.y;}}} Rtrect.left = Nleft;rtrect.top = Ntop;rtrect.right = Nright;rtrect.bottom = Nbottom;} void Cgetidcode::getnearpoint (Mat & SRCIMG,CV::P oint currentpoint, STD::VECTOR&LT;CV::P oint> & pointlist) { Detects a point with a range of 20 * 20 centered on that point. for (int y = max (0, Currentpoint.y-mmax_dis), y < min (srcimg.rows, Currentpoint.y + Mmax_dis) and Y + +) {for (int x = max (Currentpoint.x-mmax_dis, 0); x < min (srcimg.cols, currentpoint.x + Mmax_dis); X + +) {int npixel = (int) (* (Srcimg.data + srcimg.step[0] * y + srcimg.step[1] * x)); if (Npixel > Mid_black_white) {cv::P o int Temppint (x, y);//See if the point has been put into LISTSTD::VECTOR&LT;CV::P oint>::iterator itfind = Find (Pointlist.begin (), Pointlist.end (), temppint); if (Itfind = = Pointlist.end ()) {pointlist.push_back (temppint);}}}} Frame line for a color void Cgetidcode::D rowboxcolor (Mat &srcimg, std::vector<rect> &boxlist, int ncolor) {int Nresultsize = Boxlist.size (); for(int i = 0; i < nresultsize; i + +)  {RECT Temprect = boxlist[i];//up/down edge int y1 = Temprect.top;int y2 = temprect.bottom;for (int x = Temprect.left; x <= temprect.right; X + +) {* (Srcimg.data + srcimg.step[1] * x + srcimg.step[0] * y1) = ncolor;* (Srcimg.data + srcimg.step[1] * x + srcimg.step[ 0] * y2) = Ncolor;} Left and right edge int x1 = Temprect.left;int x2 = temprect.right;for (int y = temprect.top; y <= temprect.bottom; y + +) {* (Srcimg.da TA + srcimg.step[1] * x1 + srcimg.step[0] * y) = ncolor;* (Srcimg.data + srcimg.step[1] * x2 + srcimg.step[0] * y) = Ncolor ;}}} RECT Cgetidcode::getidcode (const char * szsourcefile) {CopyFile (Szsourcefile, Strorigin.c_str (), FALSE);//File size Too small the image is not filtered rect rect;rect.bottom = Rect.top = Rect.left = Rect.right = 0;long Nfilelen = getfilelength (Strorigin.c_str ()); I F (Nfilelen = = 0) {return rect;} else if (Nfilelen > 7000) {filtercolor (strorigin);} Else{copyfile (Strorigin.c_str (), Strsave1.c_str (), FALSE);} if (outLinePic2 () = =-1) {return rect;} Return findtargetconnectedDomain ();} Cgetidcode::cgetidcode () {_getcwd (szcurrentpath,max_path); strorigin = GetFilePath ("imagetext.jpg"); strSave1 = GetFilePath ("imagetext_d.jpg"); strsave1_1 = GetFilePath ("imagetext_resize.jpg"); strSave2 = GetFilePath ("canny.jpg") ); strSave3 = GetFilePath ("imagetext_clear0.jpg"); strSave4 = GetFilePath ("imagetext_clear1.jpg"); strSave5 = GetFilePath ("imagetext_clear2.jpg"); strsave3_0 = GetFilePath ("imagetext_clear3_0.jpg"); strsave3_1 = GetFilePath (" Imagetext_clear3_1.jpg "); strsave3_2 = GetFilePath (" imagetext_clear3_2.jpg "); strsave3_3 = GetFilePath (" ImageText_ Clear3_3.jpg "); StrSave6 = GetFilePath (" imagetext_clear3.jpg "); StrSave7 = GetFilePath (" imagetext_d.jpg "); StrSave8 = GetFilePath ("Imagetext_clear4.jpg");}

Test code for the class:

#include ". /findidcode/findidcode.h "using namespace std; #ifdef _debug#pragma comment (lib," Debug/findidcode.lib ") #else #pragma Comment (lib, "Release/findidcode.lib") #endifint main (int argc, char **argv) {if (ARGC < 2) return (1); Cgetidcode getidcode;//char* szsourcefile = "d:\\scan\\00000000000000000\\3032_024.jpg";//dll test char* szSourceFile = ARGV[1]; Rect rect = Getidcode.getidcode (szsourcefile);//copyfile (Szsourcefile,strorigin.c_str (), FALSE); Getidcode.savepicwithdestrect (Szsourcefile, Getidcode.strsave8, rect);cout<< "The Rect is" <<rect.left << "" <<rect.top<< "<<rect.bottom<<" "<<rect.right<<" "; return 0;}


Description

Due to continuous cycle detection, if the pixel is too high picture is too large time consuming more, and edge detection effect is particularly bad, so the program for pixel width greater than 900 is scaled to 400.

The effect of program operation is directly influenced by the effect of canny picture. So for different characteristics of the picture, you can adjust the parameters of the Canny function, as in this example, the parameters are: Canny (src,dst,220,240,3).

Color filter: because the ID card has a lot of blue and red shading, the RGB too large color into white. Sometimes it does not necessarily have a good effect, but it will increase the edge, but affect the results. In addition, if the image is particularly blurred, it is best not to color filter.

Finally, we need to remind OpenCV of the environmental problems.

Image extraction of ID card number--connected domain detection algorithm based on canny edge detection

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.