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()
自适应阈值
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()
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()
参考:
https://www.cnblogs.com/gezhuangzhuang/p/10295181.html
https://blog.csdn.net/on2way/article/details/46812121
其中还给出Otsu算法理论推导