PS:本篇通过两个小的案例,来示范下形态学操作在图像处理过程中的应用。
提取一副图片中的水平线和水直线
AIP介绍
自适应阈值分割
void adaptiveThreshold(InputArray src, OutputArray dst,
double maxValue, int adaptiveMethod,
int thresholdType, int bolckSize, double C)
参数1:InputArray类型的src,输入图像,填单通道,单8位浮点类型Mat即可。
参数2:函数运算后的结果存放在这。即为输出图像(与输入图像同样的尺寸和类型)。
参数3:预设满足条件的最大值,普通图像为255。
参数4:指定自适应阈值算法。可选择ADAPTIVE_THRESH_MEAN_C 或 ADAPTIVE_THRESH_GAUSSIAN_C两种。
参数5:指定阈值类型。可选择THRESH_BINARY或者THRESH_BINARY_INV两种。(即二进制阈值或反二进制阈值)。
参数6:表示邻域块大小,用来计算区域阈值,选用奇数。
参数7:参数C表示与算法有关的参数,它是一个从均值或加权均值提取的常数,可以是负数。
ADAPTIVE_THRESH_MEAN_C,为局部邻域块的平均值,该算法是先求出块中的均值,再减去常数C。
ADAPTIVE_THRESH_GAUSSIAN_C,为局部邻域块的高斯加权和。该算法是在区域中(x, y)周围的像素根据高斯函数按照他们离中心点的距离进行加权计算,再减去常数C。
流程与思路
- 首先将图片转换为灰度图片
- 使用自适应阈值分割,将图片处理为二至图片(注意:前景比背景暗时,对前景处理应使用闭操作;前景比背景亮时,对前景处理应使用开操作);
- 设计运算核用于提取在横向和纵向的连通线条:
- 如提取横向水平线条,则核的形状应为Size(5,1);如提取竖向垂直线条,则核的形状应为Size(1,5)。总之,所要提取的方向上,核的应大于另一个方向。
- 提取方向上,核的跨度越大,则提取的程度越高,即要求该方向上的连通程度比较高才会被提取出来。
- 非提取方向上,设为“1”,保证隔断另一个方向连通性对提取方向的干扰。
代码与实践
#include <iostream>
#include <math.h>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
//src = imread("src.jpg");
Mat src = imread("1.PNG");
if (!src.data)
{
cout << "cannot open image" << endl;
return -1;
}
namedWindow("input image", WINDOW_AUTOSIZE);
imshow("input image",src);
Mat gray;
cvtColor(src,gray ,COLOR_BGR2GRAY);
imshow("gray", gray);
adaptiveThreshold(gray, gray, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, 10);
imshow("bineray", gray);
Mat Hline = getStructuringElement(MORPH_RECT, Size(1, 5), Point(-1, -1));
Mat Vline = getStructuringElement(MORPH_RECT, Size(5, 1), Point(-1, -1));
Mat H_res, V_res;
morphologyEx(gray,H_res,MORPH_CLOSE,Hline);
morphologyEx(gray,V_res,MORPH_CLOSE,Vline);
imshow("H-res", H_res);
imshow("V-res", V_res);
waitKey(0);
return 0;
}
去除验证码图片中的背景干扰
流程与思路(参照上面的例子)
- 首先将图片转换为灰度图片
- 使用自适应阈值分割,将图片处理为二至图片(注意:前景比背景暗时,对前景处理应使用闭操作;前景比背景亮时,对前景处理应使用开操作);
- 根据噪点的大小,来调节运算核的大小,让其可以滤除背景干扰,却又保存字符的连通性。一般核大小的长宽比与验证码图片的长宽比相同较为合适。否则应根据实际情况进行调节,保证运算核在保持字符连通性时,尽量大,越大对噪声的滤除也越强。
代码与实践
#include <iostream>
#include <math.h>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
Mat src = imread("chars.png");
if (!src.data)
{
cout << "cannot open image" << endl;
return -1;
}
namedWindow("input image", WINDOW_AUTOSIZE);
imshow("input image",src);
Mat gray;
cvtColor(src,gray ,COLOR_BGR2GRAY);
imshow("gray", gray);
adaptiveThreshold(gray, gray, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, 10);
imshow("bineray", gray);
Mat Kernel = getStructuringElement(MORPH_RECT, Size(3, 5), Point(-1, -1));
//改变核在总想和横向的范围,来保证字符的连通性
Mat Result;
morphologyEx(gray,Result,MORPH_CLOSE,Kernel);
imshow("Result", Result);
waitKey(0);
return 0;
}