cv2- 图像阈值

图像阈值


图像二值化

图像的二值化,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。

全局阈值

cv2.threshold(img, thresh, maxval, type, dst=None)

当像素值大于阀值时,我们给这个像素赋予一个新值(可能是白色),否则我们给予另外一种颜色(也许是黑色)

  • 简单阈值是一种全局性的阈值,只需要规定一个阈值值,整个图像都和这个阈值比较

img -指原图像,原图像应该是灰度图。
thresh (int) -指用来对像素值进行分类的阈值。
maxval (int) -指当像素值高于(有时是小于)阈值时应该被赋予的新的像素值,当type指定为THRESH_BINARY或THRESH_BINARY_INV时,需要设置该值
type cv2.model -二值化方法>>>有以下几种

cv2.THRESH_BINARY - 二进制阈值(黑白二值化)
cv2.THRESH_BINARY_INV - 反二进制阈值(反黑白二值化)
cv2.THRESH_TRUNC - 截断阈值
cv2.THRESH_TOZERO -
cv2.THRESH_TOZERO_INV -

cv2.model 说明
cv2.THRESH_BINARY 如果 src(x,y)>threshold, dst(x,y) = max_value; 否则,dst(x,y)=0
cv.THRESH_BINARY_INV 如果 src(x,y)>threshold, dst(x,y) = 0; 否则,dst(x,y) = max_value
cv.THRESH_TRUNC 如果 src(x,y)>threshold,dst(x,y) = max_value; 否则dst(x,y) = src(x,y)
cv.THRESH_TOZERO 如果 src(x,y)>threshold,dst(x,y) = src(x,y); 否则 dst(x,y) = 0
cv.THRESH_TOZERO_INV 如果 src(x,y)>threshold,dst(x,y) = 0; 否则dst(x,y) = src(x,y)
import numpy as np
import matplotlib.pylab  as plt

img = cv2.imread('img.jpg',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 range(6):
    plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])

plt.show()
img

自适应阈值

cv2.adaptiveThreshold(img, maxval, thresh_type, type, Block Size, C)

  • 自适应阈值可以看成一种局部性的阈值,通过规定一个区域大小,比较这个点与区域大小里面像素点的平均值(或者其他特征)的大小关系确定这个像素点是属于黑或者白(如果是二值情况)

img -输入灰度图
maxValue -设置最大值
adaptiveMethod -指定的阈值计算方法
thresholdType -跟threshold()方法中一样
blockSize -邻域大小,一般为3,5,7
C -常数,阈值等于平均值或加权平均值减去该常数

thresholdType :
cv2.THRESH_BINARY
cv2.THRESH_BINARY_INV
cv2.THRESH_TRUNC
cv2.THRESH_TOZERO
cv2.THRESH_TOZERO_INV


from cv2 import cv2 as cv

img = cv.imread(r"D:\a\timg.jpg",0)
t1,thd = cv.threshold(img,127,255,cv.THRESH_BINARY)
ath_m = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,5,3)
ath_g = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,5,3)

cv.imshow("img",img)
cv.imshow("thd",thd)
cv.imshow("ath_m",ath_m)
cv.imshow("ath_g",ath_g)
cv.waitKey()
cv.destroyAllWindows()

img

Otsu处理

有时候图像灰度级分布并不均匀,比如所有像素点均分布于127附近且均小于127,此时再以127为阈值进行处理则不再合适
而Otsu方法则会自动遍历所有可能阈值,从而需要找到最合适的阈值。

灰度直方图:将数字图像中的所有像素,按照灰度值的大小,统计其出现的频率。其实就是每个值(0~255)的像素点个数统计。

根据双峰图像的图像直方图自动计算阈值。 (对于非双峰图像,二值化不准确。)

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()

img

参考:

https://www.cnblogs.com/gezhuangzhuang/p/10295181.html

https://blog.csdn.net/on2way/article/details/46812121

其中还给出Otsu算法理论推导

posted @ 2021-12-03 18:36  贝壳里的星海  阅读(308)  评论(1编辑  收藏  举报