彩色图像的直方图处理是一种重要的图像处理技术,用于改善图像的视觉效果,增强图像的对比度,或为后续的图像处理任务(如图像分割、特征提取)做准备。彩色图像通常由红色(R)、绿色(G)、蓝色(B)三个颜色通道组成,因此彩色图像的直方图处理相比单色图像更为复杂。
直方图的构建:
首先,对于彩色图像的每个颜色通道(R、G、B),分别计算其直方图。直方图是一个图表,显示了每个像素强度值(通常是0-255)在图像中出现的频率。
对于每个通道,直方图将有256个可能的强度值(或“桶”),每个桶的高度表示该强度值在相应通道中出现的次数。
直方图均衡化:
直方图均衡化是一种常见的彩色图像直方图处理方法,目的是增强图像的全局对比度。
在这个过程中,对每个颜色通道的直方图进行变换,使得最终的输出图像的直方图具有大致均匀的分布。这意味着在调整后的图像中,每个强度值的像素大致相同。
这种方法特别适用于图像的背景和前景都很暗或者都很亮的情况。
直方图规定化(匹配):
直方图规定化是另一种方法,它涉及修改一个图像的直方图以匹配另一个特定图像的直方图。
这通常用于标准化不同图像的光照条件,或者在特定应用中使图像风格一致。
局部直方图处理:
除了对整个图像进行直方图处理,还可以对图像的局部区域进行处理,以增强局部对比度或特定区域的细节。
颜色空间转换:
在进行直方图处理之前,有时会将图像从RGB颜色空间转换到其他颜色空间,如HSV(色相、饱和度、亮度)或YCbCr,因为在这些颜色空间中进行处理有时会得到更好的视觉效果或更符合特定应用的需求。
彩色图像直方图处理的关键在于理解和操作图像的颜色分布,以及如何通过调整这些分布来改善图像的整体或局部视觉质量。正确应用这些技术可以显著提升图像的视觉效果和适用性。
结果图显示了分别对R、G、B分量进行直方图均衡和将原图转换到HSI空间后保留H、S不变,只对I分量进行直方图均衡的结果。
图像分量的分离和合并可以用cv2.split和cv2.merge函数实现,直方图均衡仍然用cv2.equalizeHist函数实现。
由于cv2.equalizeHist规定参数必须是uint8类型的,所以得到[0,1]范围内的I分量后还需将其转换到[0,255]范围内并进行类型转换I_uint8 = (I*255).astype(np.uint8)后再进行直方图均衡。最后,将未改变的H、S分量和均衡后的I分量合并并转换为R、G、B分量。
import cv2
import numpy as np
import math
from matplotlib import pyplot as plt
# RGB转HSI,输入的三分量值域范围为[0,255],输出均在[0,1]之间
def RGB2HSI(r, g, b):
r = r / 255
g = g / 255
b = b / 255
num = 0.5 * ((r-g) + (r-b))
den = ((r-g) ** 2 + (r-b) * (g-b)) ** 0.5
h = math.acos(num / (den+1e-10))
if b > g:
h = 2*np.pi - h
s = 1 - 3*min(r, g, b) / (r+g+b+1e-10)
i = (r+g+b) / 3
h = h / (2*np.pi)
return h, s, i
# HSI转RGB,输入和输出的值域范围均为[0,1]
def HSI2RGB(h, s, i):
h = h * 2 * np.pi
if h < 2*np.pi/3:
b = i * (1 - s)
r = i * (1 + s * math.cos(h) / math.cos(np.pi/3 - h))
g = 3*i - (b+r)
elif h < 4*np.pi/3:
r = i * (1 - s)
g = i * (1 + s * math.cos(h - 2*np.pi/3) / math.cos(np.pi - h))
b = 3 * i - (r + g)
else:
g = i * (1 - s)
b = i * (1 + s * math.cos(h - 4*np.pi/3) / math.cos(5*np.pi/3 - h))
r = 3 * i - (g + b)
return r, g, b
img = cv2.imread('Fig0637.tif')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
rows = img.shape[0]
cols = img.shape[1]
# 分别对R,G,B三个分量执行直方图均衡
(R, G, B) = cv2.split(img)
R_equ = cv2.equalizeHist(R)
G_equ = cv2.equalizeHist(G)
B_equ = cv2.equalizeHist(B)
img1 = cv2.merge([R_equ, G_equ, B_equ])
# RGB空间转换到HSI空间
H = np.zeros((rows, cols))
S = np.zeros((rows, cols))
I = np.zeros((rows, cols))
for x in range(rows):
for y in range(cols):
r, g, b = img[x, y, :]
H[x, y], S[x, y], I[x, y] = RGB2HSI(r, g, b)
# 将强度分量I转换到[0,255]范围内再进行直方图均衡
I_uint8 = (I*255).astype(np.uint8)
# hist = cv2.calcHist([I_uint8], [0], None, [256], [0, 256])
# plt.subplot(1,2,1)
# plt.plot(hist)
I_equ = cv2.equalizeHist(I_uint8)
# hist_equ = cv2.calcHist([I_equ], [0], None, [256], [0, 256])
I_equ = I_equ / 255
# plt.subplot(1,2,2)
# plt.plot(hist_equ)
# plt.show()
# 保持色调H和饱和度S不变,结合均衡化后的强度I,转回RGB空间
R_new = np.zeros((rows, cols))
G_new = np.zeros((rows, cols))
B_new = np.zeros((rows, cols))
for x in range(rows):
for y in range(cols):
h = H[x, y]
s = S[x, y]
i = I_equ[x, y]
# i = I[x, y]
R_new[x, y], G_new[x, y], B_new[x, y] = HSI2RGB(h, s, i)
#R_new = (255*(R_new-R_new.min())/(R_new.max()-R_new.min())).astype(np.uint8)
#G_new = (255*(G_new-G_new.min())/(G_new.max()-G_new.min())).astype(np.uint8)
#B_new = (255*(B_new-B_new.min())/(B_new.max()-B_new.min())).astype(np.uint8)
img2 = cv2.merge([R_new, G_new, B_new])
img2 = np.clip(img2, 0, 1)
plt.subplot(1, 3, 1)
plt.imshow(img)
plt.axis('off')
plt.title('orig zzinal')
plt.subplot(1, 3, 2)
plt.imshow(img1)
plt.axis('off')
plt.title('RGB_hist_equ')
plt.subplot(1, 3, 3)
plt.imshow(img2)
plt.axis('off')
plt.title('I_hist_equ')
plt.show()
在灰度图像处理中,直方图均衡化自动地确定一种变换,改变换试图产生具有均匀灰度的直方图。由于彩色图像是由多个分量组成的,所以必须考了适应多于一个分量的直方图的灰度级技术。独立地进行彩色图像分量的直方图均衡通常是不可取的,这将产生不正确的彩色。一个更符合逻辑的方法是均匀地扩展彩色强度,而保留彩色本身。
图像直方图是反映一个图像像素分布的统计表,其横坐标代表了图像像素的种类,可以是灰度的,也可以是彩色的。纵坐标代表了每一种颜色值在图像中的像素总数或者占所有像素个数的百分比。图像是由像素构成,因为反映像素分布的直方图往往可以作为图像一个很重要的特征。直方图的显示方式是左暗又亮,左边用于描述图像的暗度,右边用于描述图像的亮度。