学更好的别人,
做更好的自己。
——《微卡智享》
本文长度为985字,预计阅读2分钟
前言
最近正好遇到了一个图片的效期提取,正好当做一个小练习记录一下。
实现效果
左边的大图是截取后的原图,右边是提取后的实际图,然后根据提取出来的再进行OCR识别,识别这块就不再说了,这里只是写一下怎么提取的图片。
# | 实现思路 |
---|---|
1 | 转灰度图、高斯模糊 |
2 | Canny边缘提取 |
3 | 定义X轴较长的一个卷积进行膨胀操作 |
4 | 查找轮廓,找到符合条件的截取出来 |
01
预处理
读取图像,转为灰度图,然后高斯模糊。
预处理后的图像
02
Canny边缘提取
这里测试后发现使用50,120的阈值效果不错
Canny后的效果
用Canny的边缘提取的效果是最好的,如果考虑图像二值化什么的,效果会差很多,下面是用二值化和自适应二值化后的效果,可以看到都很不理想。
二值化的效果
自适应二值化效果
上面可以看到,正常二值化效果最差,自适应二值化干扰项也很多,Canny边缘提取的效果最好。
03
膨胀操作
其实上图Canny提取后,里面直接就有一个正方形了,可以不需要这一步直接提取轮廓即可,不过再另一张图效果就没有那么好了,比如下面这个。
所以要对上面这个图做一个卷积为(30,5)的膨胀操作,尽量让其都连接起来。
膨胀后的效果
04
查找轮廓
将所有轮廓都查找出来,这里只查找最外侧轮廓就行,然后画出效果
这一步只是看效果的,真正可以用不到,直接判断符合的轮廓提取即行
完整代码
#pragma once
#include <iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src = imread("E:/DCIM/testdate/pic1.png");
imshow("src", src);
Mat gray, dst;
//转换灰度图
cvtColor(src, gray, COLOR_BGR2GRAY);
//高斯模糊
GaussianBlur(gray, gray, Size(3, 3), 0.5, 0.5);
imshow("gray", gray);
//Canny边缘检测
Canny(gray, dst, 50, 120);
imshow("Canny", dst);
Mat dst2;
//使用膨胀操作,kernel定义的要长一点
Mat kernel = getStructuringElement(MORPH_RECT, Size(30, 5));
morphologyEx(dst, dst2, MORPH_DILATE, kernel);
imshow("morph", dst2);
//查找轮廓,只找最外侧轮廓
vector<vector<Point>> contours;
findContours(dst2, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
RNG rng(12345);
Mat dstzero = Mat::zeros(dst2.size(), CV_8UC3);
for (int i = 0; i < contours.size(); ++i) {
//判断符合区域
RotatedRect rRect = minAreaRect(contours[i]);
Rect rect = rRect.boundingRect();
Scalar color = Scalar(rng.uniform(0, 255),
rng.uniform(0, 255), rng.uniform(0, 255));
rectangle(dstzero, rect, color);
}
imshow("zero", dstzero);
for (int i = 0; i < contours.size(); ++i) {
//判断符合区域
RotatedRect rRect = minAreaRect(contours[i]);
Rect rect = rRect.boundingRect();
if (rect.width / rect.height < 2) {
Mat cutmat = src(rect);
imshow("dstzero"+i, cutmat);
}
}
waitKey(0);
return 0;
}
完
往期精彩回顾
Android Studio 2021.1.1的getNdkVersion的Bug及解决办法
笔记--解决Android使用retrofit2 OkHttp3短时间内大量通讯提示Socket Failed:EMFILE