(三)OpenCV图像分割python版

0 环境

  • Ubuntu18.04
  • Python3.6
  • OpenCV3.2.0

引入opencv

import cv2

1 基于阈值

1.0 小序

灰度阈值化,简单,速度快,广泛应用于硬件图像处理,如FPGA实时图像处理.

1.2 适用场景

图片中各物体不接触,且物体和背景的灰度值差别较明显,灰度阈值处理效果较好;
waterShed算法

def waterShed(sourceDir):
	# 读取图片
	img = cv2.imread(sourceDir)
	# 原图灰度处理,输出单通道图片
	gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
	# 二值化处理Otsu算法
	reval_O, dst_Otsu = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
	# 二值化处理Triangle算法
	reval_T, dst_Tri = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_TRIANGLE)
	# 滑动窗口尺寸
	kernel = np.ones((3, 3), np.uint8)
	# 形态学处理:开处理,膨胀边缘
	opening = cv2.morphologyEx(dst_Tri, cv2.MORPH_OPEN, kernel, iterations=2)
	# 膨胀处理背景区域
	dilate_bg = cv2.dilate(opening, kernel, iterations=3)
	# 计算开处理图像到邻域非零像素距离
	dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
	# 正则处理
	norm = cv2.normalize(dist_transform, 0, 255, cv2.NORM_MINMAX)
	# 阈值处理距离图像,获取图像前景图
	retval_D, dst_fg = cv2.threshold(dist_transform, 0.5*dist_transform.max(), 255, 0)
	# 前景图格式转换
	dst_fg = np.uint8(dst_fg)
	# 未知区域计算:背景减去前景
	unknown = cv2.subtract(dilate_bg, dst_fg)
	cv2.imshow("Difference value", unknown)
	cv2.imwrite('./images/saved/unknown_reginon.png', unknown)
	# 处理连接区域
	retval_C, marks = cv2.connectedComponents(dst_fg)
	cv2.imshow('Connect marks', marks)
	cv2.imwrite('./images/saved/connect_marks.png', marks)
	# 处理掩模
	marks = marks + 1
	marks[unknown==255] = 0
	cv2.imshow("marks undown", marks)
	# 分水岭算法分割
	marks = cv2.watershed(img, marks)
	# 绘制分割线
	img[marks == -1] = [255, 0, 255]
	cv2.imshow("Watershed", img)
	cv2.imwrite('./images/saved/watershed.png', img)
	cv2.waitKey(0)
sourceDir = "./images/reading/water_coins.jpg"
waterShed(sourceDir)

背景图和前景图.


黑色背景 白色前景

图1.0 黑色部分背景图(左)白色部分前景图(右)

未知区域和分割图.


在这里插入图片描述 分割

图1.2 未知区域(左)分割图(右)

2 基于边缘

边缘检测的结果是点,不能作为图像分割结果,需要进一步处理,将边缘点沿着图形边界连接,形成边缘链.
检测算子:
Sobel,Laplace, Canny
寻找轮廓:
findContours

