读书笔记-opencv-形态学处理
常用的形态学处理包括:腐蚀,膨胀,开操作,闭操作,顶帽运算,底帽运算等,其中膨胀腐蚀为最基础的方法。
腐蚀
原理解析
图像的腐蚀是选取每个位置邻域中的最小值座位该位置的输出值。邻域可以是矩形结构,也可以是椭圆形结构,十字交叉结构,大多定义为结构元。
选取每个邻域的最小值,腐蚀后的图像亮度会降低,图像中较亮的区域面积会减小甚至消失。图像I,结构元S的腐蚀操作记为:
E=I⊝S
对图像进行腐蚀操作缩小了亮度区域的面积,随意针对阈值分割后前景是白色的二值图,可以通过I−E操作提取边界。
实现代码
对于图像腐蚀opencv提供函数:
erode(src, element[,dst[,iterations[,borderType[,borderValue]]]])
//src 输入矩阵
//element 结构元
//anchor 结构元的锚点
//iterations 迭代的次数
//borderType 边界扩充类型
//borderValue 边界扩充值
对于超出边界,需要扩充图像边界,镜像的方式最好。代表结构元参数element,opencv提供函数:
getStructuringElement(shape, ksize[,anchor])
//shape MORPH_RECT:产生矩形结构元
// MORPH_ELLIPSEM:产生椭圆结构元
// MORPH_CROSS:产生十字交叉结构元
//ksize 结构元尺寸
//anchor 结构元锚点
利用erode和getStrcturingElement函数进行腐蚀操作:
if __name__ =='__main__':
#loading image
image=cv2.imread("G:\\blog\\OpenCV_picture\\chapter6\\img7.jpg",cv2.IMREAD_GRAYSCALE)
cv2.imshow("image",image)
#Entropy threshold
thresh,out=threshEntroy(image)
#show thresh
print(thresh)
out=np.round(out)
out.astype(np.uint8)
#erode
#create element
element = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
#erode image, iterations set 1
erodeImg = cv2.erode(out, element)
#border extraction
bordeExtractionImg = out - erodeImg
cv2.imshow("out",out)
cv2.imshow("erodeImage", erodeImg)
cv2.imshow("border extraction image", bordeExtractionImg)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7h40f80j-1571986151633)(C:\Users\huangxin\Desktop\仿射变换\opencv算法精讲-7\1.png)]
C++腐蚀操作:
//创建结构元
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
//进行2次腐蚀操作
Mat erodeImage1, erodeImage2;
erode(OtsuMat, erodeImage1, element, Point(-1, -1), 2);
erode(threshByEntroyMat, erodeImage2, element, Point(-1, -1), 2);
//显示图片
imshow("src", src);
imshow("dst", thresh_out_dst);
imshow("threshByEntroy", threshByEntroyMat);
imshow("Otsu", OtsuMat);
imshow("erode after Otsu", erodeImage1);
imshow("erode after threshByEntroy", erodeImage2);
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y6V1KLkY-1571986151634)(C:\Users\huangxin\Desktop\仿射变换\opencv算法精讲-7\2.png)]
结构元尺寸增大,目标物体的白色区域越来越小;反复进行腐蚀操作,白色区域也会越来越小。
膨胀
与腐蚀相类似,但是取得是邻域的最大值,膨胀后图像的亮度会增加,较亮的区域会增加。图像I和结构元S膨胀操作记为:
D=I⊕S
代码实现
open’c’v提供函数dilate()
dilate(src, element[,dst[,iterations[,borderType[,borderValue]]]])
//src 输入矩阵
//element 结构元
//anchor 结构元的锚点
//iterations 迭代的次数
//borderType 边界扩充类型
//borderValue 边界扩充值
if __name__=="__main__":
image=cv2.imread("G:\\blog\\OpenCV_picture\\chapter6\\img7.jpg",cv2.IMREAD_GRAYSCALE)
cv2.imshow("init iamge", image)
#结构元半径,迭代次数
radius, iterationsNum = 1, 1
MAX_R, MAX_Iter = 20, 20
#显示膨胀窗口
cv2.namedWindow("dilate", 1)
def nothing(*arg):
pass
#调节结构圆半径
cv2.createTrackbar("radius", "dilate", radius, MAX_R, nothing)
cv2.createTrackbar("iterations", "dilate", iterationsNum, MAX_Iter, nothing)
while True:
#获得当前的半径值
radius = cv2.getTrackbarPos("radius", 'dilate')
iterationsNum = cv2.getTrackbarPos("iterations", "dilate")
#创建结构元
element = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2*radius+1, 2*radius+1))
#膨胀图像
dilateImg = cv2.dilate(image, element, iterations=iterationsNum)
#显示膨胀效果
cv2.imshow("dilate", dilateImg)
ch = cv2.waitKey(5)
#按下Esc键退出
if ch == 27:
break
cv2.destroyAllWindows()
注意在这段代码“s = cv2.getStructuringElement(cv2.MORPH_OPEN,(2r+1,2r+1))”里面把cv2.cv2.MORPH_ELLIPSE在另一个程序里面会报错会报错,显示“error: (-215:Assertion failed) anchor.inside(Rect(0, 0, ksize.width, ksize.height)) in function ‘cv::normalizeAnchor’
找到这个问题出在哪里,因为我的cv2.destroyAllWindows()写在while循环里面了,造成后面的无法获取半径值和迭代值。
element最小的尺寸为3*3,必须要比这个尺寸大,不然也会报错
int radius = 1;
int MAX_R = 20;
Mat image, outImg;
//回调函数,调节半径
void callBack(int, void *)
{
//创建只有垂直方向上的矩形结构元
Mat element = getStructuringElement(MORPH_RECT, Size(1, 2 * radius + 1));
dilate(image, outImg, element);
imshow("dilate", outImg);
}
int main()
{
//输入图像
std::string imagePath = "G:\\blog\\OpenCV_picture\\chapter6\\img7.jpg";
Mat src = imread(imagePath, 0);
if (!src.data)
{
std::cout << "load image error!" << std::endl;
return -1;
}
Mat thresh_out_dst;
int ret = 0;
ret = threshTwoPeaks(src, thresh_out_dst);
if (!ret)
{
return -1;
}
cout << ret << endl;
Mat threshByEntroyMat;
ret = threshByEntroy(src, threshByEntroyMat);
if (!ret)
{
return -1;
}
cout << ret << endl;
Mat OtsuMat;
ret = Otsu(src, OtsuMat);
if (!ret)
{
return -1;
}
cout << ret << endl;
imshow("Otsu", OtsuMat);
waitKey(0);
OtsuMat.copyTo(image);
//image=OtsuMat.clone();
imshow("img", image);
namedWindow("dilate", WINDOW_AUTOSIZE);
createTrackbar("radius", "dilate", &radius, MAX_R, callBack);
callBack(0, 0);
waitKey(0);
return 0;
}
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jilr78rT-1571986151636)(C:\Users\huangxin\Desktop\仿射变换\opencv算法精讲-7\4.png)]
其中的OstuMat是前面的Ostu阈值分割得到图片。
开运算和闭运算
开运算先进行膨胀在进行腐蚀。
消除亮度较高的细小区域,在纤细点处分离物体,对于较大物体,可以不明显改变其面积的情况下平滑边界等作用。
闭运算先进行腐蚀在进行膨胀。
它可以填充白色物体内细小的黑色空洞区域,连接邻近物体,同一结构元,多次处理,也可以不明显改变其面积的情况下平滑边界等作用。
opencv提供函数norphologyEx()函数
norphologyEx(src, op, element[,dst[, anchor[iterations[,borderType[,borderValue]]]]])
//src 输入矩阵
//op 形态学处理的各种运算
// NORPH_OPEN 开运算
// NORPH_CLOSE 闭运算
// NORPH_GRADIENT 形态梯度
// NORPH_TOPHAT 顶帽运算
// NORPH_BLACKHAT 底帽运算
//element 结构元
//iterations 迭代次数
//anchor 结构元锚点
if __name__ == "__main__":
image = cv2.imread("G:\\blog\\OpenCV_picture\\chapter7\\img1.jpg", 0)
cv2.imshow("InitImage", image)
#结构元半径
radius, iter = 1, 1
MAX_R, MAX_Iter = 20, 20
#
cv2.namedWindow("morphology", 1)
def nothing(*arg):
pass
cv2.createTrackbar("radius", "morphology", radius, MAX_R, nothing)
cv2.createTrackbar("iterations", "morphology", iter, MAX_Iter, nothing)
while True:
radius = cv2.getTrackbarPos("radius", "morphology")
iter = cv2.getTrackbarPos("iterations", "morphology")
element = cv2.getStructuringElement(cv2.MORPH_RECT,(2*radius+1, 2*radius +1))
photoMorphology = cv2.morphologyEx(image, cv2.MORPH_OPEN,element,iterations=iter)
cv2.imshow("morphology", photoMorphology)
ch = cv2.waitKey(5)
if ch == 27:
break
cv2.destroyAllWindows()
运行结果[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vBQSaH8w-1571986151637)(C:\Users\huangxin\Desktop\仿射变换\opencv算法精讲-7\5.png)]
开操作消除暗背景下的的较亮区域,在明显不改变面积的情况下,消除白色亮的区域。闭操作是消除较亮区域内的较暗区域
顶帽变换
顶帽变换的定义图像减去开运算的结果
开运算可以消除暗背景下的较亮区域。原图减去开运算得到途中灰度较亮的区域,作用之一较正不均匀光照。又称白顶帽变换
底帽变换
底帽运算的定义图像减去闭运算的结果
开运算可以消除较亮背景下的较暗区域。原图减去开运算得到途中灰度较暗的区域,又称黑顶帽变换
形态学梯度
形态学梯度的定义为膨胀减去腐蚀的结果,膨胀为邻域的最大值,腐蚀为淋雨的最小值,高亮度减去低亮度得到的是物体的边界。
在opencv提供的函数morphologyEx修改op的值就可以实现顶帽,底帽运算,形态学梯度
//输入图像
Mat I;
//输出图像
Mat d;
//结构元
Mat element;
string window = "形态学处理";
//结构元半径
int r = 1;
int MAX_R = 20;
//迭代次数
int i = 1;
int MAX_I = 20;
//回调函数,调节r和i
void callBack(int, void*)
{
//创建结构元
element = getStructuringElement(MORPH_RECT, Size(2 * r + 1, 2 * r + 1));
//形态学处理
morphologyEx(I, d, cv::MORPH_TOPHAT, element, Point(-1, -1), i);
//显示形态处理的效果
imshow(window, d);
}
int main(int argc, char*argv[])
{
//输入图像
I = imread("G:\\blog\\OpenCV_picture\\chapter7\\open.jpg", 0);
if (!I.data)
return 0;
//显示原图
imshow("原图", I);
//创建显示形态学结果显示窗口
namedWindow(window, 1);
//创建调节r的进度条
createTrackbar("半径", window, &r, MAX_R, callBack);
//创建调节i的进度条
createTrackbar("迭代次数", window, &i, MAX_I, callBack);
callBack(0, 0);
waitKey(0);
return 0;
}
运行图片:
{
//输入图像
I = imread(“G:\blog\OpenCV_picture\chapter7\open.jpg”, 0);
if (!I.data)
return 0;
//显示原图
imshow(“原图”, I);
//创建显示形态学结果显示窗口
namedWindow(window, 1);
//创建调节r的进度条
createTrackbar(“半径”, window, &r, MAX_R, callBack);
//创建调节i的进度条
createTrackbar(“迭代次数”, window, &i, MAX_I, callBack);
callBack(0, 0);
waitKey(0);
return 0;
}
运行图片:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qG5oqqdk-1571986151638)(C:\Users\huangxin\Desktop\仿射变换\opencv算法精讲-7\6.png)]