美文网首页
opencv图像阈值

opencv图像阈值

作者: Zoe_C | 来源:发表于2018-04-28 10:57 被阅读0次

    1.简单阀值cv2.threshold()

    当像素值高于阀值时,我们给这个像素赋予一个新值(可能是白色),否则我们给它赋予另外一种颜色(也许是黑色)。这个函数就是cv2.threshold()。函数的第一个参数就是原图像,原图像应该是灰度图。第二个参数就是用来对像素值进行分类的阀值,第三个参数就是当像素值高于(有时小于)阀值时,应该被赋予新的像素值。OpenCV提供了多种不同的阀值方法,这是由第四个参数来决定的。方法主要包括:

    cv2.THRESH_BINARY

    cv2.THRESH_BINARY_INV

    cv2.THRESH_TRUNC

    cv2.THRESH_TOZERO

    cv2.THRESH_TOZERO_INV

    img = cv2.imread('NBA.png')

    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 range(6):

        plt.subplot(2,3,i+1)

        plt.imshow(images[i],'gray')

        plt.title(titles[i])

        plt.xticks([])

        plt.yticks([])

    plt.show()

    2.自适应阈值   cv2.adaptiveThreshold()

    在上面,我们使用全局值作为阈值。但是图像在不同区域中具有不同亮度,用一样的阈值处理,结果是不太良好的。在这种情况下,我们进行自适应阈值处理。根据图像上的每一个小区域计算与其对应的阀值。因此在同一幅图像上的不同区域采用的是不同的阀值,从而使我们能在亮度不同的情况下得到更好的结果。

    这种方法需要我们指定三个参数,返回值只有一个。

    Adaptive Method 指定计算阀值的方法

        cv2.ADAPTIVE_THRESH_MEAN_C:阀值取自相邻区域的平均值

        cv2.ADAPTIVE_THRESH_GAUSSIAN_C:阀值取自相邻区域的加权和,权重为一个高斯窗口

    Block Size 邻域大小(用来计算阀值的区域大小)

    C这就是一个常数,阀值就等于的平均值或者加权平均值减去这个常数

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

    img = cv2.medianBlur(img,5)   #中值滤波

    ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)

    # 11为block size,2为C值

    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 range(4):

        plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')

        plt.title(titles[i])

        plt.xticks([]),plt.yticks([])

    plt.show()

    3.Otsu's二值化

    我们前面说到,cv2.threshold函数是有两个返回值的,前面一直用的第二个返回值,也就是阈值处理后的图像,那么第一个返回值(得到图像的阈值)将会在这里用到。

    前面对于阈值的处理上,我们选择的阈值都是127,那么实际情况下,怎么去选择这个127呢?有的图像可能阈值不是127得到的效果更好。那么这里我们需要算法自己去寻找到一个阈值,而Otsu’s就可以自己找到一个认为最好的阈值。并且Otsu’s非常适合于图像灰度直方图具有双峰的情况,他会在双峰之间找到一个值作为阈值,对于非双峰图像,可能并不是很好用。那么经过Otsu’s得到的那个阈值就是函数cv2.threshold的第一个参数了。因为Otsu’s方法会产生一个阈值,那么函数cv2.threshold的的第二个参数(设置阈值)就是0了,并且在cv2.threshold的方法参数中还得加上语句cv2.THRESH_OTSU

    img = cv2.imread('rectangle.jpg',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 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()

    上面演示Otsu二进制化的Python实现,以显示它实际上是如何工作的。如果你不感兴趣,你可以跳过这个。

    由于我们正在处理双峰图像,Otsu的算法试图找到阈值( t ),该阈值最小化由以下关系式给出的加权类内方差:

    它实际上找到位于两个峰值之间的t值,使得两个类别的方差最小。它可以简单地用Python实现,如下所示:

    img = cv2.imread('NBA.jpg',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 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 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

    print(thresh,ret)

    相关文章

      网友评论

          本文标题:opencv图像阈值

          本文链接:https://www.haomeiwen.com/subject/cwgwlftx.html