OpenCV Python 直方图均衡化彩色图像

38

我需要对一张彩色图像进行直方图均衡化。

首先将彩色图像转换为灰度图像,并将其提供给equalizeHist函数:

image = cv2.imread("photo.jpg")
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.equalizeHist(image)
cv2.imshow("equalizeHist", image)
cv2.waitKey(0)

但是在此之后,我需要将图像转换回RGB格式,我该怎么做?

11个回答

53

来源: https://www.packtpub.com/packtlib/book/Application-Development/9781785283932/2/ch02lvl1sec26/Enhancing%20the%20contrast%20in%20an%20image

import cv2
import numpy as np

img = cv2.imread('input.jpg')

img_yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)

# equalize the histogram of the Y channel
img_yuv[:,:,0] = cv2.equalizeHist(img_yuv[:,:,0])

# convert the YUV image back to RGB format
img_output = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2BGR)

cv2.imshow('Color input image', img)
cv2.imshow('Histogram equalized', img_output)

cv2.waitKey(0)
使用OpenCV对彩色图像进行直方图均衡化

6
均衡化后的图像看起来有些奇怪。 - Kai Wang
2
你的链接损坏了! - Farid Alijani
1
要修复颜色,请查看此帖子:https://dev59.com/HFkS5IYBdhLWcg3w6qIz - Swaroop
如果你遇到了奇怪的颜色问题,可以使用CLAHE。 - user14675723

25

输入图片与均衡化后的图片


Python 代码

import cv2

def run_histogram_equalization(image_path):
    rgb_img = cv2.imread(image_path)

    # convert from RGB color-space to YCrCb
    ycrcb_img = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2YCrCb)

    # equalize the histogram of the Y channel
    ycrcb_img[:, :, 0] = cv2.equalizeHist(ycrcb_img[:, :, 0])

    # convert back to RGB color-space from YCrCb
    equalized_img = cv2.cvtColor(ycrcb_img, cv2.COLOR_YCrCb2BGR)

    cv2.imshow('equalized_img', equalized_img)
    cv2.waitKey(0)

解释

直方图均衡化(HE)是一种统计方法,用于在图像处理中扩展强度值。在图像处理中,HE用于改善任何图像的对比度,即使黑暗部分更暗,明亮部分更亮。

对于灰度图像,每个像素由强度值(亮度)表示;因此我们能够将像素值直接提供给HE函数。然而,对于RGB格式的彩色图像,这不是工作方式。 RGB的每个通道表示相关颜色的强度,而不是整个图像的强度/亮度。因此,在这些颜色通道上运行HE不是正确的方法。

我们应该首先从颜色中分离出图像的亮度,然后在亮度上运行HE。现在已经有了标准化的颜色空间,可以分别编码亮度和颜色,例如-YCbCrHSV等;因此,在此处可以使用它们进行分离,然后重新合并亮度。正确的做法:

将颜色空间从RGB转换为YCbCr>>对Y通道运行HE (该通道表示亮度)>>将颜色空间转换回RGB


补充说明

对于HSV颜色空间,应在V通道上运行HE。然而,YCbCrY通道比HSVV通道更好地代表亮度。因此,使用YCbCr格式产生更正确的HE结果。

HSV vs YCbCr


补充说明2

HE是一种朴素技术,往往会产生奇特的颜色和小众问题。这是因为它不关心异常值和像素的位置。因此,常用的扩展技术——对比有限自适应HE、保持亮度的双重HE等。此外,在后处理阶段执行不同的降噪函数以改进最终输出。


12

一种更加通用的方法是将RGB值转换为另一个包含亮度/强度值的空间(Luv、Lab、HSV、HSL),仅在强度平面上应用histeq,然后执行反向转换。


5

您无需先将图像转换为灰度图像,可以使用下面的方法。上面提出的建议解决方案使用了YUV颜色空间,但我会使用HSV颜色空间来进行此示例。

image = cv2.imread("photo.jpg")

# convert image from RGB to HSV
img_hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)

# Histogram equalisation on the V-channel
img_hsv[:, :, 2] = cv2.equalizeHist(img_hsv[:, :, 2])

# convert image back from HSV to RGB
image = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2RGB)

cv2.imshow("equalizeHist", image)
cv2.waitKey(0)

5
颜色失真。 - MsLate
imread和imshow使用的是BGR而不是RGB。这可能是颜色失真的原因。 - Pranav
要修复颜色,请查看此帖子:https://dev59.com/HFkS5IYBdhLWcg3w6qIz - Swaroop

5
img_yuv = cv2.cvtColor(image, cv2.COLOR_BGR2YUV)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(2,2))
img_yuv[:,:,0] = clahe.apply(img_yuv[:,:,0])
img = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2BGR)
cv2.imshow("equalizeHist", img)
cv2.waitKey(0)

