膨胀、腐蚀、开、闭运算是形态学操作中最基本的操作
形态学操作一般针对于 二值化图像。
腐蚀:在核区域内,选择最小像素值为当前像素值,和最小值滤波类似、不同点:腐蚀的核形状可以是圆形、矩形和十字形等等。腐蚀从图像变化上来看:就是黑吃白(因为选择的是最小值像素值)。
膨胀:在核区域内,选择最大像素值为当前像素值,和最大值滤波类似;不同点:同上,膨胀从图像变化上来看:白吃黑(因选最大像素值)。
开运算:先腐蚀,后膨胀 应用:如 去掉在黑色背景下小块白色区域, 先腐蚀:把小块白色区域吃掉。后膨胀:把大块白色复原。
闭运算:先膨胀,后腐蚀 应用:如 去掉在白色背景下的小块黑色区域。
形态渐层处理:膨胀 减去 腐蚀 又称:基本梯度。还有内部梯度(原图 - 腐蚀图)、方向梯度(x或y方向进行梯度计算)。
顶帽:原图 与 开运算的差值 ---得开运算后的图与原图的变化图。 如:开运算解释 应用中的 小块白色区域。
黑帽:闭运算 与 原图的差值。 ---得闭运算后的图与原图的变化图。如:开运算解释 应用中的 小块黑色区域。
根据想要去掉的区域大小,进行选择核大小。
介绍两个个API
(1)自适应阈值化操作:adaptiveThreshold()函数
1. 每个像素位置处的二值化阈值不是固定不变的,而是由其周围邻域像素的分布来决定的。
2. 亮度较高的图像区域的二值化阈值通常会较高,而亮度低的图像区域的二值化阈值则会相适应的变小。
3. 不同亮度、对比度、纹理的局部图像区域将会拥有相对应的局部二值化阈值。
1. void adaptiveThreshold(InputArray src, OutputArray dst, 2. double maxValue, int adaptiveMethod, 3. int thresholdType, int bolckSize, double C)
参数说明
参数1:InputArray类型的src,输入图像,填单通道,单8位浮点类型Mat即可。
参数2:函数运算后的结果存放在这。即为输出图像(与输入图像同样的尺寸和类型)。
参数3:预设满足条件的最大值。
参数4:指定自适应阈值算法。可选择ADAPTIVE_THRESH_MEAN_C 或 ADAPTIVE_THRESH_GAUSSIAN_C两种。(具体见下面的解释)。
参数5:指定阈值类型。可选择THRESH_BINARY或者THRESH_BINARY_INV两种。(即二进制阈值或反二进制阈值)。
参数6:表示邻域块大小,用来计算区域阈值,一般选择为3、5、7......等。
参数7:参数C表示与算法有关的参数,它是一个从均值或加权均值提取的常数,可以是负数。(具体见下面的解释)。
对参数4与参数7内容的解释:
自适应阈值化计算大概过程是为每一个象素点单独计算的阈值,即每个像素点的阈值都是不同的,就是将该像素点周围B*B区域内的像素加权平均,然后减去一个常数C,从而得到该点的阈值。B由参数6指定,常数C由参数7指定。
ADAPTIVE_THRESH_MEAN_C,为局部邻域块的平均值,该算法是先求出块中的均值,再减去常数C。
ADAPTIVE_THRESH_GAUSSIAN_C,为局部邻域块的高斯加权和。该算法是在区域中(x, y)周围的像素根据高斯函数按照他们离中心点的距离进行加权计算,再减去常数C。
举个例子:如果使用平均值方法,平均值mean为190,差值delta(即常数C)为30。那么灰度小于160的像素为0,大于等于160的像素为255。如下图:
如果是反向二值化,如下图:
delta(常数C)选择负值也是可以的。
(2)高级形态变换函数 morphologyEx
CV_EXPORTS_W void morphologyEx( InputArray src, OutputArray dst,
int op, InputArray kernel,
Point anchor=Point(-1,-1), int iterations=1,
int borderType=BORDER_CONSTANT,
const Scalar& borderValue=morphologyDefaultBorderValue() );
morphologyEx函数利用基本的膨胀和腐蚀技术,来执行更加高级形态学变换
src
输入图像,图像位深应该为以下五种之一:CV_8U, CV_16U,CV_16S, CV_32F 或CV_64F。
dst
输出图像,需和源图片保持一样的尺寸和类型。
op
表示形态学运算的类型:
MORPH_OPEN – 开运算(Opening operation)
MORPH_CLOSE – 闭运算(Closing operation)
MORPH_GRADIENT - 形态学梯度(Morphological gradient)
MORPH_TOPHAT - 顶帽(Top hat)
MORPH_BLACKHAT - 黑帽(Black hat)
kernel
形态学运算的内核。为NULL,使用参考点位于中心3x3的核。一般使用函数getStructuringElement配合这个参数的使用,
kernel参数填保存getStructuringElement返回值的Mat类型变量。
anchor
锚的位置,其有默认值(-1,-1),表示锚位于中心。
iterations
迭代使用函数的次数,默认值为1。
borderType
用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_CONSTANT。
borderValue
当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),
一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释。
提取线 和 提取ABCD 实例代码
#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
#include<algorithm>
using namespace std;
using namespace cv;
void MorV() // 垂直线提取
{
Mat src, dst,gray_src;
src = imread("C:/Users/Geek/Desktop/1281425_2019-07-18_10_0/zhiline.png", 1);
imshow("src", src);
cvtColor(src,gray_src,CV_BGR2GRAY);
imshow("gray_src", gray_src);
Mat BinImage;
//imshow("~gray_src",~gray_src);
adaptiveThreshold(gray_src, BinImage, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 21, 25);
// 一定要学习好使用这个函数,注意各个参数,其实可以自己写(看我博客即可)
imshow("BinImage", BinImage);
// 水平核
Mat hline = getStructuringElement(MORPH_RECT, Size(30, 1), Point(-1, -1));
// 竖直核
Mat vline = getStructuringElement(MORPH_RECT, Size(1, 40), Point(-1, -1)); // 你看我垂直核多大,因为A太粗了
Mat DImage;
//dilate(BinImage, DImage, hline); // 膨胀
//erode(DImage, dst, hline); // 腐蚀
morphologyEx(BinImage,dst,MORPH_CLOSE, vline, Point(-1, -1));
blur(dst, dst, Size(3, 3),Point(-1,-1));
imshow("dst",dst);
waitKey(0);
}
void MorH() // 水平线提取
{
Mat src, dst, gray_src;
src = imread("C:/Users/Geek/Desktop/1281425_2019-07-18_10_0/zhiline.png", 1);
imshow("src", src);
cvtColor(src, gray_src, CV_BGR2GRAY);
imshow("gray_src", gray_src);
Mat BinImage;
//imshow("~gray_src",~gray_src);
adaptiveThreshold(~gray_src, BinImage, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 21, -10);
// 看准 ~ 和 21窗口大小 和 阈值减去的值(最后一个值)。
// 一定要学习好使用这个函数,注意各个参数,其实可以自己写(看我博客即可)
imshow("BinImage", BinImage);
// 水平核
Mat hline = getStructuringElement(MORPH_RECT, Size(20, 1), Point(-1, -1));
// 竖直核
Mat vline = getStructuringElement(MORPH_RECT, Size(1, 20), Point(-1, -1));
Mat DImage;
//erode(BinImage, DImage, hline); // 腐蚀
//dilate(DImage, dst, hline); // 膨胀
morphologyEx(BinImage, dst, MORPH_OPEN, hline, Point(-1, -1)); // 开运算
bitwise_not(dst, dst); // 进行 非运算 和 ~应该相同。
blur(dst, dst, Size(3, 3), Point(-1, -1));
imshow("dst", dst);
waitKey(0);
}
void MorABCD() // 提取ABCD
{
Mat src, dst, gray_src;
src = imread("C:/Users/Geek/Desktop/1281425_2019-07-18_10_0/处理ABCD.png", 1);
imshow("src", src);
cvtColor(src, gray_src, CV_BGR2GRAY);
imshow("gray_src", gray_src);
Mat BinImage;
//imshow("~gray_src",~gray_src);
adaptiveThreshold(~gray_src, BinImage, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 21, -10);
// 看准 ~ 和 21窗口大小 和 阈值减去的值(最后一个值)。
// 一定要学习好使用这个函数,注意各个参数,其实可以自己写(看我博客即可)
imshow("BinImage", BinImage);
// 水平核
Mat hline = getStructuringElement(MORPH_RECT, Size(20, 1), Point(-1, -1));
// 竖直核
Mat vline = getStructuringElement(MORPH_RECT, Size(1, 20), Point(-1, -1));
Mat ABCD = getStructuringElement(MORPH_RECT, Size(2, 2), Point(-1, -1));
Mat DImage;
//erode(BinImage, DImage, hline); // 腐蚀
//dilate(DImage, dst, hline); // 膨胀
morphologyEx(BinImage, dst, MORPH_OPEN, ABCD, Point(-1, -1)); // 开运算
//morphologyEx(BinImage, dst, MORPH_OPEN, ABCD, Point(-1, -1)); // 开运算
blur(dst, dst, Size(3, 3), Point(-1, -1));
bitwise_not(dst, dst); // 进行 非运算 和 ~应该相同。
imshow("dst", dst);
waitKey(0);
}
int main()
{
MorV();
MorH();
MorABCD();
return 0;
}
结果:
提取ABCD
提取直线结果