opencv-python 详解阈值分割

作者:RayChiu_Labloy
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处


目录

先说固定阈值分割函数:cv2.threshold(src, thresh, maxval, type[, dst])

 再说自适应阈值分隔:cv2.adaptiveThreshold() 

 最后分析OTSU算法(又称为大津算法和最大类间方差法)


固定阈值分割很直接,一句话说就是像素点值大于阈值变成一类值,小于阈值变成另一类值。

 “二值化”图像的三种方式:固定阈值、自适应阈值和Otsu阈值法(经验之谈:很多人误以为阈值分割就是二值化,两者并不等同,阈值分割结果是两类值,而不是两个值,所以二值化加了引号。)

先说固定阈值分割函数:cv2.threshold(src, thresh, maxval, type[, dst])

  • src:表示的是图片源
  • thresh:表示的是阈值(起始值)
  • maxval:表示的是最大值(第四个参数type为CV_THRESH_BINARY和CV_THRESH_BINARY_INV是的最大值)
  • type:表示的是这里划分的时候使用的是什么类型的算法,常用值为0(cv2.THRESH_BINARY)

其中第四个参数type有五种类型:

测试一下效果: 

import cv2 as cv
from matplotlib import pyplot as plt

img = cv.imread("21.bmp",0)
ret,thresh1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
ret,thresh2 = cv.threshold(img,127,255,cv.THRESH_BINARY_INV)
ret,thresh3 = cv.threshold(img,127,255,cv.THRESH_TRUNC)
ret,thresh4 = cv.threshold(img,127,255,cv.THRESH_TOZERO)
ret,thresh5 = cv.threshold(img,127,255,cv.THRESH_TOZERO_INV)

titles = ['Original', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

for i in range(6):
    plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

 显示效果:

 再说自适应阈值分隔:cv2.adaptiveThreshold() 

        固定阈值化的缺点就是对暗亮程度不同、明暗分布不均的图片无法做到很好的处理,自适应性二值化,相比于固定阈值的二值化处理,自适应阈值不需要确定一个固定的阈值,而是可以根据对应的自适应方法,通过图像的局部特征自适应的设定阈值,也就是取图片的一小部分计算阈值,做出二值化处理,下面我们分析下自适应阈值分割函数:

        cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C, dst=None)

这个函数大致意思就是把图片每个像素点作为中心取N*N的区域,然后计算这个区域的阈值,来决定这个像素点变0还是变255,参数解释如下:

 

测试图片:

 测试代码:

import cv2
from matplotlib import pyplot as plt

# 自适应阈值对比固定阈值
img = cv2.imread('21.bmp', 0)
# 固定阈值
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# 自适应阈值
th2 = cv2.adaptiveThreshold( img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 4)
th3 = cv2.adaptiveThreshold( img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 17, 6)
titles = ['Original', 'Global(v = 127)', 'Adaptive Mean', 'Adaptive Gaussian']
images = [img, th1, th2, th3]
for i in range(4):
    plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i], fontsize=8)
    plt.xticks([]), plt.yticks([])
plt.show()

 测试效果:

 最后分析OTSU算法(又称为大津算法和最大类间方差法)

        在前面固定阈值中,我们是随便选了一个阈值如127,那如何知道我们选的这个阈值效果好不好呢?答案是:不断尝试,所以这种方法在很多文献中都被称为经验阈值。

        最大类间方差法是1979年由日本学者大津提出的,是一种自适应阈值确定的方法,又叫大津法,简称OTSU,Otsu阈值法会自动计算阈值是一种基于全局的二值化算法,它是根据图像的灰度特性(直方图相关),将图像分为前景和背景两个部分。当取最佳阈值时,两部分之间的差别应该是最大的,在OTSU算法中所采用的衡量差别的标准就是较为常见的最大类间方差,前景和背景尽可能分开。前景和背景之间的类间方差如果越大,就说明构成图像的两个部分之间的差别越大,当部分目标被错分为背景或部分背景被错分为目标,都会导致两部分差别变小,当所取阈值的分割使类间方差最大时就意味着错分概率最小。

         Otsu阈值法非常适用于双峰图片(双峰图片就是指图片的灰度直方图上有两个峰值)。

 测试图片:

测试代码:

import cv2
from matplotlib import pyplot as plt

img = cv2.imread('noisy.jpg', 0)

# 固定阈值法
ret1, th1 = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)

# Otsu阈值法
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# 先进行高斯滤波,再使用Otsu阈值法
blur = cv2.GaussianBlur(img, (5, 5), 0)
ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

