图像腐蚀目的
·去除图像中微小物体
·分离较近的两个物体
我们对图像中所有米粒进行二值化处理,之后进行连通域分割以求去整个图像中共用多少米粒,处理结果在可以发现,在上图中有一小块区域上有个小点(非米粒),也被视为有数值的情况 。通过图像腐蚀操作就可以将这个微笑区域腐蚀掉,从而得到正确结果。
若图像中有两个非常近的圆,这两个圆在像素中并没有连接在一起,但是由于像素离得近,有可能会误认为两个区域为一个区域,那么通过图像腐蚀,就可以将这两个物体尽可能拉大距离,从而较为明显的去分割出两个物体。
图像腐蚀原理
首先给出一个结构元素,结构元素可以任意指定,这里以十字型结构为例,图像的腐蚀常用于对二值化的图像进行处理, 将此结构元素放置在原图像中像素值为1的区域,我们将结构元素的中心像素放在A区域,得到如下形式:
我们可以看到有部分元素被结构元素覆盖,还有部分元素没有被覆盖,这种情况我们就将像素A删除,之后将结构元素平移,如下:
同样还有没有被结构元素覆盖的情况,因此也许要将此像素1删除,依次进行此操作,可以看到当把结构元素放置到B时,能够把所有像素进行覆盖,那么此时就保留B,将像素B 放置在腐蚀结果中 。
依次移动结构元素,将结构元素的中心依次覆盖在原图像中所有非0像素中,那么最终可得到右图所示腐蚀后结果。整个图像腐蚀操作是一个并行运算的程序。
结构元素生成函数
getStructuringElement()
void cv::getStructuringElement(Int shape,Size ksize,Point anchor = Point(-1,-1))
·shape:结构元素的种类。
·ksize:结构元素的尺寸大小。
·anchor:中心点的位置,默认参数为结构元素的几何中心。
图像腐蚀操作函数
erode()
void cv::erode(InputArray src,OutputArray dst,InputArray kernel,Point anchor = Point(-1,-1),int iterations = 1,int borderType = BORDER_CONSTANT,const Scalar & borderValue = morphologyDefaultBorderValue())
·src:输入的待腐蚀图像,图像的通道数可以是任意的,但是图像的数据类型必须是CV_8U,CV_16U,CV_16S,CV_32F,CV_64F之一。
·dst:腐蚀后的输出图像,与输入图像src具有相同的尺寸和数据类型。
·kernel:用于腐蚀操作的结构元素,可以自己输入,也可以用getStructuringElement()函数生成。
·anchor:中心点在结构元素中的位置,默认参数为结构元素的几何中心点。
·iterations:腐蚀的次数。默认情况是腐蚀1次。
·borderType:像素外推法选择标志。
·borderValue:边界不变的边界值。若图像尺寸较小,要额外注意最后两个参数的选择。
示例
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>using namespace cv; //opencv的命名空间
using namespace std;//绘制包含区域函数
void drawState(Mat &img, int number, Mat centroids, Mat stats, String str)
{RNG rng(10086); //RNG用来生成随机数,这里用了10086进行初始化。vector<Vec3b> colors; //vector是一个能够存放任意类型的动态数组,Vec3b可以看成vector<uchar,3>,即一个uchar类型,长度为3的vector向量(简单地说,就是一个uchar类型的数组,长度为3).for (int i = 0; i < number; i++);{//使用均匀分布的随机数确定颜色;rng.uniform(),可以生成指定范围的均匀分布的随机数Vec3b vec3 = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));colors.push_back(vec3);}//以不同的颜色标记出不同的连通域for (int i = 1; i < number; i++){//中心位置int center_x = centroids.at<double>(i, 0);int center_y = centroids.at<double>(i, 1);//矩形边框int x = stats.at<int>(i, CC_STAT_LEFT);int y = stats.at<int>(i, CC_STAT_TOP);int w = stats.at<int>(i, CC_STAT_WIDTH);int h = stats.at<int>(i, CC_STAT_HEIGHT);//中心位置绘制circle(img, Point(center_x, center_y), 2, Scalar(0, 255, 0), 2, 8, 0);//外接矩形Rect rect(x, y, w, h);rectangle(img, rect, colors[i], 1, 8, 0);putText(img, format("%d", i), Point(center_x, center_y), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);}imshow(str, img);
}//主函数
int main()
{//生成用于腐蚀的原图像Mat src = (Mat_<uchar>(6, 6) << 0, 0, 0, 0, 255, 0,0, 255, 255, 255, 255, 255,0, 255, 255, 255, 255, 0,0, 255, 255, 255, 255, 0,0, 255, 255, 255, 255, 0,0, 0, 0, 0, 0, 0);Mat struct1, struct2;struct1 = getStructuringElement(0, Size(3, 3));//矩形结构元素struct2 = getStructuringElement(1, Size(3, 3));//十字型结构元素Mat erodeSrc; //存放腐蚀后的图像erode(src, erodeSrc, struct2);namedWindow("src", WINDOW_GUI_NORMAL);namedWindow("erodeSrc", WINDOW_GUI_NORMAL);imshow("src", src);imshow("erodeSrc", erodeSrc);cout << "文字腐蚀验证" << endl;waitKey(0);//等待函数用于显示图像,按下键盘任意键后退出Mat LearnCV_black = imread("E:/opencv/opencv-4.6.0-vc14_vc15/opencv/LearnCV_black.png");Mat erode_black1, erode_black2;//黑背景图像腐蚀erode(LearnCV_black, erode_black1, struct1);erode(LearnCV_black, erode_black2, struct2);imshow("LearnCV_black", LearnCV_black);imshow("erode_balck1", erode_black1);imshow("erode_black2", erode_black2);cout << "验证腐蚀对小连通域的去除" << endl;waitKey(0);//等待函数用于显示图像,按下键盘任意键后退出Mat img = imread("E:/opencv/opencv-4.6.0-vc14_vc15/opencv/hua.jpeg");if (img.empty()){cout << "请检查图像文件名称是否正确" << endl;return -1;}Mat img2;copyTo(img, img2, img); //克隆一个单独的图像,用于后期图像检测Mat hua, huaBW;//把图像转为二值图像,用于统计连通域cvtColor(img, hua, COLOR_BGR2GRAY);threshold(hua, huaBW, 50, 255, THRESH_BINARY);Mat out, stats, centroids;//统计图像中连通域的个数int number = connectedComponentsWithStats(huaBW, out, stats, centroids, 8, CV_16U);drawState(img, number, centroids, stats, "未腐蚀时统计连通域");//绘制图像erode(huaBW, huaBW, struct1);//对图像矩形腐蚀number = connectedComponentsWithStats(huaBW, out, stats, centroids, 8, CV_16U);drawState(img2, number, centroids, stats, "腐蚀后统计连通域"); //绘制图像waitKey(0);//等待函数用于显示图像,按下键盘任意键后退出return 0;}
结果