opencv#37 形态学操作——腐蚀

图像腐蚀目的

·去除图像中微小物体

·分离较近的两个物体

opencv#37 形态学操作——腐蚀_第1张图片

我们对图像中所有米粒进行二值化处理,之后进行连通域分割以求去整个图像中共用多少米粒,处理结果在可以发现,在上图中有一小块区域上有个小点(非米粒),也被视为有数值的情况 。通过图像腐蚀操作就可以将这个微笑区域腐蚀掉,从而得到正确结果。

若图像中有两个非常近的圆,这两个圆在像素中并没有连接在一起,但是由于像素离得近,有可能会误认为两个区域为一个区域,那么通过图像腐蚀,就可以将这两个物体尽可能拉大距离,从而较为明显的去分割出两个物体。

图像腐蚀原理

opencv#37 形态学操作——腐蚀_第2张图片

首先给出一个结构元素,结构元素可以任意指定,这里以十字型结构为例,图像的腐蚀常用于对二值化的图像进行处理, 将此结构元素放置在原图像中像素值为1的区域,我们将结构元素的中心像素放在A区域,得到如下形式:

opencv#37 形态学操作——腐蚀_第3张图片

我们可以看到有部分元素被结构元素覆盖,还有部分元素没有被覆盖,这种情况我们就将像素A删除,之后将结构元素平移,如下:

opencv#37 形态学操作——腐蚀_第4张图片

同样还有没有被结构元素覆盖的情况,因此也许要将此像素1删除,依次进行此操作,可以看到当把结构元素放置到B时,能够把所有像素进行覆盖,那么此时就保留B,将像素B 放置在腐蚀结果中 。

opencv#37 形态学操作——腐蚀_第5张图片

依次移动结构元素,将结构元素的中心依次覆盖在原图像中所有非0像素中,那么最终可得到右图所示腐蚀后结果。整个图像腐蚀操作是一个并行运算的程序。

结构元素生成函数

getStructuringElement() 

void cv::getStructuringElement(Int   shape,
                               Size  ksize,
                               Point anchor = Point(-1,-1)
                              )

·shape:结构元素的种类。

·ksize:结构元素的尺寸大小。

·anchor:中心点的位置,默认参数为结构元素的几何中心。

opencv#37 形态学操作——腐蚀_第6张图片

图像腐蚀操作函数

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 
#include 
#include 

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 colors; //vector是一个能够存放任意类型的动态数组,Vec3b可以看成vector,即一个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(i, 0);
		int center_y = centroids.at(i, 1);
		//矩形边框
		int x = stats.at(i, CC_STAT_LEFT);
		int y = stats.at(i, CC_STAT_TOP);
		int w = stats.at(i, CC_STAT_WIDTH);
		int h = stats.at(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_(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;

}
结果

opencv#37 形态学操作——腐蚀_第7张图片

opencv#37 形态学操作——腐蚀_第8张图片 

opencv#37 形态学操作——腐蚀_第9张图片 

 

你可能感兴趣的:(opencv,人工智能,计算机视觉)