前言
在日常的开发中,我们有时会遇到添加银行卡的需求,这时候,产品可能会让你仿一下支付宝之类的相机扫描识别银行卡号。很多时候,做这样的需求会去找找稳定的第三方,本文通过 OpenCV 结合识别的需求带你分析如何实现银行卡号的识别。由于作者技术有限,本文仅从如何做到识别的思路上介绍,文中例子不适用于实际开发,也不是所有银行卡都能识别,但希望读者可以在实现的思路上给予一些启发,以及更深入熟悉 OpenCV 的组合使用。
1. 银行卡识别思路分析
1.1 银行卡一般具有的特征
银行卡一般会有 银行、卡号、银联标识等等,主要的是卡号区域,大多数银行卡卡号都是在下方显示的。那么,在检索一张图片的时候,要首先找到卡在哪里,卡一般是长方形,所以我们在背景色不非常接近下可以找到银行卡的轮廓。
1.2 总体实现思路和步骤
在图片中找到银行卡区域 --> 在银行卡区域找到卡号区域 --> 在卡号区域中找到卡号每个数字的集合 --> 识别数字
2. 在图片中找到银行卡区域
2.1 实现思路和步骤
- 高斯模糊降噪处理
- 边缘梯度增强
- 取增强绝对值
- 合并 Mat
- 转灰度
- 二值化
- 从二值图像中检索轮廓
- 从集合中找合适的轮廓
2.2 具体实现
/**
* 在图片中找到银行卡区域
* @param mat 图片
* @param rect 银行卡区域
* @return 是否成功
*/
int ocr::find_card_area(const Mat &mat, Rect &card_area) {
// 1. 高斯模糊降噪处理
Mat blurMat;
GaussianBlur(mat, blurMat, Size(5, 5), BORDER_DEFAULT, BORDER_DEFAULT);
// 2. 边缘梯度增强
// Scharr( InputArray src, OutputArray dst, int ddepth, int dx, int dy, double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT )
// ddepth:输出图像的深度
// dx:x方向上的差分阶数
// dy:y方向上的差分阶数
// 对 x 增强
Mat grade_x;
Scharr(blurMat, grade_x, CV_32F, 1, 0);
// 对 y 增强
Mat grade_y;
Scharr(blurMat, grade_y, CV_32F, 0, 1);
// 3. 取增强绝对值
Mat abs_grade_x;
convertScaleAbs(grade_x, abs_grade_x);
Mat abs_grade_y;
convertScaleAbs(grade_y, abs_grade_y);
// 4. 合并 Mat
Mat gradeMat;
addWeighted(abs_grade_x, 0.5, abs_grade_y, 0.5, 0, gradeMat);
//imwrite("/storage/emulated/0/ocr/find_card_area_gradeMat.jpg", gradeMat);
// 5. 转灰度
Mat grayMat;
cvtColor(gradeMat, grayMat, COLOR_BGRA2GRAY);
//imwrite("/storage/emulated/0/ocr/find_card_area_grayMat.jpg", grayMat);
// 6. 二值化
// threshold( InputArray src, OutputArray dst, double thresh, double maxval, int type )
// thresh:设定的阈值
// maxval;当灰度值大于(或小于)阈值时将该灰度值赋成的值
// type:当前二值化