(六)图像阈值

目录

1、简单阈值

2、自适应阈值

3、Otsu's(大津算法)二值化


目标:

  • 简单阈值、自适应阈值,Otsu's二值化
  • cv2.threshold , cv2.adaptiveThreshold

1、简单阈值

当像素值高于阈值时,给这个像素赋予一个新值,如255(白色),否则赋予另外一个颜色(如黑色)

函数:cv2.threshold() 第一个参数是原图像(必须是灰度图);第二个参数用来对像素值进行分类的阈值;第三个参数是当像素值高于阈值时应该被赋予的新的像素值。OpenCV提供了多种不同的阈值方法,这由第四个参数来决定。这些方法包括:

  • cv2.THRESH_BINARY
  • cv2.THRESH_BINARY_INV
  • cv2.THRESH_TRUNC
  • cv2.THRESH_TOZERO
  • cv2.THRESH_TOZEREO_INV

代码:

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

path="D:\\openCV\\opencv\\sources\\samples\\data\\lena.jpg"
lena=cv.imread(path)

#
gray=cv.cvtColor(lena,cv.COLOR_BGR2GRAY)
ret,thresh1=cv.threshold(gray,127,255,cv.THRESH_BINARY)
ret,thresh2=cv.threshold(gray,127,255,cv.THRESH_BINARY_INV)
ret,thresh3=cv.threshold(gray,127,255,cv.THRESH_TRUNC)
ret,thresh4=cv.threshold(gray,127,255,cv.THRESH_TOZERO)
ret,thresh5=cv.threshold(gray,127,255,cv.THRESH_TOZERO_INV)

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

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

说明:为了在同一个窗口显示多个图像,使用函数plt.subplot()

补充:关于plt.imshow(image,cmaps)

cmap的参数有很多:详情请看这里

我们常用的只有那么几个:binarygray;如果需要更加丰富的色彩可以选择:BluesGreens

 

注意:matloblib里读入的图片是RGB模式,而OpenCV读入图片的模式为BGR模式,这点需要区分开

效果图:

    

2、自适应阈值

简单阈值采用的是全局阈值,整幅图像采用同一个数作为阈值。这种方法不适应所有情况,尤其是当同一幅图像上的不同部分具有不同亮度时,这时需要采用自适应阈值,此时的阈值是根据图像上的每一个小区域计算与其对应的阈值。

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

  • Adaptive Method-指定计算阈值的方法。

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

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

  • Block Size-邻域大小(用来计算阈值的区域的大小)
  • C--一个常数,阈值就等于平均值或者加权平均值减去这个常数

代码:

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

path="D:\\openCV\\opencv\\sources\\samples\\data\\lena.jpg"
lena=cv.imread(path)
#原始图像太大,缩小一些
lena2=cv.resize(lena,None,fx=0.7,fy=0.7,interpolation=cv.INTER_CUBIC)
gray=cv.cvtColor(lena2,cv.COLOR_BGR2GRAY)
cv.imshow("gray",gray)


#中值滤波
img=cv.medianBlur(gray,5)
#阈值分割
ret,th1=cv.threshold(img,127,255,cv.THRESH_BINARY)

#11为Block size,2 为C值
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)

images=[gray,th1,th2,th3]
titles=["Gray","Threshold","Adaptive Thresh MEAN","Adaptive Thresh GAUSSIAN"]

for i in range(4):
   cv.imshow(titles[i],images[i])

 

运行效果:

    

 

3、Otsu's(大津算法)二值化

在使用全局阈值时,我们随便给了一个数来做阈值,那么怎么知道选取的这个数的好坏呢?答案就是不停的尝试。如果是一幅双峰图像呢,岂不是应该在两个峰之间的峰谷选取一个值作为阈值?这就是大津算法二值化要做的。简单来说就是对一幅双峰图像自动根据其直方图计算出一个阈值。(对于非双峰图像,这种方法得到的结果可能会不理想)

用到的函数cv.threshold(),但是需要多传入一个参数(flag):cv2.THRESH_OTSU。这时要把阈值设为0.然会算法会找到最优阈值,这个最优阈值就是retVal。如果不使用Otsu二值化,返回的retVal值与设定的阈值相等。

下面例子中,输入图像是一个带有噪声的图像。第一种方法,设127为全局阈值。第二种方法,直接使用Otsu二值化。第三种方法,先用一个5x5的高斯核取出噪音,然后在使用Otsu二值化

代码:

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

path="D:\\openCV\\opencv\\sources\\samples\\data\\pic2.png"
img=cv.imread(path)
gray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)

#全局阈值
ret,th1=cv.threshold(gray,127,255,cv.THRESH_BINARY)

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

#先进行高斯滤波,(5,5)为高斯核的大小,0为标准差
blur=cv.GaussianBlur(gray,(5,5),0)
ret,th3=cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)


images=[th1,th2,th3]
titles=["Thresholding","Otsu thresholding","Gaussian Otsu thresholding"]

for i in range(3):
    cv.imshow(titles[i],images[i])
cv.imshow("original",gray)
#cv.imshow("gray",gray)
cv.waitKey()

效果图:

    

 

那么如果使用matplotlib输出窗口呢:

代码:

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

path="D:\\openCV\\opencv\\sources\\samples\\data\\pic2.png"
img=cv.imread(path)
gray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)

#全局阈值
ret,th1=cv.threshold(gray,127,255,cv.THRESH_BINARY)

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

#先进行高斯滤波,(5,5)为高斯核的大小,0为标准差
blur=cv.GaussianBlur(gray,(5,5),0)
ret,th3=cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)

images=[gray,0,th1,
        gray,0,th2,
        blur,0,th3]
titles=["original","Histogram","thresholding(v=127)",
        "original","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(),255)
    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()


cv.waitKey()

效果图:

    

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值