android opencv 银行卡识别,【opencv小应用】银行卡号识别(一)

银行卡几何校正及卡号定位

一、首先看下效果:

0818b9ca8b590ca3270a3433284dd417.png                                                                                                                                    图1

0818b9ca8b590ca3270a3433284dd417.png

图2

二、几何校正:

步骤:

0.背景:纯色背景(如果卡面颜色与背景颜色相近,后续的边缘检测会有影响,这块后续可以通过更改边缘检测的阀值参数或其他方法提高)

1.边缘检测(预处理)

2.直线检测(设置检测直线的条件(最小直线长度和最大直接间隔),获取银行卡边,条件:直线数量大于等于3,小于10)

3.根据直线集获得点集(Vec4i转换成vector>)

4.根据点集获得最小外接可旋转矩形minAreaRect();

5.几何校正(getRotationMatrix2D(),warpAffine(),getRectSubPix();)

三、银行卡的上卡号定位:

方法1:

根据模板匹配,获取卡号的位置

已实现,识别率>70%;缺点,对无银联标志或其在右上角的卡,不适用

0818b9ca8b590ca3270a3433284dd417.png(此标志是在测试环境中获取的)

方法2:

构想 (未实现):

1.cropped.rows/5至cropped.rows*4/5之间,以间距cropped.rows/5扫描

2.检测直线,比较直线的长度和数量来确认;另一种方法,二值化图像,比较数字间的空白数。但因为背景复杂且有些卡相差很大,此种方法成功率较低。

ps:如果需要高效稳定的方法,这一块还需要继续找其他方法

四、卡号识别(下一步实现)

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png 

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png 

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

图3                     图4                 图5

难度:

1.同一张卡,背景复杂,如图3切割于图2的工商卡,有个白底e。固定化的阀值化操作已不适用于此类型卡。更离谱是有些凹凸卡号,不认真看,连人眼都分不清。

2.数字的字体多,不适用于模板匹配。可使用SVM、KNN等进行识别

3.数字的预测度设置,目前在微信上,我的两张卡都会识别错误(主要原因是背景过于复杂)

暂时先到这,后续需要找到新的方法,解决以上难点,还需要不断提高。

五、demo代码

#include "stdafx.h"

#include

#include

#include

using namespace cv;

using namespace std;

void drawDetectLines(Mat& image,const vector& lines,Scalar & color);

void on_canny( int, void* );

//void on_Threshold( int, void* );以备后面使用

void on_line( int, void* );

void vec4i2vecPoint();

bool findUPflag();

void cropBankNoByUPflag();

Mat frame;

Mat grayImg;

Mat contours;

Mat threImg;

int i_canThres=50;

int g_nThresholdValue=100;

int g_nThresholdType=1;

int minLineLength=170;

int maxLineGap=10;

vector lines;

vector co;

vector > conn;

Mat UPImg,cropped,noImg;

Point minLoc;

void main()

