本章节的主要内容是图像分割,包括以下几点内容:
1、阈值二值化
2、Canny算子
3、Sobel算子
4、Laplace算子
以下代码均在python3.6,opencv4.2.0环境下试了跑一遍,可直接运行。
1、阈值二值化
阈值二值化,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。灰度值0:黑,灰度值255:白。
阈值分割方法的核心在于如何寻找适当的阈值。最常用的阈值方法是基于灰度直方图的方法,如最大类间方差法(OTSU)、最小误差法、最大熵法等,直方图表示图像中具有每种灰度级的像素的个数。直方图方法选择二值化阈值主要是发现图像的两个最高的峰,然后在阈值取值在两个峰之间的峰谷最低处。
1)完整代码如下:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
img_path = "test.jpg"
img=cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# 高斯去燥
gaussianBlur_img = cv2.GaussianBlur(gray, (5, 5), 0)
# 阈值二值化分割
ret, threshold_binary = cv2.threshold(gaussianBlur_img, 155, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
#寻找轮廓
h = cv2.findContours(threshold_binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
# 也可以直接用contours表示
# binary, contours, hierarchy = cv2.findContours(threshold_binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#提取轮廓
contours = h[0]
#打印返回值,这是一个元组
print(type(h))
#打印轮廓类型,这是个列表
print(type(h[1]))
#查看轮廓数量
print (len(contours))
# 在二值图像上画出轮廓:threshold_binary是二值图像,contours是轮廓,-1表示全画,然后是颜色,厚度
cv2.drawContours(img,contours,-1,(0,255,0),3)
cv2.imshow("threshold_binary_image", img)
# 创建白色幕布
temp = np.ones(threshold_binary.shape,np.uint8)*255
# 在白色幕布上画出轮廓:temp是白色幕布,contours是轮廓,-1表示全画,然后是颜色,厚度
cv2.drawContours(temp,contours,-1,(0,255,0),3)
cv2.imshow("temp_threshold_binary_image",temp)
cv2.waitKey(0)
cv2.destroyAllWindows()
2)运行结果如下:
原图上的二值分割结果
白色幕布上的二值分割结果
2、Canny算子
canny边缘检测的基本思想是:首先对图像选择一定的Gauss滤波器进行平滑滤波,然后采用非极值抑制技术进行处理得到最后的边缘图像。Canny算子力图在抗噪声干扰和精确定位之间寻求最佳折中方案。
Canny算子求边缘的具体算法步骤如下:
1. 用高斯滤波器平滑图像.
2. 用一阶偏导有限差分计算梯度幅值和方向.
3. 对梯度幅值进行非极大值抑制.
4. 用双阈值算法检测和连接边缘.
1)完整代码如下:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
img_path = "test.jpg"
img=cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# 高斯去燥
gaussianBlur_img = cv2.GaussianBlur(gray, (5, 5), 0)
# canny检测
cannyImg = cv2.Canny(gaussianBlur_img,50,200)
#寻找轮廓
h = cv2.findContours(cannyImg,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
#提取轮廓
contours = h[0]
#打印返回值,这是一个元组
print(type(h))
#打印轮廓类型,这是个列表
print(type(h[1]))
#查看轮廓数量
print (len(contours))
# 在二值图像上画出轮廓:threshold_binary是二值图像,contours是轮廓,-1表示全画,然后是颜色,厚度
cv2.drawContours(img,contours,-1,(0,255,0),3)
cv2.imshow("cannyImg_image", img)
# 创建白色幕布
temp = np.ones(cannyImg.shape,np.uint8)*255
# 在白色幕布上画出轮廓:temp是白色幕布,contours是轮廓,-1表示全画,然后是颜色,厚度
cv2.drawContours(temp,contours,-1,(0,255,0),3)
cv2.imshow("temp_cannyImg_image",temp)
cv2.waitKey(0)
cv2.destroyAllWindows()
2)运行结果如下:
原图上的canny分割结果
白色幕布上的canny分割结果
3、Sobel算子
Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。
1)完整代码如下:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
img_path = "test.jpg"
img=cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# Sobel检测:普通一阶差分,基于寻找梯度强度,边缘提取
# ddepth =-1/CV_16S/CV_32F/CV_64F
# sobel 水平方向边缘检测
x = cv2.Sobel(gray,cv2.CV_16S,1,0,ksize=3)
# 将像素点进行绝对值计算
sobelx_img = cv2.convertScaleAbs(x)
# sobel 竖直方向边缘检测
y = cv2.Sobel(gray,cv2.CV_16S,0,1,ksize=3)
# 将像素点进行绝对值计算
sobely_img = cv2.convertScaleAbs(y)
# sobel边缘检测,两个方向图像加权混合,融合,addWeighted()也可以设置图片的透明度
sobelxy_img = cv2.addWeighted(sobelx_img, 0.5, sobely_img, 0.5, 0)
# sobel边缘检测,两个方向同时进行检测
sobel_edges = cv2.Sobel(img,cv2.CV_16S,1,1,ksize=3)
# 将像素点进行绝对值计算
sobel_img = cv2.convertScaleAbs(sobel_edges)
cv2.imshow("sobelx_img", sobelx_img)
cv2.imshow("sobely_img", sobely_img)
cv2.imshow("sobelxy_img", sobelxy_img)
cv2.imshow("sobel_img", sobel_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
2)运行结果如下:
sobel 水平方向检测结果
sobel 竖直方向检测结果
sobel 水平竖直两个方向加权混合检测结果
sobel 水平竖直同时检测结果
4、Laplace算子
laplace算子是最简单的各向同性微分算子,它具有旋转不变性。一个二维图像函数的拉普拉斯变换是各向同性的二阶导数。在一阶导数的极值位置,二阶导数为0。可以用这个特点来作为检测图像边缘的方法。但是, 二阶导数的0值不仅仅出现在边缘,也可能出现在无意义的位置,可以过滤掉这些点。
1)完整代码如下:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
img_path = "test.jpg"
img=cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# Laplace检测:无高斯滤波
laplace_img = cv2.Laplacian(gray, cv2.CV_16S, ksize = 3)
# 将像素点进行绝对值计算
laplace_img = cv2.convertScaleAbs(laplace_img)
cv2.imshow("laplace_image", laplace_img)
# Laplace检测:有高斯滤波
# 高斯去燥
gaussianBlur_img = cv2.GaussianBlur(gray, (5, 5), 0)
# 拉普拉斯检测
laplace_img = cv2.Laplacian(gray, cv2.CV_16S, ksize = 3)
# 将像素点进行绝对值计算
gauss_laplace_img = cv2.convertScaleAbs(laplace_img)
cv2.imshow("gauss_laplace_image", gauss_laplace_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
2)运行结果如下:
无高斯去燥的Laplace算子分割结果
有高斯去燥的Laplace算子分割结果
有无高斯去燥对Laplace算子的分割结果没有影响。
以上内容如有错误或者需要补充的,请留言!