OpenCV(python)一键入门--十二篇(二值化)
本系列OpenCV博客旨在以最简单的方式分享OpenCV知识,欢迎大家交流和提出指导意见
1:简单的二值化
import cv2 as cv
import numpy as np
src = cv.imread("ma.jpg")
cv.imshow("input", src)
# 转换为灰度图像
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
h, w = gray.shape
t = cv.mean(gray)[0]
#t , std = cv.meanStdDev(gray)
#提示:以上两种方式都可以,都是为了提取均值
#为了方便入门理解,第二行的“std”变量仅用于接收方差,没有其他用途
#区别:
#cv.mean返回一个向量数组,数组里面的值是标量,用【0】获取值
#cv.meanStdDev返回一个矩阵
#可以通过下面的 print语句查看差别
print("t value : ", t)
# 创建一个空图
binary = np.zeros((h, w), dtype=np.uint8)
for row in range(h):
for col in range(w):
pv = gray[row, col]#遍历像素,大于t则赋值255,否则为0
if pv > t:
binary[row, col] = 255
else:
binary[row, col] = 0
cv.imshow("binary", binary)
cv.waitKey(0)
cv.destroyAllWindows()
1)均值这一部分,在本系列博客第二篇:https://bbs.huaweicloud.com/blogs/285391有简单介绍,大致内容放在下图:
当然,除了均值,可以根据自己的需要调整这个 阈值t 的获取方式,根据需要自行调整即可,本案例用均值进行二值化
2)下边的for循环嵌套很好理解了,就是遍历原图像素,大于 阈值t 的像素赋值255,否则为0,。这就是简单的二值化分割。
效果如下:
2:二值化基本阈值操作
import cv2 as cv
import numpy as np
#二值化分割
#下列表示阈值分割方法
#
# THRESH_BINARY = 0 二值分割
# THRESH_BINARY_INV = 1 反向二值分割
# THRESH_TRUNC = 2 截断
# THRESH_TOZERO = 3 取零
# THRESH_TOZERO_INV = 4 反向取零
#
src = cv.imread("ma.jpg")
cv.imshow("input", src)
T = 127#这里直接给定阈值,不再设置别的计算方式
# 转换为灰度图像
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
#for循环输出五种分割方式
for i in range(5):
ret, binary = cv.threshold(gray, T, 255, i)
#返回127.0(得到的阈值) 以及二值化图像
print(f"ret_{i}:{ret}\n")
cv.imshow("binary_" + str(i), binary)
cv.waitKey(0)
cv.destroyAllWindows()
cv.threshold有两个返回值,返回的第一个ret就是得到的阈值值,第二个就是阈值化后的图像。
cv.threshold中,对于BINARY方法,当图像中的灰度值大于127(也就是阈值T),其重置像素值为255.
所以,这里的cv.threshold函数原型为:
cv.threshold(灰度图,阈值,重置像素值,模式)
3:图像二值寻找算法——OTSU
我们前面说到,cv.threshold函数有两个返回值的
前面的代码在阈值的处理上,我们选择的阈值都是127,或者均值计算。那么实际情况下,有的图像可能阈值127不是最好的效果。
那这里我们需要算法自己去寻找到一个阈值,而Otsu’s就可以自己找到一个认为最好的阈值。并且Otsu’s非常适合于图像灰度直方图具有双峰的情况,他会在双峰之间找到一个值作为阈值,对于非双峰图像,可能并不是很好用。
经过Otsu’s得到的那个阈值就是函数cv.threshold的第一个参数。因为Otsu’s方法会产生一个阈值,那么函数cv.threshold的的第二个参数(设置阈值)就是0了,并且在cv.threshold的方法参数中还得加上语句cv.THRESH_OTSU。
双峰图像:就是图像的灰度统计图中可以明显看出只有两个波峰,比如下面一个图的灰度直方图就可以是双峰图:
下列是代码
import cv2 as cv
import numpy as np
#
# THRESH_BINARY = 0
# THRESH_BINARY_INV = 1
# THRESH_TRUNC = 2
# THRESH_TOZERO = 3
# THRESH_TOZERO_INV = 4
# THRESH_MASK = 5 不支持
# THRESH_OTSU = 6 不支持32位
# THRESH_TRIANGLE = 7 不支持32位
src = cv.imread("ma.jpg")
cv.imshow("input", src)
# 自动阈值分割 OTSU
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
# 灰度图,阈值,重置像素值,模式
# OTSU--基于类内最小方差实现阈值寻找
print("ret :", ret)
cv.imshow("binary", binary)
cv.waitKey(0)
cv.destroyAllWindows()
4:图像二值寻找算法——TRIANGLE
前面说到,OTSU对于有两个波峰的直方图效果很好。如果该直方图只有一个波峰,TRIANGLE是个不错的选择
import cv2 as cv
import numpy as np
src = cv.imread("ma.jpg")
cv.imshow("input", src)
# 自动阈值分割 TRIANGLE
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_TRIANGLE)
# 函数原型请参考之前的说明
## 有时候直方图只有一个波峰,就用这种triangle寻找阈值
print("ret :", ret)
cv.imshow("binary", binary)
cv.waitKey(0)
cv.destroyAllWindows()
由于手头没有合适的图像,只能展示如下:
补充:
关于cv.threshold参数:
- 点赞
- 收藏
- 关注作者
评论(0)