def cutImage(sourceDir):
	# 读取图片
	img = cv2.imread(sourceDir)
	# 灰度化
	gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
	# 高斯模糊处理:去噪(效果最好)
	blur = cv2.GaussianBlur(gray, (9, 9), 0)
	# Sobel计算XY方向梯度
	gradX = cv2.Sobel(gray, ddepth=cv2.CV_32F, dx=1, dy=0)
	gradY = cv2.Sobel(gray, ddepth=cv2.CV_32F, dx=0, dy=1)
	# 计算梯度差
	gradient = cv2.subtract(gradX, gradY)
	# 绝对值
	gradient = cv2.convertScaleAbs(gradient)
	# 高斯模糊处理:去噪(效果最好)
	blured = cv2.GaussianBlur(gradient, (9, 9), 0)
	# 二值化
	_ , dst = cv2.threshold(blured, 90, 255, cv2.THRESH_BINARY)
	# 滑动窗口
	kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (107, 76))
	# 形态学处理:形态闭处理(腐蚀)
	closed = cv2.morphologyEx(dst, cv2.MORPH_CLOSE, kernel)
	# 腐蚀与膨胀迭代
	closed = cv2.erode(closed, None, iterations=4)
	closed = cv2.dilate(closed, None, iterations=4)
	# 获取轮廓
	_, cnts, _ = cv2.findContours(closed.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
	c = sorted(cnts, key=cv2.contourArea, reverse=True)[0]
	rect = cv2.minAreaRect(c)
	box = np.int0(cv2.boxPoints(rect))
	draw_img = cv2.drawContours(img.copy(), [box], -1, (0, 0, 255), 3)
	cv2.imshow("Box", draw_img)
	cv2.imwrite('./images/saved/monkey.png', draw_img)
	cv2.waitKey(0)
sourceDir = "./images/reading/monkey1.jpg"
cutImage(sourceDir)

原图与结果图.


source Result

图2.1 原图(左)结果图(右)

3 基于区域

grabCut算法

def grab_cut(sourceDir):
	# 读取图片
	img = cv2.imread(sourceDir)
	# 图片宽度
	img_x = img.shape[1]
	# 图片高度
	img_y = img.shape[0]
	# 分割的矩形区域
	rect = (96,1, 359, 358)
	# 背景模式,必须为1行,13x5列
	bgModel = np.zeros((1, 65), np.float64)
	# 前景模式,必须为1行,13x5列
	fgModel = np.zeros((1, 65), np.float64)
	# 图像掩模,取值有0,1,2,3
	mask = np.zeros(img.shape[:2], np.uint8)
	# grabCut处理,GC_INIT_WITH_RECT模式
	cv2.grabCut(img, mask, rect, bgModel, fgModel, 4, cv2.GC_INIT_WITH_RECT)
	# grabCut处理,GC_INIT_WITH_MASK模式
	# cv2.grabCut(img, mask, rect, bgModel, fgModel, 4, cv2.GC_INIT_WITH_MASK)
	# 将背景0,2设成0,其余设成1
	mask2 = np.where((mask==2) | (mask==0), 0, 1).astype('uint8')
	# 重新计算图像着色,对应元素相乘
	img = img*mask2[:, :, np.newaxis]
	cv2.imshow("Result", img)
	cv2.waitKey(0)
sourceDir = "./images/reading/bird2.png"
grab_cut(sourceDir)

原图与结果图


在这里插入图片描述 在这里插入图片描述

图3 原图(左) 结果图(右)

4 问题

grabCut(img, mask, rect, bgModel, fgModel, iterCount, cv2.GC_INIT_WITH_MASK)
OpenCV Error: Assertion failed (!bgdSamples.empty() && !fgdSamples.empty()) in initGMMs, file /build/opencv-L2vuMj/opencv-3.2.0+dfsg/modules/imgproc/src/grabcut.cpp, line 379
cv2.error: /build/opencv-L2vuMj/opencv-3.2.0+dfsg/modules/imgproc/src/grabcut.cpp:379: error: (-215) !bgdSamples.empty() && !fgdSamples.empty() in function initGMMs

grabCut不能使用GC_INIT_WITH_MASK切割图片,我也佷无奈.

5 总结

  • 还在学习阶段,该篇为笔记记录,借鉴较多.

[参考文献]
[1]https://www.cnblogs.com/xinxue/archive/2017/07/08/5350746.html
[2]https://blog.csdn.net/qq_29300341/article/details/79026392
[3]https://blog.csdn.net/sinat_36458870/article/details/78825571


  • 13
    点赞
  • 161
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
通过使用OpenCV库和Python编程语言,可以实现图像分割的任务。下面是一种基于K-means聚类算法的图像分割方法的示例代码: ``` python import cv2 import numpy as np # 读取图像 img = cv2.imread("path_to_image.jpg") # 将图像转换为灰度图 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 使用K-means聚类算法进行图像分割 Z = gray.reshape((-1, 1)) Z = np.float32(Z) criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) k = 2 # 聚类中心个数 ret, label, center = cv2.kmeans(Z, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS) center = np.uint8(center) res = center[label.flatten()] segmented_img = res.reshape((gray.shape)) # 显示分割结果 cv2.imshow("Segmented Image", segmented_img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 上述代码首先读取图像,并将其转换为灰度图像。然后使用K-means聚类算法对灰度图像进行分割,将像素值聚类为k个类别。最后,将分割结果可视化显示出来。 请注意,上述代码只是图像分割中的一种方法,其他图像分割方法也可以使用OpenCV中的不同函数来实现。具体选择哪种方法取决于实际需求和图像特征。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Python 计算机视觉(十二)—— OpenCV 进行图像分割](https://blog.csdn.net/qq_52309640/article/details/120941157)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天然玩家

坚持才能做到极致

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值