OpenCV之图像二值化

举报
Y_K_C 发表于 2021/12/20 20:30:21 2021/12/20
【摘要】 声明:本文是OpenCV入门级别的技术分享,主要围绕图像预处理来进行学习,所用语言均为Python。

一、图像的二值化操作

图像二值化操作主要是为了分开图像主体与图像背景,大体的思路是设定一个阈值,将大于阈值或者小于阈值的像素点赋给一个新的像素值,提高图像主体与图像背景的对比度。新像素值的分配称为阈值分割,假设分配的新的像素值为255,则阈值分割的方法如下:
THRESH_BINARY:原像素值大于阈值的像素点设为255,小于阈值的设为0。
THRESH_BINARY_INV:原像素值大于阈值的像素点设为0,小于阈值的设为255。
THRESH_TRUNC:原像素值大于阈值的像素点设为该阈值,小于阈值的像素点保持原像素值。
THRESH_TOZERO:原像素值大于阈值的像素点设为0,小于阈值的像素点保持原像素值。
THRESH_TOZERO_INV:原像素值大于阈值的像素点保持原像素值,小于阈值的像素点设为0。

原图的像素分布:image.png
虚线为阈值,实线为图片的像素值分布。
THRESH_BINARY:image.png
THRESH_BINARY_INV:image.png
THRESH_TRUNC:image.png
THRESH_TOZERO:image.png
THRESH_TOZERO_INV:image.png
具体操作如下:

import cv2 as cv
path = "C:\\Users\\27914\\Desktop\\images\\test2.jpg"
image = cv.imread(path,cv.IMREAD_GRAYSCALE)
cv.imshow("image",image)
ret1,result1 = cv.threshold(image,127,255,cv.THRESH_BINARY)
ret2,result2 = cv.threshold(image,127,255,cv.THRESH_BINARY_INV)
ret3,result3 = cv.threshold(image,127,255,cv.THRESH_TOZERO)
ret4,result4 = cv.threshold(image,127,255,cv.THRESH_TOZERO_INV)
ret5,result5 = cv.threshold(image,127,255,cv.THRESH_TRUNC)
cv.imshow("BINARY",result1)
cv.imshow("BINARY_INV",result2)
cv.imshow("TOZERO",result3)
cv.imshow("TOZERO_INV",result4)
cv.imshow("TRUNC",result5)
cv.waitKey(0)
cv.destroyAllWindows()

OpenCV提供的二值化API为threshold(),
参数解释:
src:输入的图像,此时的图像只能是灰度图;
thresh:阈值;
maxval:小于或大于阈值时被赋予的新值(不一定要255);
type:指阈值分割的方法。
该函数会返回两个值,一个为阈值,一个为转换后的图片矩阵。
输出:
image.png
image.png
image.png
image.png
image.png

二、阈值的获取

通过以上的介绍,不难发现阈值的选取关系到二值化的效果好坏,但是在上面的例子中我把所有的阈值都设置为127,这显然局限性很大。对于不同的图片,不同的阈值分割的方法,其最适阈值往往都不同,而像素点众多,人工选取工作量太大,因此我们需要一个算法帮助我们选取一个最适的阈值,这样的算法主要分为两大类,一是全局阈值和自适应阈值。

1.全局阈值

全局阈值是指通过对整张图片的像素点进行像素值分布的统计,以此为参考选择一个对全局影响最大的阈值进行分割,主要有均值法,三角法和OTSU算法。
均值法:
image.png
m为阈值,p(i,j)为对应位置的像素值。
均值法实现:

import cv2 as cv
import numpy as np
path = "C:\\Users\\27914\\Desktop\\images\\test2.jpg"
image = cv.imread(path,cv.IMREAD_GRAYSCALE)
cv.imshow("image",image)
mean = np.mean(image)
mean = np.int(mean)
ret6,result6 = cv.threshold(image,mean,255,cv.THRESH_BINARY)
cv.waitKey(0)
cv.destroyAllWindows()

输出如下:
image.png
OTSU:
OTSU算法基于前面讨论过的直方图,在获得直方图后,遍历所有的像素值,将一个像素值作为阈值,阈值将图像的像素值分为两类(即背景和图像主体两类),计算类间方差,再将下一个像素值作为阈值,进行下一次循环,遍历完成后将类间方差最大的像素值作为最适阈值。
OTSU实现:

import cv2 as cv
path = "C:\\Users\\27914\\Desktop\\images\\test2.jpg"
image = cv.imread(path,cv.IMREAD_GRAYSCALE)
cv.imshow("image",image)
ret7,result7 = cv.threshold(image,0,255,cv.THRESH_BINARY | cv.THRESH_OTSU)
cv.imshow("OTSU",result7)
cv.waitKey(0)
cv.destroyAllWindows()

输出:
image.png
三角法:
三角法也是基于直方图,是基于纯几何的方法寻找阈值的方法,假设直方图的最大波峰靠近最亮的一侧,波峰的值记为pmax,对应的像素值即为bmax,在往左找到频数为0第一个像素值记为bmin,连接(bmax,pmax)与(bmin,0),得到一条直线,记每一个像素值为bi,从bmin开始计算点(bi,0)到该直线的垂直距离,直到bmax,将垂直距离最大的点对应的像素值作为阈值。
image.png
当图像直方图波峰出现在靠近暗的一侧时,则直方图翻转,依照上述方法计算出一个像素值,在用255减去这个像素值得到的即是阈值。
三角法实现:

import cv2 as cv
path = "C:\\Users\\27914\\Desktop\\images\\test2.jpg"
image = cv.imread(path,cv.IMREAD_GRAYSCALE)
cv.imshow("image",image)
ret8,result8 = cv.threshold(image,0,255,cv.THRESH_BINARY|cv.THRESH_TRIANGLE)
cv.imshow("TRIANGLE",result8)
cv.waitKey(0)
cv.destroyAllWindows()

输出:
image.png

三角法和OTSU两种方法是全局阈值用得最多的方法,但三角法对于处理直方图有多个波峰的图片效果不佳,所以一般使用OTSU方法比较多。

2.自适应阈值

全局阈值存在一定的缺陷,对于图片的光照不均匀的图片,采用全局阈值容易错误分割,如:
原图:
image.png
全局阈值二值化后:
image.png
自适应通过对局部进行最适阈值选取弥补了这个缺点,自适应通过确定一个邻域,计算邻域内像素值的中值或均值或高斯加权平均值(高斯滤波)来确定阈值,再通过卷积过程以邻域为单位计算出每一个邻域的最适阈值,达到对整个图像的二值化的目的。
自适应阈值实现:

import cv2 as cv
path = "C:\\Users\\27914\\Desktop\\images\\test10.jpeg"
image = cv.imread(path,cv.IMREAD_GRAYSCALE)
cv.imshow("image",image)
result9 = cv.adaptiveThreshold(image,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,5,2)#高斯滤波
result10 = cv.adaptiveThreshold(image,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,5,2)#均值
cv.imshow("GAUSS",result9)
cv.imshow("MEAN_C",result10)
cv.waitKey(0)
cv.destroyAllWindows()

高斯滤波适应:
image.png
均值适应:
image.png
OpenCV提供的自适应阈值API为adaptiveThreshold(),
参数解释:
src:输入的图像;
maxValue:赋值的像素值上限;
adaptiveMethod:自适应的方法(仅有均值和高斯滤波两种);
thresholdType:阈值分割的方法;
blockSize:邻域的大小;
C:偏置项,最终阈值等于求出的平均值或高斯加权平均值加上它。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。