参考文献:
OTSU阈值分割+孔洞填充+海陆分离_SwordKii的博客-CSDN博客
drawContours函数_普通网友的博客-CSDN博客_drawcontours
R329-opencv阈值分割算法——自适应阈值_Third Impact的博客-CSDN博客_opencv自适应阈值分割
分水岭算法的python实现及解析_进不去的博客-CSDN博客_python分水岭算法
分水岭算法的理解和应用_Evonne_H的博客-CSDN博客_分水岭算法详细介绍与应用
目录
OTSU大津算法(常用于海陆分割)
1.原理:
2.代码API
3.实现:
自适应阈值算法(复杂颜色地物提取例如打鱼船)
1.原理
2.代码API
3.实现
分水岭算法
OTSU大津算法(常用于海陆分割)
1.原理:
寻找海陆分割二值化的阈值,通过统计学方法,找到方差最大的时候的灰度值
2.代码API
#获取二值图像轮廓
contours, hierarchy=cv.findContours( img, mode, method);
contours:输出的轮廓,每一个轮廓用std::vector<std::vector >来存储;
hierarchy:输出的轮廓关系的存储;
img:二值图像;
mode:轮廓模式
cv.RETR_EXTERNAL:只有最外层轮廓;
cv.RETR_LIST : 检测所有的轮廓,但是轮廓之间都是单独的,没有父子关系;
cv.RETR_CCOMP : 检测所有的轮廓,但所有轮廓只建立两个等级关系;如果超过两个等级关系的,从顶层开始每两层分解成一个轮廓;
cv.RETR_TREE : 检测所有轮廓,所有轮廓按照真实的情况建立等级关系,层数不限;
method:轮廓处理:
cv.CHAIN_APPROX_NONE :不经过处理
cv.CHAIN_APPROX_SIMPLE:压缩轮廓
cv.CHAIN_APPROX_TC89_L1:用Teh-Chin chain approximation algorithm的一种算法压缩轮廓;
cv.CHAIN_APPROX_TC89_KCOS:用Teh-Chin chain approximation algorithm的另一种算法压缩轮廓;
#画出二值图像轮廓
cv.drawContours( img, contours, contourIdx,color, thickness=1)
函数参数详解:
contours:输入的轮廓组,每一组轮廓由点vector构成,
contourIdx:int 指明画第几个轮廓,如果该参数为负值,则画全部轮廓,
color:轮廓的颜色,
thickness:轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部,
#轮廓面积
area = cv.contourArea(contours[i])
#填充轮廓
cv.fillPoly(img,contours,color)
3.实现:
import cv2 as cvimport matplotlib.pyplot as pltimport numpy as np#解决中文显示问题,固定格式plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=False#1.转化为灰度图pic1=cv.imread("DJI_0023.jpg")#2.高斯滤波去噪pic1 = cv.GaussianBlur(pic1, (5,5), 0) # 高斯滤波gray=cv.cvtColor(pic1,cv.COLOR_BGR2GRAY)#3.OUST算法转换为二值图floatshold,bin = cv.threshold(gray, 0, 255, cv.THRESH_BINARY+cv.THRESH_OTSU) #方法选择为THRESH_OTSU#4.形态学操作,闭运算去除孔洞,链接细小边缘kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (10, 10))bin = cv.morphologyEx(bin, cv.MORPH_CLOSE, kernel)#4.获取轮廓contours, hierarchy=cv.findContours(bin, cv.RETR_TREE,cv.CHAIN_APPROX_NONE)#5.填充轮廓len_contour = len(contours)contour_list = []mask = np.zeros_like(bin, np.uint8) # 纯黑模板for i in range(len_contour): cv.drawContours(mask, contours,i,(255,255, 255), -1)print(mask)#6.彩色图片去除黑色蒙版pic2=cv.bitwise_and(pic1,pic1, mask=mask)#绘制图像fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,10))axes[0,0].set_title("原图")axes[0,0].imshow(pic1[:,:,::-1])axes[0,1].set_title("二值图")axes[0,1].imshow(bin,plt.cm.gray)axes[1,0].set_title("轮廓合并")axes[1,0].imshow(mask,plt.cm.gray)axes[1,1].set_title("彩色图片去除黑色蒙版")axes[1,1].imshow(pic2[:,:,::-1])plt.show()cv.waitKey()
结果:
大津算法有利于海路分割,屏蔽海洋
自适应阈值算法(复杂颜色地物提取例如打鱼船)
1.原理
对分割的小块进行二值化阈值处理,而不考虑整体图像,有利于处理光照不均匀的图像
2.代码API
dst = cv.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
src:要处理的图像数据,为单通道灰度图像;
maxValue:double类型,二值化后的最大值;
adaptiveMethod:动态计算阈值的方法,有以下两种:cv.ADAPTIVE_THRESH_MEAN_C:计算区域内的平均值减去C;
cv.ADAPTIVE_THRESH_GAUSSIAN_C:计算区域内的高斯均值减去C;thresholdType:二值化类型flags,在该函数中仅能使用cv.THRESH_BINARY和cv.THRESH_BINARY_INV两种
blockSize:动态化计算阈值时所使用的区域的大小,类似卷积时的卷积核大小,需要为奇数;
C:计算区域内的均值后减去的常量,最后作为阈值;
3.实现
1.
import cv2 as cvimport matplotlib.pyplot as pltimport numpy as np#解决中文显示问题,固定格式plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=False#1.转化为灰度图pic1=cv.imread("DJI_0023.jpg")#2.高斯滤波去噪pic1 = cv.GaussianBlur(pic1, (5,5), 0) # 高斯滤波gray=cv.cvtColor(pic1,cv.COLOR_BGR2GRAY)#3.adaptiveThreshold转换为二值图bin=cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,11,5)#4.形态学操作,闭运算去除孔洞,链接细小边缘bin2=255-binbin2=cv.medianBlur(bin2,5)#中值去噪bin2=cv.dilate(bin2,np.ones(20,np.uint8))#膨胀#5.获取轮廓contours, hierarchy=cv.findContours(bin2, cv.RETR_TREE,cv.CHAIN_APPROX_NONE)#6.填充轮廓len_contour = len(contours)contour_list = []for i in range(len_contour): area=cv.contourArea(contours[i]) if(area<5000): contour_list.append(contours[i])cv.fillPoly(bin2,contour_list,(255,255,255))#7.腐蚀bin3=cv.erode(bin2,np.ones(20,np.uint8))#腐蚀#8.彩色图片去除黑色蒙版pic2=cv.bitwise_and(pic1,pic1, mask=bin3)#绘制图像fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,10))axes[0,0].set_title("原图")axes[0,0].imshow(pic1[:,:,::-1])axes[0,1].set_title("自适应二值图")axes[0,1].imshow(bin,plt.cm.gray)axes[1,0].set_title("人为进一步处理")axes[1,0].imshow(bin3,plt.cm.gray)axes[1,1].set_title("腐蚀后彩色图片去除黑色蒙版")axes[1,1].imshow(pic2[:,:,::-1])plt.show()cv.waitKey()
第三幅图靠作者的现阶段能力只能处理到这了。。不要嫌弃
噪声影响比较严重,对于复杂颜色的渔船提取较好
可见自适应二值化,对于边缘线提取比较有优势,但也提取了不必要的高亮海面部分
2.
如果扩大填充面积,area<50000,“船只”的提取情况更好一些,但相应不必要高亮海面也提取的更多
import cv2 as cvimport matplotlib.pyplot as pltimport numpy as np#解决中文显示问题,固定格式plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=False#1.转化为灰度图pic1=cv.imread("DJI_0023.jpg")#2.高斯滤波去噪pic1 = cv.GaussianBlur(pic1, (5,5), 0) # 高斯滤波gray=cv.cvtColor(pic1,cv.COLOR_BGR2GRAY)#3.adaptiveThreshold转换为二值图bin=cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,11,5)#4.形态学操作,闭运算去除孔洞,链接细小边缘bin2=255-binbin2=cv.dilate(bin2,np.ones(20,np.uint8))#膨胀#5.获取轮廓contours, hierarchy=cv.findContours(bin2, cv.RETR_TREE,cv.CHAIN_APPROX_NONE)#6.填充轮廓len_contour = len(contours)contour_list = []# mask = np.zeros_like(bin, np.uint8) # 纯黑模板for i in range(len_contour): area=cv.contourArea(contours[i]) if(area<50000): contour_list.append(contours[i])cv.fillPoly(bin2,contour_list,(255,255,255))#7.腐蚀bin3=cv.erode(bin2,np.ones(20,np.uint8))#腐蚀#8.彩色图片去除黑色蒙版pic2=cv.bitwise_and(pic1,pic1, mask=bin3)#绘制图像fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,10))axes[0,0].set_title("原图")axes[0,0].imshow(pic1[:,:,::-1])axes[0,1].set_title("自适应二值图")axes[0,1].imshow(bin,plt.cm.gray)axes[1,0].set_title("人为进一步处理")axes[1,0].imshow(bin3,plt.cm.gray)axes[1,1].set_title("腐蚀后彩色图片去除黑色蒙版")axes[1,1].imshow(pic2[:,:,::-1])plt.show()cv.waitKey()
3.自己调参数改算法步骤吧。累了,陆地提取的一点不好。。。
分水岭算法
import cv2 as cvimport numpy as npimport matplotlib.pyplot as plt# 解决中文显示问题,固定格式,直接复制下面俩行代码就行plt.rcParams['font.sans-serif'] = ['SimHei']plt.rcParams['axes.unicode_minus'] = Falsedef watershed_image(image): """分水岭算法""" # 图像二值化 blurred = cv.pyrMeanShiftFiltering(image, 10, 50) # 均值迁移滤波 gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY) # 转换成灰度图 # cv.imshow("gray", gray) ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU) # 图像二值化 # cv.imshow("binary", binary) # 去除噪声 kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3)) # 构造25×25的方形结构元素 opening = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel=kernel, iterations=2) # 开操作(需要去除图像中的任何白点噪声),迭代次数2 # cv.imshow("noise removal", opening) # 确定背景区域sure_bg sure_bg = cv.dilate(opening, kernel, iterations=3) # 腐蚀,迭代次数3,会去除边界像素 cv.imshow("sure_bg", sure_bg) # 寻找前景区域sure_fg """ />
分水岭算法提取的边框比较规整,但是将顶上一部分水面也提取出来了,还是需要改进