把图像分成若干个特定的、具有独特性质的区域,每一个区域代表一个像素的集合,每一个集合代表一个物体,而完成该过程的技术通常称为图像分割。
图像分割方法主要分为:基于阈值的分割方法、基于区域的分割方法、基于边缘的分割方法,以及基于特定理论的分割方法等。
阈值分割实现简单、计算量小、性能稳定。
阈值分割处理又称为图像的二值化处理。
文章目录
阈值分割处理主要是根据灰度值信息提取前景,对前景与背景有较强对比度的图像的分割很好。
1 全局阈值分割
全局阈值分割指的是将灰度值大于thresh(阈值)的像素设为白色,小于或者等于thresh的像素设为黑色,或者反之。
import numpy as np
src = np.array([[123,234,68],[33,51,17],[48,98,234],[129,89,27],[45,167,134]]);
src[src>150]=255;src[src<=150]=0;
API
threshold(src,dst,thresh,maxval,type)
当参数type=THRESH_BINARY,采用
dst(r,c)={maxVal,0,src(r,c)>threshsrc(r,c)≤thresh
当参数type=THRESH_BINARY_INV,与前者相反,采用
dst(r,c)={0,maxVal,src(r,c)>threshsrc(r,c)≤thresh
- 当类型为THRESH_OTSU 或者 THRESH_TRIANGLE时,输入参数src只支持uchar类型。
- 当type=THRESH_OTSU 或 type=THRESH_TRIANGLE(3.x新特性)时,会自动计算阈值。
- 当type=THRESH_OTSU + THRESH_BINARY时,即先用THRESH_OTSU自动计算出阈值,然后利用该阈值采用THRESH_BINARY规则(默认)。
#当(type=THRESH_OTSU & type=THRESH_TRIANGLE(3.x新特性))时,会自动计算阈值。
#当(type=THRESH_OTSU + THRESH_BINARY)时,即先用THRESH_OTSU自动计算出阈值,然后利用该阈值采用THRESH_BINARY规则(默认)。
import cv2
import numpy as np
src = np.array([[123,234,68],
[33,51,17],
[48,98,234],
[129,89,27],
[45,167,134]],np.uint8)
#手动设置阈值
the = 150
maxval = 255
the, dst = cv2.threshold(src, the, maxval, cv2.THRESH_BINARY)
print (the)
print (dst)
#Otsu阈值处理
otsuThe = 0
otsuThe, dst_Otsu = cv2.threshold(src, otsuThe, maxval, cv2.THRESH_OTSU)
print (otsuThe)
print (dst_Otsu)
#TRIANGLE阈值处理
triThe = 0
triThe, dst_tri = cv2.threshold(src, triThe, maxval, cv2.THRESH_TRIANGLE + cv2.THRESH_BINARY_INV)
print (triThe)
print (dst_tri)
OTSU优化
Otsu提出最大方差法
在判别分析最小二乘法原理的基础上推导而来
import cv2
src = cv2.imread(r'C:\Users\h\Desktop\image\lena.jpg', cv2.IMREAD_GRAYSCALE)
otThe = 0
maxval = 255
otThe, dst_tri = cv2.threshold(src, otThe, maxval, cv2.THRESH_OTSU + cv2.THRESH_BINARY)
otThe1, dst_tri1 = cv2.threshold(src, otThe, maxval, cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV)
print (otThe)
print (otThe1)
cv2.imshow("image", src)
cv2.imshow('thresh_out', dst_tri)
cv2.imshow('thresh_out1', dst_tri1)
cv2.waitKey(0)
cv2.destroyAllWindows()
>==< 有点ps的蒙版的意思
TRIANGLE优化
import cv2
#TRIANGLE阈值处理
src = cv2.imread(r'C:\Users\h\Desktop\image\lena.jpg', cv2.IMREAD_GRAYSCALE)
triThe = 0
maxval = 255
triThe, dst_tri = cv2.threshold(src, triThe, maxval, cv2.THRESH_TRIANGLE + cv2.THRESH_BINARY)
triThe1, dst_tri1 = cv2.threshold(src, triThe, maxval, cv2.THRESH_TRIANGLE + cv2.THRESH_BINARY_INV)
print (triThe)
print (triThe1)
cv2.imshow("image", src)
cv2.imshow('thresh_out', dst_tri)
cv2.imshow('thresh_out1', dst_tri1)
cv2.waitKey(0)
cv2.destroyAllWindows()
>==< 偏激进
直方图技术法
一幅对比度比较大的直方图中,存在两个峰值,峰值之间的波谷对应于物体边缘附近。
直方图技术就是要找到这两个峰值,然后取两个峰值之间的波谷位置对应的灰度值,就是所要的阈值。
import cv2
import numpy as np
def caleGrayHist(image):
#灰度图像的高、宽
rows, cols = image.shape
#存储灰度直方图
grayHist = np.zeros([256], np.uint64) #图像的灰度级范围是0~255
for r in range(rows):
for c in range(cols):
grayHist[image[r][c]] += 1
return grayHist
def threshTwoPeaks(image):
#计算灰度直方图
histogram = caleGrayHist(image)
#找到灰度直方图的最大峰值对应得灰度值
maxLoc = np.where(histogram==np.max(histogram))
firstPeak = maxLoc[0][0] #取第一个最大的灰度值
#寻找灰度直方图的第二个峰值对应得灰度值
measureDists = np.zeros([256], np.float32)
for k in range(256):
measureDists[k] = pow(k-firstPeak,2)*histogram[k]
maxLoc2 = np.where(measureDists==np.max(measureDists))
secondPeak = maxLoc2[0][0]
#找到两个峰值之间的最小值对应的灰度值,作为阈值
thresh = 0
if firstPeak > secondPeak: #第一个峰值在第二个峰值右侧
temp = histogram[int(secondPeak):int(firstPeak)]
minLoc = np.where(temp==np.min(temp))
thresh = secondPeak + minLoc[0][0] + 1 #有多个波谷取左侧的波谷
else:
temp = histogram[int(firstPeak):int(secondPeak)]
minLoc = np.where(temp==np.min(temp))
thresh = firstPeak + minLoc[0][0] + 1
#找到阈值后进行阈值处理,得到二值图
threshImage_out = image.copy()
threshImage_out[threshImage_out > thresh] = 255
threshImage_out[threshImage_out <= thresh] = 0
return (thresh, threshImage_out)
#THRESH_TRIANGLE与直方图技术法类似(效果更好)
img = cv2.imread(r'C:\Users\h\Desktop\image\lena.jpg', cv2.IMREAD_GRAYSCALE)
the, dst = threshTwoPeaks(img)
the1 = 0
maxval = 255
the1, dst1 = cv2.threshold(img, the1, maxval, cv2.THRESH_TRIANGLE + cv2.THRESH_BINARY)
print('The thresh is :', the)
print('The thresh1 is :', the1)
cv2.imshow("image", img)
cv2.imshow('thresh_out', dst)
cv2.imshow('thresh_out1', dst1)
cv2.waitKey(0)
cv2.destroyAllWindows()
这和TRIANGLE相似。
2 自适应阈值
在不均匀照明或者灰度值分布不均的情况下,使用全局阈值分割,得到的效果往往会很不理想.
图片进行平滑处理后的输出结果作为每个像素设置阈值的参考值
区域(局部)自适应二值化 计算大概过程是为每一个像素点单独计算的阈值,即每个像素点的阈值都是不同的,就是将该像素点周围B*B区域内的像素加权平均,然后减去一个常数C,从而得到该点的阈值。
针对每个位置的灰度值设置一个对应的阈值,而该位置的阈值的设置和其邻域有必然的关系。
可以使用平滑处理后的输出结果作为每个像素设置阈值的参考值。
一般,平滑算子的宽度必须大于被识别的物体的宽度。
优点:
在于每个像素位置处的二值化阈值不是固定不变的,而是由其周围邻域像素的分布来决定的。
亮度较高的图像区域的二值化阈值通常会较高,而亮度较低的图像区域的二值化阈值则会相适应地变小。
不同亮度、对比度、纹理的局部图像区域将会拥有相对应的局部二值化阈值。
cv2.adaptiveThreshold(src, dst, maxValue, adaptiveMethod, teresholdType, blocksize, C)
src:要二值化的灰度图
dst:二值化后的图
maxValue:一般取255
adaptiveMethod:块计算的方法
ADAPTIVE_THRESH_MEAN_C(均值平滑),为局部邻域块的平均值。该算法是先求出块中的均值,再减去常数C。
ADAPTIVE_THRESH_GAUSSIAN_C(高斯平滑),为局部邻域块的高斯加权和。该算法是在区域中(x,y)周围的像素根据高斯函数按照他们离中心点的距离进行加权计算, 再减去常数C。
teresholdTypt:二值化类型
THRESH_BINARY
THRESH_BINARY_INV
blocksize:平滑算子尺寸为奇数
C:系数
import cv2
img = cv2.imread(r'C:\Users\h\Desktop\image\ti.jpg', cv2.IMREAD_GRAYSCALE)
dst = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 1005, 0.8)
cv2.imshow("image", img)
cv2.imshow('thresh_out', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
节选
原文:https://blog.csdn.net/qq_40755643/article/details/84066750