python-opencv Tutorials 一码人翻译(12)图像处理— 图像阈值

目标

在本教程中,您将学习

简单的阈值、自适应阈值、Otsu的阈值等。

你将学习这些功能: cv.threshold, cv.adaptiveThreshold 等等。

  • 简单的阈值

   在这里,事情是直截了当的。如果像素值大于阈值,那么它就被赋值一个值(可能是白色),否则它会被赋值另一个值(可能是黑色)。所使用的函数是cv.threshold.。

第一个参数是源图像,它应该是一个灰度图像。

第二个参数是用来对像素值进行分类的阈值。

第三个参数是maxVal,它表示如果像素值大于(有时小于)阈值,则给出的值。

OpenCV提供了不同的阈值模式,它是由函数的第四个参数决定的。不同的类型:

文档清楚地解释了每种类型的含义。请查看文档。

两个输出:

第一个是retval返回值类型说明,稍后将会解释。

第二个输出是我们的阈值图像。

代码:

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

img = cv.imread('park.png',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 Image','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()

分割结果

  • 自适应阈值

在上一节中,我们使用全局值作为阈值。但在不同地区,图像具有不同的光照条件,这可能并不好。在这种情况下,我们选择自适应阈值。在此基础上,该算法计算了图像的一个小区域的阈值。所以我们对同一图像的不同区域有不同的阈值,它给我们提供了更好的结果,对于不同的光照。

它有三个“特殊”输入参数,只有一个输出参数。

Adaptive Method  --自适应方法,决定了阈值的计算值。

cv.ADAPTIVE_THRESH_MEAN_C:阈值是相邻区域的平均值。

cv.ADAPTIVE_THRESH_GAUSSIAN_C。阈值是相邻值的加权总和,权重为高斯窗口。

Block Size——它决定了邻近区域的大小。

C它只是一个常数,从均值或加权平均值中减去。

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

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


img = cv.imread('xiangqi.jpg',0)
img = cv.medianBlur(img,5)

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

titles = ['Original Image', 'Global Thresholding (v = 118)',
            'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
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])
    plt.xticks([]),plt.yticks([])
plt.show()

 

首先进行二值化

在第一部分中,我告诉过您还有第二个参数retVal。当我们去看大津的二化时,它的用处就来了。那么它是什么呢?

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

为此,我们使用了cv.threshold()函数,但是传递了一个额外的标志,cv.THRESH OTSU。对于阈值,只需传递零。然后该算法找到最优阈值,并将其作为第二个输出返回,retVal。如果没有使用Otsu阈值,那么retVal与您使用的阈值相同。

看看下面的例子。输入图像是一个嘈杂的图像。在第一种情况下,我应用了全局阈值,值为127。在第二种情况下,我直接应用了Otsu的阈值。在第三种情况下,我用5x5高斯核过滤了图像,以消除噪声,然后应用Otsu阈值。看看噪声过滤是如何改进结果的。

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

img = cv.imread('xiangqi.jpg',0)

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

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

# Otsu's thresholding after Gaussian filtering
blur = cv.GaussianBlur(img,(5,5),0)
ret3,th3 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.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 range(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()

 

首先进行二值化

在第一部分中,我告诉过您还有第二个参数retVal。当我们去看大津的二化时,它的用处就来了。那么它是什么呢?

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

为此,我们使用了cv.threshold()函数,但是传递了一个额外的标志,cv.THRESH OTSU。对于阈值,只需传递零。然后该算法找到最优阈值,并将其作为第二个输出返回,retVal。如果没有使用Otsu阈值,那么retVal与您使用的阈值相同。

看看下面的例子。输入图像是一个嘈杂的图像。在第一种情况下,我应用了全局阈值,值为127。在第二种情况下,我直接应用了Otsu的阈值。在第三种情况下,我用5x5高斯核过滤了图像,以消除噪声,然后应用Otsu阈值。看看噪声过滤是如何改进结果的。

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

img = cv.imread('xiangqi.jpg',0)
blur = cv.GaussianBlur(img,(5,5),0)

# find normalized_histogram, and its cumulative distribution function
hist = cv.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 range(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 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
print( "{} {}".format(thresh,ret) )
107 106.0

 (其中一些功能可能是新的,但我们将在接下来的章节中介绍它们)

猜你喜欢

转载自blog.csdn.net/qq_41905045/article/details/81333216