目录
1、腐蚀
1.1 腐蚀目的
1.2 原理与代码实现
2、膨胀
3、应用
3.1 开闭运算、形态学梯度
3.1.1 开运算
3.1.2 闭运算
编辑
3.1.3 形态学梯度
编辑
3.1.4 顶帽与黑帽运算
3.2 相关函数
形态学操作常用于对二值化图像的操作
1、腐蚀
1.1 腐蚀目的
去除图像中微小物体,分离较近的两个物体
1.2 原理与代码实现
//绘制包含区域函数
void drawState(Mat &img, int number, Mat centroids, Mat stats, String str)
{
RNG rng(10086);
vector<Vec3b> colors;
for (int i = 0; i < number; i++)
{
//使用均匀分布的随机数确定颜色
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 test1()
{
//生成用于腐蚀的原图像
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("F:/testMap/rice.png", IMREAD_ANYCOLOR);
Mat erode_black1,erode_black2;
//黑背景图像腐蚀
erode(LearnCV_black,erode_black1,struct1);
erode(LearnCV_black, erode_black2,struct2);
imshow("LearnCV_black", LearnCV_black);
imshow("erode_blackl", erode_black1);
imshow("erode_black2", erode_black2);
cout << "验证腐蚀对小连通域的去除"<< endl;
waitKey(0);
Mat img = imread("F:/testMap/rice.png");
if (img.empty())
{
cout << "请确认图像文件名称是否正确"<< endl;
return -1;
}
Mat img2;
copyTo(img,img2,img);//克隆一个单独的图像,用于后期图像绘制
Mat rice,riceBW;
//将图像转成二值图像,用于统计连通域
cvtColor(img,rice,COLOR_BGR2GRAY);
threshold(rice,riceBW,50,255,THRESH_BINARY);
Mat out,stats, centroids;
//统计图像中连通域的个数
int number = connectedComponentsWithStats(riceBW,out,stats,centroids, 8,CV_16U);
drawState(img,number,centroids,stats,"未腐蚀时统计连通域");//绘制图像
erode(riceBW, riceBW, struct1);//对图像进行腐蚀
number = connectedComponentsWithStats(riceBW, out,stats, centroids,8,CV_16U);
drawState(img2,number,centroids,stats,"腐蚀后统计连通域");//绘制图像
waitKey(0);
return 0;
}
2、膨胀
同上
//形态学操作-膨胀
int test2()
{
//生成用于膨胀的原图像
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;//存放膨胀后的图像
dilate(src, erodeSrc, struct2);//膨胀
namedWindow("src",WINDOW_GUI_NORMAL);
namedWindow("dilateSrc",WINDOW_GUI_NORMAL);
imshow("src",src) ;
imshow("dilateSrc", erodeSrc);
cout << "文字膨胀" << endl;
waitKey(0);
Mat LearnCV_black = imread("F:/testMap/learnCV_black.png", IMREAD_ANYCOLOR);
Mat dilate_black1, dilate_black2;
//黑背景图像膨胀
dilate(LearnCV_black, dilate_black1, struct1);
dilate(LearnCV_black,dilate_black2, struct2);
imshow("LearnCV_black", LearnCV_black);
imshow("dilate_black1", dilate_black1);
imshow("dilate_black2", dilate_black2);
waitKey(0);
return 0;
}
3、应用
3.1 开闭运算、形态学梯度
3.1.1 开运算
先腐蚀再膨胀
3.1.2 闭运算
先膨胀再腐蚀
3.1.3 形态学梯度
膨胀结果减去腐蚀结果
3.1.4 顶帽与黑帽运算
原图像减去开运算
闭运算减去原图像
3.2 相关函数
//形态学应用
int test3()
{
//用于验证形态学应用的二值化矩阵
Mat src = (Mat_<uchar>(9, 12) << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 0,
0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0,
0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 0,
0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
namedWindow("src", WINDOW_NORMAL);//可以自由调节显示图像的尺寸
imshow("src", src);
//3×3矩形结构元素
Mat kernel = getStructuringElement(0, Size(3, 3));
//对二值化矩阵进行形态学操作
Mat open, close, gradient, tophat, blackhat, hitmiss;
//对二值化矩阵进行开运算
morphologyEx(src, open, MORPH_OPEN, kernel);
namedWindow("open", WINDOW_NORMAL);//可以自由调节显示图像的尺寸
imshow("open", open);
//对二值化矩阵进行闭运算
morphologyEx(src, close, MORPH_CLOSE, kernel);
namedWindow("close", WINDOW_NORMAL);//可以自由调节显示图像的尺寸
imshow("close", close);
//对二值化矩阵进行梯度运算
morphologyEx(src, gradient, MORPH_GRADIENT, kernel);
namedWindow(" gradient", WINDOW_NORMAL);//可以自由调节显示图像的尺寸
imshow("gradient", gradient);
//对二值化矩阵进行顶帽运算
morphologyEx(src, tophat, MORPH_TOPHAT, kernel);
namedWindow("tophat", WINDOW_NORMAL);//可以自由调节显示图像的尺寸
imshow("tophat ", tophat);
//对二值化矩阵进行黑帽运算
morphologyEx(src, blackhat, MORPH_BLACKHAT, kernel);
namedWindow("blackhat", WINDOW_NORMAL);//可以自由调节显示图像的尺寸
imshow("blackhat", blackhat);
//对二值化矩阵进行击中击不中变换
morphologyEx(src, hitmiss, MORPH_HITMISS, kernel);
namedWindow("hitmiss", WINDOW_NORMAL);//可以自由调节显示图像的尺寸
imshow("hitmiss", hitmiss);
cout << "用图像验证形态学操作效果" << endl;
waitKey(0);
Mat keys = imread("F:/testMap/key.png", IMREAD_GRAYSCALE);
imshow("原图像", keys);
threshold(keys, keys, 80, 255, THRESH_BINARY); //二值化
imshow("二值化后的keys", keys);
//5×5矩形结构元素
Mat kernel_keys = getStructuringElement(0, Size(5, 5));
Mat open_keys, close_keys, gradient_keys, tophat_keys, blackhat_keys, hitmiss_keys;
//对图像进行开运算
morphologyEx(keys, open_keys, MORPH_OPEN, kernel_keys);
imshow("open_keys", open_keys);
//对图像进行闭运算
morphologyEx(keys, close_keys, MORPH_CLOSE, kernel_keys);
imshow("close_keys", close_keys);
//对图像进行梯度运算
morphologyEx(keys, gradient_keys, MORPH_GRADIENT, kernel_keys);
imshow(" gradient_keys", gradient_keys);
//对图像进行顶帽运算
morphologyEx(keys, tophat_keys, MORPH_TOPHAT, kernel_keys);
imshow("tophat_keys", tophat_keys);
//对图像进行黑帽运算
morphologyEx(keys, blackhat_keys, MORPH_BLACKHAT, kernel_keys);
imshow("blackhat_keys", blackhat_keys);
//对图像进行击中击不中变换
morphologyEx(keys, hitmiss_keys, MORPH_HITMISS, kernel_keys);
imshow("hitmiss_keys", hitmiss_keys);
waitKey(0);
return 0;
}