opencv学习-阈值分割

把图像分成若干个特定的、具有独特性质的区域,每一个区域代表一个像素的集合,每一个集合代表一个物体,而完成该过程的技术通常称为图像分割。

图像分割方法主要分为:基于阈值的分割方法、基于区域的分割方法、基于边缘的分割方法,以及基于特定理论的分割方法等。
阈值分割实现简单、计算量小、性能稳定。
阈值分割处理又称为图像的二值化处理

文章目录


阈值分割处理主要是根据灰度值信息提取前景,对前景与背景有较强对比度的图像的分割很好。

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,src(r,c)&gt;thresh0,src(r,c)threshdst(r,c)=\begin{cases}maxVal,&amp;src(r,c)&gt;thresh\\ 0,&amp;src(r,c)\leq thresh\end{cases}dst(r,c)={maxVal,0,​src(r,c)>threshsrc(r,c)≤thresh​
当参数type=THRESH_BINARY_INV,与前者相反,采用
dst(r,c)={0,src(r,c)&gt;threshmaxVal,src(r,c)threshdst(r,c)=\begin{cases}0,&amp;src(r,c)&gt;thresh\\ maxVal,&amp;src(r,c)\leq thresh\end{cases}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)
opencv学习-阈值分割

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()

opencv学习-阈值分割

>==< 有点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()

opencv学习-阈值分割
>==< 偏激进

直方图技术法

一幅对比度比较大的直方图中,存在两个峰值,峰值之间的波谷对应于物体边缘附近。
直方图技术就是要找到这两个峰值,然后取两个峰值之间的波谷位置对应的灰度值,就是所要的阈值。

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()

opencv学习-阈值分割
节选
原文:https://blog.csdn.net/qq_40755643/article/details/84066750

上一篇:图像处理之 阈值分割


下一篇:Foreign Exchange UVA - 10763