[图像处理]14.分割算法比较 OTSU算法+自适应阈值算法+分水岭

article/2025/9/16 3:34:44

参考文献:

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<cv::Point> >来存储;

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 cv
import matplotlib.pyplot as plt
import 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 cv
import matplotlib.pyplot as plt
import 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-bin
bin2=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 cv
import matplotlib.pyplot as plt
import 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-bin
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 = []
# 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 cv
import numpy as np
import 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_bgsure_bg = cv.dilate(opening, kernel, iterations=3)  # 腐蚀,迭代次数3,会去除边界像素cv.imshow("sure_bg", sure_bg)# 寻找前景区域sure_fg""" 距离变换的基本含义是计算一个图像中非零像素点到最近的零像素点的距离,也就是到零像素点的最短距离一个最常见的距离变换算法就是通过连续的腐蚀操作来实现,腐蚀操作的停止条件是所有前景像素都被完全腐蚀。这样根据腐蚀的先后顺序,我们就得到各个前景像素点到前景中心像素点的距离。根据各个像素点的距离值,设置为不同的灰度值。这样就完成了二值图像的距离变换。cv2.distanceTransform(src, distanceType, maskSize)distanceType为距离类型CV_DIST_L1, CV_DIST_L2 , CV_DIST_C;maskSize为距离转换掩码的大小"""dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5)  # 距离变换dist_output = cv.normalize(dist_transform, 0, 1.0, cv.NORM_MINMAX)  # 矩阵归一化,主要是为了显示出dist_outputcv.imshow("dist_transform", dist_output * 50)  # dist_output不乘50看不出来ret, sure_fg = cv.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)  # 图像二值化cv.imshow("sure_fg", sure_fg)# 找到未知的区域unknownsure_fg = np.uint8(sure_fg)unknown = cv.subtract(sure_bg, sure_fg)  # 从sure_bg区域中减去sure_fg区域来获得unknowncv.imshow("unknown", unknown)# 类别标记ret, markers1 = cv.connectedComponents(sure_fg)print(ret)  # 计算数量,但此时会把图像边框也算进去,因此ret会多1# print(markers1)# 为所有的标记加1,保证背景是0而不是1markers = markers1 + 1# print(markers)# 现在让所有的未知区域为0markers[unknown == 255] = 0# 使用分水岭算法markers3 = cv.watershed(image, markers=markers)  # 边界区域将被修改标记为-1image[markers3 == -1] = [0, 0,255]  # 边界区域画红色#创建黑色蒙版mask=np.zeros_like(image,np.uint8)mask[markers3 == -1]=(255,255,255)mask=cv.dilate(mask,np.ones(20,np.uint8))# print(markers3)fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 10))axes[0, 0].set_title("边框")axes[0, 0].imshow(mask, plt.cm.gray)axes[0, 1].set_title("原图")axes[0, 1].imshow(image[:,:,::-1])axes[1, 0].set_title("sure_fg")axes[1, 0].imshow(sure_fg, plt.cm.gray)axes[1, 1].set_title("sure_bg")axes[1, 1].imshow(sure_bg, plt.cm.gray)plt.show()cv.waitKey()
if __name__=="__main__":image=cv.imread("DJI_0023.JPG")watershed_image(image)

 分水岭算法提取的边框比较规整,但是将顶上一部分水面也提取出来了,还是需要改进


http://chatgpt.dhexx.cn/article/BWXehnMi.shtml

相关文章

OTSU算法 (大津算法)理解代码

OTSU算法&#xff1a;对图像进行二值化的算法 介绍 OTSU算法是一种自适应的阈值确定的方法&#xff0c;又称大津阈值分割法&#xff0c;是最小二乘法意义下的最优分割。 它是按图像的灰度特性&#xff0c;将图像分成背景和前景两部分。因方差是灰度分布均匀性的一种度量,背景…

Pr-快速上手-基本操作-教程

视频链接: Pr教程 视频设计到的知识点: 视频的剪辑bgm的管理添加字幕及弹幕的添加鬼畜视频的制作发布教程

Pr常用操作技巧

操作技巧持续更新中 1.premiere如何裁剪视频尺寸 视频尺寸怎么修改 1.将premiere左下角的视频素材直接向右拖动到编辑区中 2.鼠标左键单击视频,然后选择上方的【效果】 3.这时,页面左侧将弹出效果的菜单栏,依次选择效果→视频效果→变换→裁剪 4.鼠标左键按住【裁剪】不放,直接…

Premiere: 基本操作

1、首先进入编辑模式&#xff0c;使得视频能加效果 2、这时候能找到视频的效果添加&#xff0c;这里有视频的水平翻转&#xff0c;高斯模糊等&#xff0c;需要什么效果直接&#xff0c;把该效果抓到视频上就可以。

PR的入门基础教程

提示&#xff1a;这里只记述作者学习PR入门基础教程视频后的总结 文章目录 常用视频概念第1天学习总结第2天学习总结第3天学习总结 常用视频概念 第1天学习总结 第2天学习总结 第3天学习总结

Adobe Premiere Pro快速入门教程

简介&#xff1a; 适用于纯新手零基础&#xff0c;看完本教程即可完成常用视频编辑技巧。 采用Adobe Premiere Pro 2020版本 windows10操作系统 一、制作 照片音频字幕的视频 目标&#xff1a;把三张图片和一个音乐做成带字幕的视频。&#xff08;素材请自行准备&#xff0…

使用pr的8大技巧

