灰度直方图: 灰度直方图是一个像素分布函数,基于每个灰度级(0-255)。横轴是灰度级0-255,纵轴是图像中每个灰度级像素点的数量。
灰度直方图特点: 把整个图像浓缩在直方图中,丢失了所有的空间信息;灰度直方图按照x轴进行积分,就是图像的面积。
灰度直方图应用:
(1)设置图像的参数:
(2)分析图像灰度的变化,确定最优二值化的值:因为灰度直方图通常有一个属性,双峰性(bimodal)(一个称为前景峰值,另一个为背景峰值)。通常两个峰值之间的最小值,为我们想找的最优二值化的分界点。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
'''绘制每个通道的像素值的直方图:既每个通道下,每个像素出现的频次'''
def image_hist_demo(image):
''''''
color=('blue','green','red')
for i ,color in enumerate(color):
hist=cv.calcHist(image,[i],None,[256],[0,255])#图像,通道,mask,bins(直方图size)、range[0,256]
plt.plot(hist,color=color)
plt.xlim([0,256])
plt.show()
src=cv.imread(r'D:\Project\Opencv\Learning01\angelababy.jpg')
cv.imshow("origin image",src)
image_hist_demo(src)
cv.waitKey(0)
直方图是图像的统计学特征。直方图举例:像素值直方图,边缘、方向,梯度直方图等等。
直方图有很多应用:均衡化(增强对比度)、有颜色物体跟踪…
图像直方图均值化都是基于灰度图。直方图均值化自动调整图像对比度,使图像清晰,是图像增强的一个手段
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def equalHist_demo(image):
''''''
gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY)#图像转灰度图
dst=cv.equalizeHist(gray)
cv.imshow('equalHist',dst)
src=cv.imread(r'D:\Project\Opencv\Learning01\angelababy.jpg')
cv.imshow("origin image",src)
equalHist_demo(src)
cv.waitKey(0)
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
"""全局均衡化"""
def equalHist_demo(image):
''''''
gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY)#图像转灰度图
dst=cv.equalizeHist(gray)
cv.imshow('equalHist',dst)
"""自适应(局部)均衡化"""
def clahe_demo(image):
''''''
gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY)#图像转灰度图
clahe=cv.createCLAHE(clipLimit=2.0,tileGridSize=(8,8))
dst=clahe.apply(gray)
cv.imshow('clahe lHist',dst)
src=cv.imread(r'D:\Project\Opencv\Learning01\angelababy.jpg')
cv.imshow("origin image",src)
equalHist_demo(src)
clahe_demo(src)
cv.waitKey(0)
(左)原图、(中)全局均衡化、(右)自适应或局部均衡化
上一部分依赖灰度直方图可以理解图像,灰度和像素之间的相关性,进而找到统计学的分布。
二值化: 简单、没有前后关联的、基础、有效的图像分割算法。二值化实际上是通过对灰度直方图的分析,来实现二值化过程。
图像二值化特点:
(1)通常为灰度图的二值化
(2)将图像像素分为两个类别
(3)产生二值图像
二值化分类:
(1)固定阈值二值化(固定阈值,单一阈值或者区间阈值)
固定或全局阈值,只需要一个值就完成整个图像分割。如何选择最优阈值是研究者一直关注的问题,怎么通过数学或模型的方法取得最优二值化的值。
(2)自适应阈值(局部阈值)
应用超过一个阈值;将图像切割多个子图像,对每个子图像求取阈值,将二值化后的图像进行拼接得到最终图像;
求取最优二值化阈值,实际求取灰度直方图双峰的最低点,但并不是所有图像具有双峰性(或不明显)。
最优二值化的问题关键在于怎么找到评价函数,该评价函数既包含前景信息,又包括背景信息。通过评价函数求优——求最大值及最小值,最终获取最优二值化的值。
评价函数经过对全部灰度值进行计算,求最大、最小,最为最优二值化阈值。
算法步骤:
(1)选取初始阈值T0(例,图像灰度值的均值)
(2)使用阈值T0将图像划分为两部分(R1和R2)
(3)在R1、R2中分别求取灰度均值μ1和μ2
(4)整个图像的新的二值化阈值:T1=(μ1+μ2)/2
(5)重复(2)(3)(4)直至前一个T和当前T值相同
OSTU算法思想: 在两个峰值之间找到相关性,进而求取函数最优值,获取两个峰值最低点。
步骤:
(1)类间方差:每个类别的平均值与所有像素的总强度平均值的变化.(把整体前景和背景融合起来)
w0,w1,u0,u1分别代表两个类别的频率、均值
(2)评价函数: 类间方差除以总方差
(3)求取最优二值化值:所有可能的阈值(0-255带入(1)(2)操作)通过上述方式进行评估,最大为最优化二值化阈值。
熵:用来衡量一个物体,或者图像,信息量的多少。
步骤:
(1)假设一个阈值将图像分为前景和背景两个部分,求取前景的熵和背景的熵:
Hb和Hw衡量了,前景和背景的信息量的多少。
(2)将前景的熵和背景的熵进行求和,得到整体熵
(3)求取H最优值,获取最优二值化的值:所有可能的阈值(0-255带入上述(1)(2)操作)通过上述方式进行评估,最大H值为最优化二值化阈值。
原理:在灰度直方图中,找到灰度直方图中,最高峰值的顶点,和其左侧的最小值,在整个直方图中构成三角形,在三角形斜边做垂线,最长的d值为最优的二值化阈值。
ret,binary=cv.threshold()
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
''''''
def threshold_demo():
''''''
target=cv.imread(r'D:\Project\Opencv\Learning01\angelababy.jpg')
"""变为灰度图像"""
gray=cv.cvtColor(target,cv.COLOR_BGR2GRAY)
"""变为二值图像"""
#########方法1:此时cv.THRESH_OTSU计算阈值,0,255作废
ret,binary=cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)#参数:原图像,0,255,二值化方法
cv.imshow('origin', target)
print('yuzhi:',ret)#自动计算的分割阈值
cv.imshow('binary',binary)
# #########方法2,自动全局阈值,此时cv.THRESH_TRIANGLE计算阈值,0,255作废
# ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_TRIANGLE)
# cv.imshow('origin', target)
# print('yuzhi:', ret) # 自动计算的分割阈值
# cv.imshow('binary', binary)
# #########方法3,自动指定阈值,小于127是黑色,大于127是白色
# ret, binary = cv.threshold(gray, 127, 255, cv.THRESH_BINARY )
# cv.imshow('origin', target)
# print('yuzhi:', ret) # 自动计算的分割阈值
# cv.imshow('binary', binary)
# #########方法4.取反.大于127是黑色,小于127是白色
# ret, binary = cv.threshold(gray, 127, 255, cv.THRESH_BINARY_INV)
# cv.imshow('origin', target)
# print('yuzhi:', ret) # 自动计算的分割阈值
# cv.imshow('binary', binary)
# #########方法5.截断阈值,大于127变成127,
# ret, binary = cv.threshold(gray, 127, 255, cv.THRESH_TRUNC)
# cv.imshow('origin', target)
# print('yuzhi:', ret) # 自动计算的分割阈值
# cv.imshow('binary', binary)
# #########方法6.小于127变为0
# ret, binary = cv.threshold(gray, 127, 255, cv.THRESH_TOZERO)
# cv.imshow('origin', target)
# print('yuzhi:', ret) # 自动计算的分割阈值
# cv.imshow('binary', binary)
threshold_demo()
cv.waitKey(10000)
binary=cv.adaptiveThreshold()
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
''''''
def local_threshold():
''''''
target=cv.imread(r'D:\Project\Opencv\Learning01\angelababy.jpg')
"""变为灰度图像"""
gray=cv.cvtColor(target,cv.COLOR_BGR2GRAY)
"""变为二值图像"""
#########自适应阈值
###方法1:cv.ADAPTIVE_THRESH_MEAN_C
dst=cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,25,10)
cv.imshow('target', target)
cv.imshow('binary',dst)
###方法2:cv.ADAPTIVE_THRESH_GAUSSIAN_C
# dst=cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,25,10)
# cv.imshow('target', target)
# cv.imshow('binary',dst)
local_threshold()
cv.waitKey(10000)
ret,binary=cv.threshold()
例使用均值阈值
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
''''''
def custom_threshold():
''''''
target=cv.imread(r'D:\Project\Opencv\Learning01\angelababy.jpg')
"""变为灰度图像"""
gray=cv.cvtColor(target,cv.COLOR_BGR2GRAY)
"""变为二值图像"""
h,w=gray.shape[0:2]
m=np.reshape(gray,[1,w*h])
mean=m.sum()/(w*h)
print('mean',mean)
ret,binary=cv.threshold(gray,mean,255,cv.THRESH_BINARY)
cv.imshow('target',target)
cv.imshow('binary',binary)
custom_threshold()
cv.waitKey(10000)