Python 计算机视觉(十二)—— OpenCV 进行图像分割
参考的一些文章以及论文我都会给大家分享出来 —— 链接就贴在原文,论文我上传到资源中去,大家可以免费下载学习,如果当天资源区找不到论文,那就等等,可能正在审核,审核完后就可以下载了。大家一起学习,一起进步!加油!!
目录
前言
(1)图像分割
(2)读取图像信息
1. 基于阈值的图像分割
(1)基本概念
(2)二值化操作
a. 函数
b. 代码实现
2. 基于边缘检测的图像分割
3. 基于 K-Means 聚类的区域分割
(1)基本概念
(2)代码实现
4. 基于分水岭算法的图像分割
(1)基本概念
(2)代码实现
5.整体代码
结束语
前言
(1)图像分割
图像分割是 AI 领域中一个重要的分支,是机器视觉技术中的关于图像理解的重要一环。近几年兴起的自动驾驶技术中,也需要用到这种技术。车载摄像头探查到图像,后台计算机可以自动将图像分割归类,以避让行人和车辆等障碍。
(2)读取图像信息
无需多言,直接读取图像信息:
"""
Author:XiaoMa
date:2021/11/2
"""
import cv2
import numpy as np
import matplotlib.pyplot as pltimg0 = cv2.imread("E:\From Zhihu\For the desk\cvtwelve3.jpg")
img1 = cv2.resize(img0, dsize = None, fx = 0.5, fy = 0.5)
img2 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
h, w = img1.shape[:2]
print(h, w)
cv2.namedWindow("W0")
cv2.imshow("W0", img2)
cv2.waitKey(delay = 0)
得到图像信息如下:
540 960
1. 基于阈值的图像分割
(1)基本概念
根据图像的整体或部分信息选择阈值,把图像依据灰度级别划分,前面说过的图像二值化就是一种基于阈值的图像分割,当像素点的灰度值高于阈值时将其设置为1,低于阈值时将其设置为0,通过这种方法达到将感兴趣的图像和背景进行分离的操作,所以说如何选取合适的阈值对于这种方法来说比较重要,如果背景和图像亮度区别较大我们可以使用全局阈值分割,但是背景和图像亮度区别不大时得使用局部阈值分割。
(2)二值化操作
a. 函数
ret,dst = cv2.threshold(src,thresh,maxval,type)
res:分割阈值
dst:分割后图像
scr:输入的原图
thresh:分割时的像素分界点值(和阈值等值)
maxval:给大于阈值的像素点安排的灰度值(如定为240,那么大于阈值的点都置为240)
type:阈值的类型,包括四种不同的阈值类型
OpenCV 提供的几种阈值类型:
cv2.THRESH_BINARY #小于阈值的像素点置0,大于阈值的像素点置maxval;
cv2.THRESH_BINARY_INV #小于阈值的像素点置maxval,大于阈值的像素点置0;
cv2.THRESH_TRUNC # 小于阈值的像素点保持原数值,大于阈值的像素点置阈值;
cv2.THRESH_TOZERO # 小于阈值的像素点置0,大于阈值的像素点保持原数值;
cv2.THRESH_TOZERO_INV #小于阈值的像素点保持原数值,大于阈值的像素点置0。
b. 代码实现
本文中将阈值都设置为 127 ,对不同的阈值类型都进行尝试:
将下面的代码复制过去改一下图像的读取路径就可以直接运行了,重要的地方都添加了注释,应该可以看懂。
"""
Author:XiaoMa
date:2021/11/2
"""
import cv2
import numpy as np
import matplotlib.pyplot as pltimg0 = cv2.imread("E:\From Zhihu\For the desk\cvtwelve0.jpg")
img1 = cv2.resize(img0, dsize = None, fx = 0.5, fy = 0.5)
img2 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
h, w = img1.shape[:2]
print(h, w)
cv2.namedWindow("W0")
cv2.imshow("W0", img2)
cv2.waitKey(delay = 0)
#图像进行二值化
##第一种阈值类型
ret0, img3 = cv2.threshold(img2, 127, 255, cv2.THRESH_BINARY)
print(ret0)
##第二种阈值类型
ret1, img4 = cv2.threshold(img2, 127, 255, cv2.THRESH_BINARY_INV)
print(ret1)
##第三种阈值类型
ret2, img5 = cv2.threshold(img2, 127, 255, cv2.THRESH_TRUNC)
print(ret2)
##第四种阈值类型
ret3, img6 = cv2.threshold(img2, 127, 255, cv2.THRESH_TOZERO)
print(ret3)
##第五种阈值类型
ret4, img7 = cv2.threshold(img2, 127, 255, cv2.THRESH_TOZERO)
print(ret4)
#将所有阈值类型得到的图像绘制到同一张图中
plt.rcParams['font.family'] = 'SimHei' #将全局中文字体改为黑体
figure = [img2, img3, img4, img5, img6, img7]
title = ["原图", "第一种阈值类型", "第二种阈值类型", "第三种阈值类型", "第四种阈值类型", "第五种阈值类型"]
for i in range(6):figure[i] = cv2.cvtColor(figure[i], cv2.COLOR_BGR2RGB) #转化图像通道顺序,这一个步骤要记得plt.subplot(3, 2, i+1)plt.imshow(figure[i])plt.title(title[i]) #添加标题
plt.savefig("E:\From Zhihu\For the desk\cvtwelven.jpg") #保存图像,如果不想保存也可删去这一行
plt.show()
2. 基于边缘检测的图像分割
这一部分在我前面的文章种已经介绍过了:Python 计算机视觉(十)—— OpenCV 图像锐化及边缘检测
这里我们就拿其中的一个算子简单试一下:
#边缘检测之Sobel 算子
img8 = cv2.Sobel (img2, cv2.CV_64F, 0, 1, ksize=5)
cv2.namedWindow("W1")
cv2.imshow("W1", img8)
cv2.waitKey(delay = 0)
得到的结果如下:
3. 基于 K-Means 聚类的区域分割
(1)基本概念
此处参考:《K-Means聚类算法研究综述_杨俊闯》
K-Means算法是一种无监督学习,同时也是基于划分的聚类算法,一般用欧式距离(两点间的直线距离)作为衡量数据对象间相似度的指标,相似度与数据对象间的距离成反比,相似度越大,距离越小。算法需要预先指定初始聚类数目k (需要分割的份数)以及 k 个初始聚类中心,根据数据对象与聚类中心之间的相似度,不断更新聚类中心的位置,不断降低类簇的误差平方和(Sum of Squared Error,SSE),当SSE不再变化或目标函数收敛时,聚类结束,得到最终结果。
对于该算法的理解,也可以参考 OpenCV 官网给出的解释:K-means聚类
(2)代码实现
此处参考:OpenCV 官网
#K-means均值聚类
Z = img1.reshape((-1, 3))
Z = np.float32(Z) #转化数据类型
c = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
k = 4 #聚类中心个数,一般来说也代表聚类后的图像中的颜色的种类
ret, label, center = cv2.kmeans(Z, k, None, c, 10, cv2.KMEANS_RANDOM_CENTERS)
center = np.uint8(center)
res = center[label.flatten()]
img9 = res.reshape((img1.shape))
cv2.namedWindow("W2")
cv2.imshow("W2", img9)
cv2.waitKey(delay = 0)
4. 基于分水岭算法的图像分割
(1)基本概念
此处参考:IMAGE SEGMENTATION AND MATHEMATICAL MORPHOLOGY
任何灰度图像都可以视为地形表面,其中高强度表示山峰和丘陵,而低强度表示山谷。你开始用不同颜色的水(标签)填充每个孤立的山谷(局部最小值)。随着水位上升,以附近的山峰(梯度)作为基础,来自不同山谷的水,明显不同颜色的水会开始融合。为了避免这种情况,你可以在水汇合的位置建立障碍。你继续填水和建造屏障,直到所有的山峰都在水下。然后你创建的障碍为你提供了分割结果。这就是分水岭背后的“哲学”。
但如果图像中噪声比较多,那么就会出现很多的“山谷”,这样就分割出太多的区域,所以我们在进行分水岭操作时,一般也会对图像进行一下平滑处理或者形态学操作,来使得图像上的噪声点减少,使得分割效果更加明显。图像平滑和形态学的部分我在前面的文章中提到过:Python 计算机视觉(九)—— OpenCV进行图像平滑
Python 计算机视觉(十一)—— OpenCV 图像形态学处理
(2)代码实现
此处参考:分水岭算法的图像分割(官网)
#分水岭算法
ret1, img10 = cv2.threshold(img2, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)#(图像阈值分割,将背景设为黑色)
cv2.namedWindow("W3")
cv2.imshow("W3", img10)
cv2.waitKey(delay = 0)
##noise removal(去除噪声,使用图像形态学的开操作,先腐蚀后膨胀)
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(img10, cv2.MORPH_OPEN, kernel, iterations = 2)
# sure background area(确定背景图像,使用膨胀操作)
sure_bg = cv2.dilate(opening, kernel, iterations=3)
# Finding sure foreground area(确定前景图像,也就是目标)
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
ret2, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0)
# Finding unknown region(找到未知的区域)
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)
# Marker labelling
ret3, markers = cv2.connectedComponents(sure_fg) #用0标记所有背景像素点
# Add one to all labels so that sure background is not 0, but 1(将背景设为1)
markers = markers+1
##Now, mark the region of unknown with zero(将未知区域设为0)
markers[unknown == 255] = 0
markers = cv2.watershed(img1, markers) #进行分水岭操作
img1[markers == -1] = [0, 0, 255] #边界区域设为-1,颜色设置为红色
cv2.namedWindow("W4")
cv2.imshow("W4", img1)
cv2.waitKey(delay = 0)
效果并不是很理想,建议大家找一些亮度相差较大而且梯度明显但种类不多的图像进行试验操作。
5.整体代码
我将本篇文章中的代码贴在下面,大家可以直接复制进行试验,改一下图像的读取路径就可以使用了:
"""
Author:XiaoMa
date:2021/11/2
"""
import cv2
import numpy as np
import matplotlib.pyplot as pltimg0 = cv2.imread("E:\From Zhihu\For the desk\cvtwelve0.jpg")
img1 = cv2.resize(img0, dsize = None, fx = 0.5, fy = 0.5)
img2 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
h, w = img1.shape[:2]
print(h, w)
cv2.namedWindow("W0")
cv2.imshow("W0", img1)
cv2.waitKey(delay = 0)
#图像进行二值化
##第一种阈值类型
ret0, img3 = cv2.threshold(img2, 127, 255, cv2.THRESH_BINARY)
print(ret0)
##第二种阈值类型
ret1, img4 = cv2.threshold(img2, 127, 255, cv2.THRESH_BINARY_INV)
print(ret1)
##第三种阈值类型
ret2, img5 = cv2.threshold(img2, 127, 255, cv2.THRESH_TRUNC)
print(ret2)
##第四种阈值类型
ret3, img6 = cv2.threshold(img2, 127, 255, cv2.THRESH_TOZERO)
print(ret3)
##第五种阈值类型
ret4, img7 = cv2.threshold(img2, 127, 255, cv2.THRESH_TOZERO)
print(ret4)
#将所有阈值类型得到的图像绘制到同一张图中
plt.rcParams['font.family'] = 'SimHei' #将全局中文字体改为黑体
figure = [img2, img3, img4, img5, img6, img7]
title = ["原图", "第一种阈值类型", "第二种阈值类型", "第三种阈值类型", "第四种阈值类型", "第五种阈值类型"]
for i in range(6):figure[i] = cv2.cvtColor(figure[i], cv2.COLOR_BGR2RGB) #转化图像通道顺序,这一个步骤要记得plt.subplot(3, 2, i+1)plt.imshow(figure[i])plt.title(title[i]) #添加标题
plt.savefig("E:\From Zhihu\For the desk\cvtwelven.jpg") #保存图像,如果不想保存也可删去这一行
plt.show()
#边缘检测之Sobel 算子
img8 = cv2.Sobel(img2, cv2.CV_64F, 0, 1, ksize = 5)
cv2.namedWindow("W1")
cv2.imshow("W1", img8)
cv2.waitKey(delay = 0)
#K-means均值聚类
Z = img1.reshape((-1, 3))
Z = np.float32(Z) #转化数据类型
c = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
k = 4
ret, label, center = cv2.kmeans(Z, k, None, c, 10, cv2.KMEANS_RANDOM_CENTERS)
center = np.uint8(center)
res = center[label.flatten()]
img9 = res.reshape((img1.shape))
cv2.namedWindow("W2")
cv2.imshow("W2", img9)
cv2.waitKey(delay = 0)#分水岭算法
ret1, img10 = cv2.threshold(img2, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)#(图像阈值分割,将背景设为黑色)
cv2.namedWindow("W3")
cv2.imshow("W3", img10)
cv2.waitKey(delay = 0)
##noise removal(去除噪声,使用图像形态学的开操作,先腐蚀后膨胀)
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(img10, cv2.MORPH_OPEN, kernel, iterations = 2)
# sure background area(确定背景图像,使用膨胀操作)
sure_bg = cv2.dilate(opening, kernel, iterations=3)
# Finding sure foreground area(确定前景图像,也就是目标)
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
ret2, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0)
# Finding unknown region(找到未知的区域)
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)
# Marker labelling
ret3, markers = cv2.connectedComponents(sure_fg) #用0标记所有背景像素点
# Add one to all labels so that sure background is not 0, but 1(将背景设为1)
markers = markers+1
##Now, mark the region of unknown with zero(将未知区域设为0)
markers[unknown == 255] = 0
markers = cv2.watershed(img1, markers) #进行分水岭操作
img1[markers == -1] = [0, 0, 255] #边界区域设为-1,颜色设置为红色
cv2.namedWindow("W4")
cv2.imshow("W4", img1)
cv2.waitKey(delay = 0)
结束语
本文介绍了使用 OpenCV 进行图像分割的几种常用手段,包括阈值分割、边缘分割、K均值聚类分割以及分水岭分割。当然还有一些其他的比如均值漂移、基于纹理分割、文本分割、水漫分割等手段并没有在本文中提到,小伙伴们感兴趣可以去进行了解学习。
Python 计算机视觉(十二)—— OpenCV 进行图像分割相关推荐
- 《OpenCv视觉之眼》Python图像处理十二 :Opencv图像轮廓提取之基于一阶导数的Roberts算法、Prewitt算法及Sobel算法
本专栏主要介绍如果通过OpenCv-Python进行图像处理,通过原理理解OpenCv-Python的函数处理原型,在具体情况中,针对不同的图像进行不同等级的.不同方法的处理,以达到对图像进行去噪.锐 ...
- 《OpenCv视觉之眼》Python图像处理十六:Opencv图像处理实战一之图像中的硬币检测
本专栏主要介绍如果通过OpenCv-Python进行图像处理,通过原理理解OpenCv-Python的函数处理原型,在具体情况中,针对不同的图像进行不同等级的.不同方法的处理,以达到对图像进行去噪.锐 ...
- 《OpenCv视觉之眼》Python图像处理十四 :Opencv图像轮廓提取之Scharr算法和Canny算法
本专栏主要介绍如果通过OpenCv-Python进行图像处理,通过原理理解OpenCv-Python的函数处理原型,在具体情况中,针对不同的图像进行不同等级的.不同方法的处理,以达到对图像进行去噪.锐 ...
- 《OpenCv视觉之眼》Python图像处理十九:Opencv图像处理实战四之通过OpenCV进行人脸口罩模型训练并进行口罩检测
本专栏主要介绍如果通过OpenCv-Python进行图像处理,通过原理理解OpenCv-Python的函数处理原型,在具体情况中,针对不同的图像进行不同等级的.不同方法的处理,以达到对图像进行去噪.锐 ...
- Python自动化(十二):一分钟搞定几百个Excel中查找的数据
一.需求说明 首先我们来看下今天的需求,有一份档案记录总表的Excel工作簿, 每天会根据当天日期建立新表,每天的表格内包含所有档案信息,同时也有可能会添加新的档案名.同个年度的总表在年末可能会有两. ...
- 零基础入门学Python(十二)—— 魔法方法(下)
零基础入门学Python系列内容的学习目录→\rightarrow→零基础入门学Python系列内容汇总. 魔法方法(下) 1. 构造和析构 2. 算术运算 3. 简单定制 4. 属性访问 5. 描述 ...
- 零基础入门学Python(十二)—— 魔法方法(上)
零基础入门学Python系列内容的学习目录→\rightarrow→零基础入门学Python系列内容汇总. 魔法方法(上) 1. 构造和析构 1.1 _ _ init _ _(self[, ...]) ...
- 无字天书之Python第十二页(迭代器基础)
博客目录 传送门 迭代器 传送门 无字天书之Python第一页 无字天书之Python第二页 无字天书之Python第三页 无字天书之Python第四页 无字天书之Python第五页 无字天书之Pyt ...
- Python 计算机视觉(二) —— OpenCV 基础
目录 1. 安装配置 2. OpenCV 基础语法 (1)读取图像并显示 (2)调整显示窗口大小 (3)调整图像尺寸大小 (4)图像灰度处理 3. 几何图形绘制 (1)绘制线段 (2)绘制矩形 (3) ...
- Python计算机视觉编程学习笔记 九 图像分割
图像分割 (一)图割(Graph Cut) 1.1 从图像创建图 1.2 用户交互式分割 (二)利用聚类进行分割 (三)变分法 图像分割是将一幅图像分割成有意义区域的过程.区域可以是图像的前景与背景或 ...
最新文章
- oracle 10g安装
- 毕业设计(二十四)---退出 博客 清除session
- `Caused by: java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverter
- UVA 10706 Number Sequence
- bind1st bind2nd的使用
- obs捕获窗口没有窗口_学习工具 | 视频录制软件OBS
- 改善CSS的10种最佳做法,帮助你从样式中获得最大的收益
- Netty工作笔记0045---异步模型原理剖析
- 关于Java的静态初始化块
- 一拖再拖忍无可忍,谷歌披露影响开发人员的 GitHub 高危0day漏洞
- jmeter安装和使用-个人总结
- [转载] python下载安装教程
- php 农历日历,php下实现农历日历的代码_php实例
- 我一直在心酸——有感于512大地震
- Hello JavaEye
- 计算机专业英语prototype,[听单词] 计算机专业英语词汇音频72,计算机英语单词MP3...
- 坦克大战Netty网络联机版项目笔记
- 移动端网页签名,附上DOM,效果图
- 转 Java知识——精华总结
- java.io.FileNotFoundException: .\xiangmu\src\main\webapp\upload....jpg (系统找不到指定的路径。)