{

Mat imgROI;

bool stop = false;

char c;

//VideoCapture capture(0);

VideoCapture capture("D://img//bankcard//1.wmv");

namedWindow( "canny");

//namedWindow( "Threshold");

namedWindow( "Bob_BankCard_Num_Reader");

//cvtColor(frame,grayImg,CV_BGR2GRAY);

//createTrackbar( "模式","Threshold", &g_nThresholdType,4, on_Threshold );

//createTrackbar( "参数值","Threshold", &g_nThresholdValue,255, on_Threshold );

createTrackbar( "canThres","canny", &i_canThres,100, on_canny );

createTrackbar( "最小直线长度","Bob_BankCard_Num_Reader", &minLineLength,300, on_line);

createTrackbar( "最大直线间隔度","Bob_BankCard_Num_Reader", &maxLineGap,300, on_line);

Mat M, rotated;

float angle;

Size rect_size;

float ratio;

int lineSize=0;

UPImg=imread("D://img//bankcard//UPflag.jpg");

while(!stop)

{

capture>>frame;

cvtColor(frame,grayImg,CV_BGR2GRAY);

//on_Threshold(0,0);

//imshow("canny",contours);

on_canny(0,0);

imshow("canny",contours);

on_line(0,0);

lineSize=lines.size();

if(lineSize>=3&&lineSize<=10)//线条的数量,可根据亮度去调节canny的阀值

{

drawDetectLines(frame,lines,Scalar(0,255,0));

vec4i2vecPoint();

Rect rc=boundingRect(conn.at(0));

RotatedRect rect;

rect=minAreaRect(conn.at(0));

imgROI=frame(rc);

imshow("outRect",imgROI);

//后期如果需要提高卡的轮廓识别率,可以判断卡的height/width比,大约0.64(实际量过)

ratio=rect.size.height/rect.size.width;

cout<

if(ratio>0.6&&ratio<0.7)

{

angle = rect.angle;

rect_size = rect.size;

if (rect.angle < -45.)

{

angle += 90.0;

swap(rect_size.width, rect_size.height);

}

M = getRotationMatrix2D(rect.center, angle, 1.0);

warpAffine(frame, rotated, M, frame.size(), INTER_CUBIC);

getRectSubPix(rotated, rect_size, rect.center, cropped);

imshow("cropped",cropped);

if(findUPflag())

cropBankNoByUPflag();

//else

//执行第二种方法定位银行卡号的y值,方法构想

//1.cropped.rows/5至cropped.rows*4/5之间,以间距cropped.rows/5扫描

//2.检测直线,比较直线的长度和数量来确认;另一种方法,二值化图像,比较数字间的空白数。但因为背景复杂且有时相差很大,此种方法成功率较低。

//如果需要高效稳定的方法,这一块还需要继续找其他方法

}

}

co.clear();

conn.clear();

lines.clear();

imshow("Bob_BankCard_Num_Reader",frame);

c=waitKey(24);;

if(c==27)

stop=true;

}

}

void drawDetectLines(Mat& image,const vector& lines,Scalar & color)

{

vector::const_iterator it=lines.begin();

while(it!=lines.end()&&lines.size()>=3)

{

Point pt1((*it)[0],(*it)[1]);

Point pt2((*it)[2],(*it)[3]);

line(image,pt1,pt2,color,1); // 线条宽度设置为1

++it;

}

}

void vec4i2vecPoint()

{

vector::const_iterator it=lines.begin();

while(it!=lines.end())

{

Point pt1((*it)[0],(*it)[1]);

Point pt2((*it)[2],(*it)[3]);

co.push_back(pt1);

co.push_back(pt2);

++it;

}

conn.push_back(co);

}

void on_canny( int, void* )

{

Canny(grayImg,contours,i_canThres,i_canThres*3);

}

//void on_Threshold( int, void* )

//{

//threshold(contours ,contours ,g_nThresholdValue,255,g_nThresholdType);

//imshow( "Threshold", contours );

//}

void on_line( int, void* )

{

HoughLinesP(contours,lines,1,CV_PI/180,80,minLineLength,maxLineGap);//maxLineGap);

}

bool findUPflag()

{

int result_cols = cropped.cols - UPImg.cols + 1;

int result_rows = cropped.rows - UPImg.cols + 1;

Mat result = Mat( result_cols, result_rows, CV_32FC1 );

matchTemplate( cropped, UPImg, result, CV_TM_SQDIFF );

normalize(result,result,0,1,NORM_MINMAX,-1,Mat());

minMaxLoc( result, NULL, NULL, &minLoc, NULL, Mat() );

rectangle(cropped, Rect(minLoc,UPImg.size()),Scalar(255,0,0), 1, 8, 0);

cout<

if(minLoc.x

return false;

else

return true;//在右下角的情况才会返回,因为大部分卡如此

}

void cropBankNoByUPflag()

{

Rect rc;

rc.x=10;//左起

rc.width=cropped.cols-10;//右结束

rc.y=minLoc.y-60;

rc.height=60;

noImg=cropped(rc);

imshow("noImg",noImg);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值