images = [img, 0, th1,
          img, 0, th2,
          blur, 0, th3]
titles = ['Original', 'Histogram', 'Global(v=100)',
          'Original', 'Histogram', "Otsu's",
          'Gaussian filtered Image', 'Histogram', "Otsu's"]

for i in range(3):
    # 绘制原图
    plt.subplot(3, 3, i * 3 + 1)
    plt.imshow(images[i * 3], 'gray')
    plt.title(titles[i * 3], fontsize=8)
    plt.xticks([]), plt.yticks([])

    # 绘制直方图plt.hist,ravel函数将数组降成一维
    plt.subplot(3, 3, i * 3 + 2)
    plt.hist(images[i * 3].ravel(), 256)
    plt.title(titles[i * 3 + 1], fontsize=8)
    plt.xticks([]), plt.yticks([])

    # 绘制阈值图
    plt.subplot(3, 3, i * 3 + 3)
    plt.imshow(images[i * 3 + 2], 'gray')
    plt.title(titles[i * 3 + 2], fontsize=8)
    plt.xticks([]), plt.yticks([])
plt.show()

 测试结果:

        可以看到,Otsu 阈值明显优于固定阈值,省去了不断尝试阈值判断效果好坏的过程。其中,绘制直方图时,使用了numpy 中的 ravel() 函数,它会将原矩阵压缩成一维数组,便于画直方图。

Otsu算法详解
Otsu阈值法将整幅图分为前景(目标)和背景,以下是一些符号规定:
$ T $:分割阈值
$ N_0 $:前景像素点数
$ N_1 $:背景像素点数
$ \omega_0 $:前景的像素点数占整幅图像的比例
$ \omega_1 $:背景的像素点数占整幅图像的比例
$ \mu_0 $:前景的平均像素值
$ \mu_1 $:背景的平均像素值
$ \mu $:整幅图的平均像素值
$ rows\times cols $:图像的行数和列数
结合下图会更容易理解一些,有一副大小为4×4的图片,假设阈值T为1,那么:

 其实很好理解,$ N_0+N_1 $就是总的像素点个数,也就是行数乘列数:

 $ \omega_0 $$ \omega_1 $是前/背景所占的比例,也就是:

 整幅图的平均像素值就是:

 此时,我们定义一个前景$ \mu_0 $与背景$ \mu_1 $的方差$ g $

 将前述的1/2/3公式整合在一起,便是:

$ g $ 就是前景与背景两类之间的方差,这个值越大,说明前景和背景的差别也就越大,效果越好。 Otsu 算法便是遍历阈值 T ,使得 $ g $ 最大,所以又称为最大类间方差法。 基本上双峰图片的阈值 T 在两峰之间的谷底。

【如果对您有帮助,交个朋友给个一键三连吧,您的肯定是我博客高质量维护的动力!!!】  

OpenCV中的OTSU阈值分割是一种高效的二值化算法,它可以自动确定最佳的阈值,而不需要手动设置。在OpenCV中,可以使用threshold函数来实现OTSU阈值分割。下面是一个使用OpenCV实现OTSU阈值分割的C++代码示例: ```cpp #include <opencv2/opencv.hpp> using namespace cv; int main() { Mat img = imread("test.png", 0); // 读入灰度图像 Mat binary; double thresh = threshold(img, binary, 0, 255, THRESH_BINARY | THRESH_OTSU); // 自动确定阈值 imshow("Original Image", img); imshow("Binary Image", binary); waitKey(0); return 0; } ``` 在这个示例中,首先使用imread函数读入灰度图像,然后使用threshold函数进行OTSU阈值分割,将分割结果保存在binary中。最后使用imshow函数显示原始图像和二值化图像。通过这种方式,可以自动确定最佳的阈值进行图像二值化处理。\[1\] 如果想要了解更多关于OTSU阈值分割的内容,可以参考这篇文章:https://blog.csdn.net/yuan123890/article/details/107238610。该文章中提供了完整的代码示例,包括灰度化函数和二值化函数的实现。你可以将这些函数加入到主程序中,以实现完整的OTSU阈值分割。\[3\] #### 引用[.reference_title] - *1* [OpenCV阈值分割(五)——OSTU](https://blog.csdn.net/m0_48748418/article/details/130107467)[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^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [opencv学习5——大律二值化(ostu)](https://blog.csdn.net/yuan123890/article/details/107320168)[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^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值