目录
- 前言
- 正文
- 原理
- 获取阈值的原理
- 重要函数:cv.threshold
- threshold中type的参数
- 全局阈值
- 效果图
- 函数如下
- 局部阈值
- 效果图
- 图片全部像素的平均值作为阈值
- 效果图
- 方法
- 代码
- 超大图像二值化
- 效果图
- 方法
- 函数
- 代码
- 参考博客
前言
二值图像就是将灰度图转化成黑白图,没有灰,在一个值之前为黑,之后为白有全局和局部两种在使用全局阈值时,我们就是随便给了一个数来做阈值,那我们怎么知道我们选取的这个数的好坏呢?答案就是不停的尝试。如果是一副双峰图像(简 单来说双峰图像是指图像直方图中存在两个峰)呢?我们岂不是应该在两个峰之间的峰谷选一个值作为阈值?这就是 Otsu 二值化要做的,简单来说就是对 一副双峰图像自动根据其直方图计算出一个阈值。(对于非双峰图像,这种方法 得到的结果可能会不理想)。
正文
原理
获取阈值的原理
重要函数:cv.threshold
#这个函数的第一个参数就是原图像,原图像应该是灰度图。
#第二个参数就是用来对像素值进行分类的阈值。
#第三个参数就是当像素值高于(有时是小于)阈值时应该被赋予的新的像素值
#第四个参数来决定阈值方法
threshold中type的参数
比如说我这里解释一个:THRESH_BINARY
。这个函数就是当过门限的值为最大值,其他值为0。其他就可以参照这些进行解释了,具体的效果如何可能还是会依据你不同图像的特征进行效果不同。
全局阈值
效果图
函数如下
def thresold_simple(image):
img = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
ret,thresh1 = cv.threshold(image,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') # 将图像按2x3铺开
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
局部阈值
说明:
在前面的部分我们使用是全局阈值,整幅图像采用同一个数作为阈值。
当时这种方法并不适应与所有情况,尤其是当同一幅图像上的不同部分的具有不同亮度时。
这种情况下我们需要采用自适应阈值。此时的阈值是根据图像上的 每一个小区域计算与其对应的阈值。
因此在同一幅图像上的不同区域采用的是不同的阈值,从而使我们能在亮度不同的情况下得到更好的结果。
这种方法需要我们指定三个参数,返回值只有一个
_MEAN_C:阈值取自相邻区域的平均值,_GAUSSIAN_C:阈值取值相邻区域 的加权和,权重为一个高斯窗口。
Block Size - 邻域大小(用来计算阈值的区域大小)。
C - 这就是是一个常数,阈值就加等于的平均值或者权平均值减去这个常数。
使用的函数为:cv2.adaptiveThreshold()
第一个原始图像
第二个像素值上限
第三个自适应方法Adaptive Method:
— cv2.ADAPTIVE_THRESH_MEAN_C :领域内均值
—cv2.ADAPTIVE_THRESH_GAUSSIAN_C :领域内像素点加权和,权 重为一个高斯窗口
第四个值的赋值方法:只有cv2.THRESH_BINARY 和cv2.THRESH_BINARY_INV
第五个Block size:规定领域大小(一个正方形的领域)
第六个常数C,阈值等于均值或者加权值减去这个常数(为0相当于阈值 就是求得领域内均值或者加权值)
这种方法理论上得到的效果更好,相当于在动态自适应的调整属于自己像素点的阈值,而不是整幅图像都用一个阈值。
效果图
code:
def threshold_demo(image):
img = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
# 中值滤波(基本思想是用像素点邻域灰度值的中值来代替该像素点的灰度值,让周围的像素值接近真实的值从而消除孤立的噪声点。)
img = cv.medianBlur(img, 5)
ret, th1 = cv.threshold(img, 127, 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 Threshold (v = 127)', 'Adaptive Mean Threshold', 'Adaptive Gaussian Threshold']
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()
# 第一个原始图像
# 第二个像素值上限
# 第三个自适应方法Adaptive
# Method:
# — cv2.ADAPTIVE_THRESH_MEAN_C :领域内均值
# —cv2.ADAPTIVE_THRESH_GAUSSIAN_C :领域内像素点加权和,权
# 重为一个高斯窗口
# 第四个值的赋值方法:只有cv2.THRESH_BINARY
# 和cv2.THRESH_BINARY_INV
# 第五个Block
# size: 规定领域大小(一个正方形的领域)
# 第六个常数C,阈值等于均值或者加权值减去这个常数(为0相当于阈值
# 就是求得领域内均值或者加权值)
# 这种方法理论上得到的效果更好,相当于在动态自适应的调整属于自己像素点的阈值,而不是整幅图像都用一个阈值。
图片全部像素的平均值作为阈值
效果图
方法
- 读取函数
- 灰度化
- 重新定义了原张量的阶数,弄成了1行w*h列的一个向量了
- 求出整个灰度图像的平均值
- 求出灰度图像根据该阈值进行的灰度化
代码
def threshold_custome(image):
gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
h,w = gray.shape[:2]#去shape中的前两个通道
m = np.reshape(gray,[1,w*h])#reshape()函数重新定义了原张量的阶数,弄成了1行w*h列的一个向量了。
mean = m.sum()/(w*h)#求出整个灰度图像的平均值
print("mean:",mean)
ret,binary = cv.threshold(gray,mean,255,cv.THRESH_BINARY)
# 这个函数的第一个参数就是原图像,原图像应该是灰度图。
# 第二个参数就是用来对像素值进行分类的阈值。
# 第三个参数就是当像素值高于(有时是小于)阈值时应该被赋予的新的像素值
# 第四个参数来决定阈值方法
cv.imshow("thresold_custome",binary)
超大图像二值化
效果图
方法
- 图像灰度化
- 将图像全部像素点进行循环,一个小块一个小块的走。然后,对这小块进行自适应。再把自适应好的图片小块重新进行赋值。
- 将图片写入固定的位置。
函数
- 自适应阈值化——cv::adaptiveThreshold()
上述的二值化本质上还是全局二值化,重点在于如何获取最佳阈值,这次我们讲解一种局部阈值方式,即opencv集成的自适应二值化。自适应阈值化能够根据图像不同区域亮度分布的,改变阈值。
void cv::adaptiveThreshold(
cv::InputArray src, // 输入图像
double maxValue, // 向上最大值
int adaptiveMethod, // 自适应方法,平均或高斯
int thresholdType // 阈值化类型
int blockSize, // 块大小
double C // 常量
);
cv::adaptiveThreshold()支持两种自适应方法,即cv::ADAPTIVE_THRESH_MEAN_C(平均)和cv::ADAPTIVE_THRESH_GAUSSIAN_C(高斯)。在两种情况下,自适应阈值T(x, y)。通过计算每个像素周围bxb大小像素块的加权均值并减去常量C得到。其中,b由blockSize给出,大小必须为奇数;如果使用平均的方法,则所有像素周围的权值相同;如果使用高斯的方法,则(x,y)周围的像素的权值则根据其到中心点的距离通过高斯方程得到。
代码
# 将大图片拆分成小图片后再用自适应局部阈值比较好
def big_image_demo(image):
print(image.shape)
cw = 200
ch = 200
h, w = image.shape[:2]
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
cv.imshow("big_image_demo_gray", gray)
# 将一张图片每隔ch * cw分成一份
for row in range(0, h, ch):
for col in range(0, w, cw):
roi = gray[row:row+ch, col:col+cw]
dst = cv.adaptiveThreshold(roi, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 127, 2)
gray[row:row + ch, col:col + cw] = dst
print(np.std(dst), np.mean(dst))
cv.imwrite("../images/result_big_image.png", gray)