基础版笔记链接:
python3+opencv学习笔记汇总目录(适合基础入门学习)
基础版二值化讲解
opencv学习笔记10:阈值分割
二值化方法:全局阈值,局部阈值
具体原理见上面链接
1.全局阈值
通常情况,我们一般不知道设定怎样的阈值thresh才能得到比较好的二值化效果,只能去试。如对于一幅双峰图像(理解为图像直方图中存在两个峰),我们指定的阈值应尽量在两个峰之间的峰谷。这时,就可以用第四个参数THRESH_OTSU,它对一幅双峰图像自动根据其直方图计算出合适的阈值(对于非双峰图,这种方法得到的结果可能不理想)。
对于双峰图,我们需要多传入一个参数cv2.THRESH_OTSU,并且把阈值thresh设为0,设置为其他数也默认为0,算法会找到最优阈值,并作为第一个返回值ret返回。
cv2.THRESH_BINARY:二进制阈值。把亮的处理成白色,暗的处理成黑色
cv2.THRESH_BINARY_INV:反二进制阈值。把亮的处理成黑色,暗的处理成白色
cv2.THRESH_TRUNC:截断阈值。亮的不能太亮,有上限,暗的不变
cv2.THRESH_TOZERO_INV:threshold 反阈值化为0,把比较亮的部分处理成0成黑色,小于等于阈值的像素点不变
cv2.THRESH_TOZERO:threshold 阈值化为0,比较亮的部分不变,比较暗的部分处理成黑色为0
import cv2 as cv
import numpy as np
def threshold_demo(image):
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 127, 255, cv.THRESH_BINARY|cv.THRESH_OTSU)
print("threshold value %s"%ret)
cv.imshow("binary", binary)
print("--------- Python OpenCV Tutorial ---------")
src = cv.imread("duoren.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
threshold_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()
修改cv.THRESH_BINARY为其他参数。结果如下
cv2.THRESH_BINARY_INV:反二进制阈值
cv2.THRESH_TRUNC:截断阈值
cv2.THRESH_TOZERO_INV: 反阈值化为0
cv2.THRESH_TOZERO:阈值化为0
2.局部阈值 自适应阈值
cv2.adaptiveThreshold()
ADAPTIVE_THRESH_MEAN_C :把图像分成一个个小的区域,每个区域做阈值处理,每个区域阈值为这个区域的均值减去常量c,大于阈值取白色,小于取黑色。整个图像有很多阈值。
ADAPTIVE_THRESH_GAUSSIAN_C:把图像分成一个个小的区域,阈值是每个区域均值的权重和(均值分布为高斯分布,越接近中心均值权重越高)再减去常量c,整个图像只有一个阈值
blocksize:区域大小,必须是奇数。
C: 二值化时,如何一个像素点减去均值大于C,才把这个点设为白色,能减弱噪声影响。等于说阈值=均值-C
import cv2 as cv
import numpy as np
def local_threshold(image):
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
binary = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 25, 10)
cv.imshow("binary", binary)
print("--------- Python OpenCV Tutorial ---------")
src = cv.imread("duoren.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
local_threshold(src)
cv.waitKey(0)
cv.destroyAllWindows()
换一张经典图
自适应阈值结果
全局阈值结果
首先还是自适应阈值吧。
3.自定义阈值
自己实现一个二值化处理
import cv2 as cv
import numpy as np
def custom_threshold(image):
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)#转换为灰度图
h, w = gray.shape[:2]#高宽
m = np.reshape(gray, [1, w*h])#将图像转换为1维数组,1行多列
mean = m.sum() / (w*h)#求均值,把均值作为阈值
print("mean : ", mean)
ret, binary = cv.threshold(gray, mean, 255, cv.THRESH_BINARY)
cv.imshow("binary", binary)
print("--------- Python OpenCV Tutorial ---------")
src = cv.imread("duoren.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
custom_threshold(src)
cv.waitKey(0)
cv.destroyAllWindows()
方法:图像分块,再分别阈值
图超大时,由于光照不能很好分布全图,所以有很多噪声。
import cv2 as cv
import numpy as np
def big_image_binary(image):
print(image.shape)#(1200, 1920, 3)
cw = 256#每个小块宽
ch = 256#每个小块高
h, w = image.shape[:2]#整个图像高,宽
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)#转灰度图
for row in range(0, h, ch):#遍历每一小块高
for col in range(0, w, cw):#遍历每一块宽
roi = gray[row:row+ch, col:cw+col]#小块区域
#print(np.std(roi), np.mean(roi))#打印小块方差,均值
dev = np.std(roi)
if dev < 15:
gray[row:row + ch, col:cw + col] = 255#去除空白区域的噪点
else:
#全局阈值
ret, dst = cv.threshold(roi, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)#cv.THRESH_OTSU自动寻找阈值
#自适应阈值
#dst = cv.adaptiveThreshold(roi, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 25, 10)
gray[row:row + ch, col:cw + col] = dst#在原图上替换小块二值化结果
#cv.imwrite("result_binary.png", gray)
cv.imshow('result_binary',gray)
print("--------- Python OpenCV Tutorial ---------")
src = cv.imread("limi.jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
big_image_binary(src)
cv.waitKey(0)
cv.destroyAllWindows()
说明
下面代码是去除图像空白小块区域噪声。如果一个小块没有其他东西,那么它的方差就很小,去除一些小黑点(去噪)
if dev < 15:
gray[row:row + ch, col:cw + col] = 255#去除空白区域的噪点
电气专业的计算机萌新,写博文不容易。如果你觉得本文对你有用,请点个赞支持下。谢谢。