许多小伙伴是通过pr这个软件进行素材剪辑的&#xff0c;当我们面对许多素材需要剪辑的时候&#xff0c;往往被这些素材弄得头昏脑涨&#xff0c;剪辑拼接的费时费力&#xff0c;最后出来的成品效果也不太好&#xff0c;下面就告诉大家一些pr使用的技巧&#xff0c;来提升我们的…

Premiere 零基础快速上手教程

关注并星标“高级农民工” 回复“视频”可获取视频剪辑软件和教程 在前几天的文章中&#xff0c;我分享了几款主流视频剪辑软件&#xff1a; 最主流的视频剪辑软件 简单来说就是&#xff0c;手机端用「剪映」这一款 app 就够&#xff0c;当你熟练到发现手机剪视频不方便&#x…

pr基础学习笔记

pr基础学习笔记&#xff08;正题&#xff09; 推荐几个小技巧 1.快速插入 2.快速移动小片段 2. 另&#xff1a;移动Ctrl是多轨移动移动CtrlAlt是单轨移动3.如何去除两个片段之间的空档&#xff1f; 4.两种选择工具的比较 附&#xff1a; pr快捷键 应用程序 选择工具…

pr基础入门

一、快速认识 PR 主界面并导入素材 修改 名称、位置&#xff0c;其他不用变&#xff0c;点击确定 进入界面如下&#xff1a; 认识、添加必要 窗口 导入素材方法 1.直接将文件拖入pr中 2.导入媒体以开始&#xff0c;部分右键创建 素材箱 进入素材箱&#xff0c;右键选择导入&a…

PR(基础剪辑)

一.剪辑步骤&#xff1a; 1.先粗剪后精剪&#xff1a; 粗剪&#xff1a; 精剪&#xff1a; 二. 常用键&#xff1a; 1. i&#xff1a;设置素材的起点 o&#xff1a;设置素材的终点 &#xff08;在预览素材时&#xff09; 2.快速浏览素材&#xff1a; l&#xff1a;按一次常速…

Pr 入门系列之十:基本图形

在 Pr 中&#xff0c;文字&#xff08;包括字幕&#xff09;以及形状等被归类为图形 Graphics。 一个图形剪辑里可包含多个文本图层、形状图层以及其它媒体文件等图形元素。 提示&#xff1a; 1、图形剪辑不会出现在项目面板中&#xff0c;除非升级为源图。 2、与 Ps 一样&…

PR(Adobe Premiere Pro)软件基础知识

一、基础参数设置 时长 时长为视频时间的长度。基本单位为秒。但是在PR软件中&#xff0c;有更为精准的时间单位计算为帧&#xff0c;也就是把1秒分为若干份&#xff0c;一份就是一帧&#xff0c;一帧也就可以理解为一张图片。所以在PR软件中视频显示的时间长度表述为 时&…

Premiere基础操作

一&#xff1a;设置缓存 二&#xff1a;ctrI导入素材 三&#xff1a;导入图像序列 四&#xff1a;打开吸附。 打开吸附后素材会对齐。 五&#xff1a;按~键可以全屏窗口。 六&#xff1a;向前选择轨道工具。 在时间线上点击&#xff0c;向前选中时间线上素材。向后选择轨道工具…

pr剪视频基本操作

1 打开pr 2 导入设置 1&#xff09;双击左下角“项目”窗口&#xff0c;导入准备好的视频 2&#xff09;建立一个序列 点击文件 -> 新建 -> 序列 设置自定义序列 3 修建编辑 1&#xff09;双击视频素材&#xff0c;在预览框&#xff08;源&#xff09;中可以点击播放或…

【PR】零基础快速入门教程

【PR】零基础快速入门教程 PR&#xff08;Premiere&#xff09;能做什么&#xff1f;PR欢迎界面及新建项目工作区及窗口说明导入文件建立序列视频剪辑添加字幕导出视频 使用软件&#xff1a;Premiere2020 新年卷起来&#xff0c;写文章已近不能满足与我了&#xff0c;我要向着更…

PR基础知识

什么是帧&#xff0c;什么叫帧速率&#xff0c;什么叫方形像素&#xff0c;什么叫场序…… 1、时长 时长为视频时间的长度&#xff0c;基本单位为秒。但是在PR软件中&#xff0c;有更为精准的时间单位计算为帧&#xff0c;也就是把1秒分为若干份&#xff0c;一份就是一帧&…

Pr的5种基本操作

说明&#xff1a;本文基于软件Adobe Premiere Pro cc 2018&#xff0c;请自行到网上下载 首先&#xff0c;基本界面如下图所示&#xff1a; 以下解决几个问题&#xff1a;如何简单的载入舞台、创建序列、添加标题、调整音频层级以及导出视频&#xff1f; 1. 载入舞台 如何…

pr 基本操作

视频效果&#xff1a; 高斯模糊&#xff1a;镜头扭曲&#xff1a;色调&#xff1a;亮度对比度&#xff1a; 视频过度&#xff1a; 溶解&#xff1a; 1、文件夹直接拖、 项目面板双击&#xff0c;导入单个或者多个&#xff0c;或者文件夹&#xff1b;项目左下角&#xff0c;…

绘制流程图的基本规则

流程图可以简单地描述一个过程&#xff0c;是对过程、算法、流程的一种图像表示&#xff0c;在技术设计、交流及商业简报等领域有广泛的应用。流程图可分为&#xff1a;数据流程图和作业流程图。 1、程序流程图的作用 程序流程图的作用程序流程图的作用程序流程图的作用 程序流…