3
如果你能解释一下你的代码,以及你实际在做什么,那就太好了,我的朋友。 - stateMachine
https://en.wikipedia.org/wiki/Adaptive_histogram_equalization - Homura Akemi
3
正如 @eldesgraciado 提到的那样,请对您的答案进行一些解释,仅提供一个维基百科链接并不能使其更加完整。请解释为什么您包含了该参考资料?该参考资料与问题有何关联。谢谢!(翻译:请提供更多解释,不要只给维基百科链接,解释为什么你用这个链接作为参考,并说明它与问题的关系。谢谢!) - EnriqueBet
建议修改:请在img = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2RGB)之前将倒数第三行更改为RGB。 - user2814778

4

颜色转换方法cv2.cvtColor()用于在RGB / BGR和YUV之间转换原始图像。以下是最佳的代码片段 -

# convert it to grayscale
img_yuv = cv2.cvtColor(img,cv2.COLOR_BGR2YUV)

# apply histogram equalization 
img_yuv[:,:,0] = cv2.equalizeHist(img_yuv[:,:,0])
hist_eq = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2BGR)

您可以从此处了解更多信息 - https://www.etutorialspoint.com/index.php/311-python-opencv-histogram-equalization

2

这是一个函数,它可以接受彩色图像作为输入,并返回直方图均衡化后的图像。

# function for color image equalization
def histogram_equalization(img_in):
    # segregate color streams
    b, g, r = cv2.split(img_in)
    h_b, bin_b = np.histogram(b.flatten(), 256, [0, 256])
    h_g, bin_g = np.histogram(g.flatten(), 256, [0, 256])
    h_r, bin_r = np.histogram(r.flatten(), 256, [0, 256])
    # calculate cdf
    cdf_b = np.cumsum(h_b)
    cdf_g = np.cumsum(h_g)
    cdf_r = np.cumsum(h_r)

    # mask all pixels with value=0 and replace it with mean of the pixel values
    cdf_m_b = np.ma.masked_equal(cdf_b, 0)
    cdf_m_b = (cdf_m_b - cdf_m_b.min()) * 255 / (cdf_m_b.max() - cdf_m_b.min())
    cdf_final_b = np.ma.filled(cdf_m_b, 0).astype('uint8')

    cdf_m_g = np.ma.masked_equal(cdf_g, 0)
    cdf_m_g = (cdf_m_g - cdf_m_g.min()) * 255 / (cdf_m_g.max() - cdf_m_g.min())
    cdf_final_g = np.ma.filled(cdf_m_g, 0).astype('uint8')


    cdf_m_r = np.ma.masked_equal(cdf_r, 0)
    cdf_m_r = (cdf_m_r - cdf_m_r.min()) * 255 / (cdf_m_r.max() - cdf_m_r.min())
    cdf_final_r = np.ma.filled(cdf_m_r, 0).astype('uint8')
    # merge the images in the three channels
    img_b = cdf_final_b[b]
    img_g = cdf_final_g[g]
    img_r = cdf_final_r[r]

    img_out = cv2.merge((img_b, img_g, img_r))
    # validation
    equ_b = cv2.equalizeHist(b)
    equ_g = cv2.equalizeHist(g)
    equ_r = cv2.equalizeHist(r)
    equ = cv2.merge((equ_b, equ_g, equ_r))
    # print(equ)
    # cv2.imwrite('output_name.png', equ)
    return img_out

1

如果您想均衡化RGB图像,不应该将其转换为灰度图像,而是应该逐个均衡化RGB通道。

所以,我认为这可能是您想要的:

def equalize_hist(img):
    for c in xrange(0, 2):
       img[:,:,c] = cv2.equalizeHist(img[:,:,c])

    cv2.imshow('Histogram equalized', img)
    cv2.waitKey(0)

    return img

2
正如另一个答案的评论所提到的,这会扭曲颜色。 - SajanGohil
应该使用xrange(3)来迭代索引0、1和2。 - Andy

1

我不确定它是否正常工作:

def histogram_equalize(img):
    b, g, r = cv2.split(img)
    red = cv2.equalizeHist(r)
    green = cv2.equalizeHist(g)
    blue = cv2.equalizeHist(b)
    return cv2.merge((blue, green, red))

20
这是独立地均衡化RGB通道,因此会导致颜色失真。 - broofa
在一行中返回翻译后的文本:cv2.merge([cv2.equalizeHist(c) for c in cv2.split(img)]) - Andy

0

你不应该将图像转换为灰度。你可以使用彩色图像来处理。但是,OpenCV始终以BGR颜色格式读取图像,而不是RGB格式。

import cv2

# imread needs 2 parameters. path and the flag
img = cv2.imread("photo.jpg", 1)

# convert image from BGR to HSV
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# Histogram equalisation on the V-channel
img_hsv[:, :, 2] = cv2.equalizeHist(img_hsv[:, :, 2])

# now the img_hsv has equalized
# now convert hsv image back from HSV to RGB
imgequalized = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2RGB)

cv2.imshow("original img", img)
cv2.imshow("equalizeHist", imgequalized)
cv2.waitKey(0)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接