OpenCV_Python API 官方文档学习_ cv2 Image Thresholding

官方官方文档

Goal

  • In this tutorial, you will learn Simple thresholding, Adaptive thresholding, Otsu’s thresholding etc.
  • You will learn these functions : cv2.thresholdcv2.adaptiveThreshold etc.

实现目标:

1. 在本章中,将学习简单的阈值,自适应的阈值,Otsu的阈值等等。

2. 学习函数  cv2.thresholdcv2.adaptiveThreshold 


简单阈值

      我们面临的问题非常直接。如果像素值大于阈值,则分配给它一个值(可以是白色的),它也可以分配给另一个值(比如黑色等)。所使用的函数为cv2.threshold()。第一个参数是源图像,应该是灰度图像。第二个参数是阈值,用于对像素值进行分类。第三个参数是maxVal,它表示像素值大于(有时小于)阈值时要给出的值。OpenCV提供了不同类型的阈值,它由函数的第四个参数决定。不同的类型有:

  • cv2.THRESH_BINARY
  • cv2.THRESH_BINARY_INV
  • cv2.THRESH_TRUNC
  • cv2.THRESH_TOZERO
  • cv2.THRESH_TOZERO_INV

文档清楚地解释了每种类型的含义。想详细了解请查看官方文档。该概述会返回两个输出。第一个是retval ,稍后将加以解释。第二个输出是我们的阈值图像。

代码:

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('gradient.png',0)
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)

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

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

plt.show()
      要绘制多个图像,我们使用了plt.subplot()函数。有关更多细节,请查看Matplotlib文档。
结果如下图:

在本教程中,您将学习简单的阈值,自适应的阈值,Otsu的阈值等等。

自适应阈值

       在上面的案例中,我们使用了一个全局值作为阈值。但是,在图像在不同区域有不同照明条件的情况下,这可能并不是很好。在这种情况下,我们采用自适应阈值。在此基础上,算法计算了图像的一个小区域的阈值。因此,对于同一幅图像的不同区域,我们得到了不同的阈值,对于光照不同的图像,我们得到了更好的结果。

      它有三个“special”输入参数和一个输出参数。

①:Adaptive Method   - 它决定如何计算阈值。

  • cv2.ADAPTIVE_THRESH_MEAN_C : 阈值是邻域面积的平均值。
  • cv2.ADAPTIVE_THRESH_GAUSSIAN_C : 阈值是权值为高斯窗口的邻域值的加权和。

②: Block Size:它决定了邻近地区的大小。

③: c : 它只是一个常数,它是从计算的平均值或加权平均数中减去的。

下面的代码比较了全局阈值和自适应阈值在不同光照下的图像。

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('dave.jpg',0)
img = cv2.medianBlur(img,5)

ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
            cv2.THRESH_BINARY,11,2)
th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY,11,2)

titles = ['Original Image', 'Global Thresholding (v = 127)',
            'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]

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

由上图我们可以看出:

经过阈值的设置,阴影被我们处理掉了。而且效果很不错。


Otsu’s 二值化算法

      在第一节中,我告诉你们有一个第二个参数RATVAL。我们使用OTSU的二值化时它的使用。那是什么?下面我会给大家介绍。

      在全局阈值中,我们使用任意值作为阈值,那么,我们怎么知道我们选择的价值是好的还是不好的?答案是,试错法。但是考虑双峰图像(简单地说,双峰图像是直方图有两个峰值的图像)。对于该图像,我们可以近似取这些峰中间的一个值作为阈值,这就是Otsu binarization的所作所为。因此,简单地说,它自动地从图像直方图中计算出双峰图像的阈值。(对于不是双峰的图像,二值化是不准确的。)

      为此,我们使用了 cv2.threshold() 函数,但是通过了额外的flag cv2.THRESH_OTSU。对于阈值,只需传递零。然后算法找到最优阈值并将其作为第二个输出:retVal。如果不使用Otsu阈值,则ReVALL与所使用的阈值相同。

      查看下面的示例。输入图像是一种噪声图像。在第一种情况下,我应用全局阈值为127。在第二种情况下,我直接应用了Otsu的阈值。在第三种情况下,我用5x5高斯核对图像进行滤波以去除噪声,然后进行Otsu阈值处理。看看噪声过滤是如何改善结果的。

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('noisy2.png',0)

# global thresholding
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)

# Otsu's thresholding
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# Otsu's thresholding after Gaussian filtering
blur = cv2.GaussianBlur(img,(5,5),0)
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# plot all the images and their histograms
images = [img, 0, th1,
          img, 0, th2,
          blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
          'Original Noisy Image','Histogram',"Otsu's Thresholding",
          'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]

for i in xrange(3):
    plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
    plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
    plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
    plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()


Otsu是如何工作的?

      下面说的是一些原理性的东西,它的计算过程。演示Otsu的二值化的Python实现,以说明它实际上是如何工作的。如果你不感兴趣,你可以跳过这个。由于我们处理的是双峰图像,Otsu算法试图找到一个阈值(T),该阈值(T)最小化了该关系给出的类内加权方差:


      它实际上找到了一个t的值,它位于两个峰值之间,这两个类的方差都是最小的。它可以简单地在Python中实现,如下所示:

img = cv2.imread('noisy2.png',0)
blur = cv2.GaussianBlur(img,(5,5),0)

# find normalized_histogram, and its cumulative distribution function
hist = cv2.calcHist([blur],[0],None,[256],[0,256])
hist_norm = hist.ravel()/hist.max()
Q = hist_norm.cumsum()

bins = np.arange(256)

fn_min = np.inf
thresh = -1

for i in xrange(1,256):
    p1,p2 = np.hsplit(hist_norm,[i]) # probabilities
    q1,q2 = Q[i],Q[255]-Q[i] # cum sum of classes
    b1,b2 = np.hsplit(bins,[i]) # weights

    # finding means and variances
    m1,m2 = np.sum(p1*b1)/q1, np.sum(p2*b2)/q2
    v1,v2 = np.sum(((b1-m1)**2)*p1)/q1,np.sum(((b2-m2)**2)*p2)/q2

    # calculates the minimization function
    fn = v1*q1 + v2*q2
    if fn < fn_min:
        fn_min = fn
        thresh = i

# find otsu's threshold value with OpenCV function
ret, otsu = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print thresh,ret

注:

      有些函数我们现在可能还没学习,不过后边会逐渐介绍的。


  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值