【问题标题】:Histogram equalization not working on color image - OpenCV直方图均衡不适用于彩色图像 - OpenCV
【发布时间】:2013-02-07 01:47:38
【问题描述】:

我正在尝试使用以下函数使用 OpenCV 执行直方图均衡

Mat Histogram::Equalization(const Mat& inputImage)
{
    if(inputImage.channels() >= 3)
    {
        vector<Mat> channels;
        split(inputImage,channels);
        Mat B,G,R;

        equalizeHist( channels[0], B );
        equalizeHist( channels[1], G );
        equalizeHist( channels[2], R );
        vector<Mat> combined;
        combined.push_back(B);
        combined.push_back(G);
        combined.push_back(R);
        Mat result;
        merge(combined,result);
        return result;
    }
    return Mat();
}

但是当我得到结果时,输入和输出图像似乎没有区别,我做错了什么?

抱歉图像质量不好,“预处理”(左)是直方图均衡,你可以看到它与输入相同(右)。

错过了什么?

【问题讨论】:

  • Split -> Equalize -> Merge 不是执行彩色图像直方图均衡的正确方法。它会严重影响图像的色彩平衡。在图像中引入多种颜色的对象,您会看到它会产生颜色不平衡。

标签: c++ opencv image-processing histogram histogram-equalization


【解决方案1】:

直方图均衡是一个非线性过程。通道拆分和单独均衡每个通道不是对比度均衡的正确方法。均衡涉及图像的 强度 值,而不是颜色分量。所以对于一个简单的 RGB 彩色图像,HE 不应该单独应用于每个通道。相反,它应该被应用,以便在不干扰图像色彩平衡的情况下均衡强度值。因此,第一步是将图像的颜色空间从 RGB 转换为将强度值与颜色分量分开的颜色空间之一。其中一些是:

将图像从 RGB 转换为上述颜色空间之一。 YCbCr 是首选,因为它专为 数字 图像而设计。执行强度平面 Y 的 HE。将图像转换回 RGB。

在您目前的情况下,您没有观察到任何显着变化,因为图像中只有 2 种突出的颜色。当图像中的颜色较多时,分割方法会导致颜色不平衡。

例如,考虑以下图片:

输入图像

强度图像均衡

独立通道均衡

(注意假色)

这是使用 YCbCr 色彩空间对彩色图像进行直方图均衡的 OpenCV 代码。

Mat equalizeIntensity(const Mat& inputImage)
{
    if(inputImage.channels() >= 3)
    {
        Mat ycrcb;

        cvtColor(inputImage,ycrcb,CV_BGR2YCrCb);

        vector<Mat> channels;
        split(ycrcb,channels);

        equalizeHist(channels[0], channels[0]);

        Mat result;
        merge(channels,ycrcb);

        cvtColor(ycrcb,result,CV_YCrCb2BGR);

        return result;
    }
    return Mat();
}

【讨论】:

  • 谢谢 :) 会试试看!
  • 美丽 - 这是最好的解决方案。我看到的其他一切都涉及操纵光栅阵列。 ++++1
【解决方案2】:

我为 BGRA 图像实现了直方图均衡化。我认为这个函数对你的目标很有用(但你应该忽略 alpha 通道)。

Mat equalizeBGRA(const Mat& img)
{
Mat res(img.size(), img.type());
Mat imgB(img.size(), CV_8UC1);
Mat imgG(img.size(), CV_8UC1);
Mat imgR(img.size(), CV_8UC1);
Vec4b pixel;

if (img.channels() != 4)
{
    cout << "ERROR: image input is not a BGRA image!" << endl;
    return Mat();
}

for (int r = 0; r < img.rows; r++)
{
    for (int c = 0; c < img.cols; c++)
    {
        pixel = img.at<Vec4b>(r, c);
        imgB.at<uchar>(r, c) = pixel[0];
        imgG.at<uchar>(r, c) = pixel[1];
        imgR.at<uchar>(r, c) = pixel[2];
    }
}

equalizeHist(imgB, imgB);
equalizeHist(imgG, imgG);
equalizeHist(imgR, imgR);

for (int r = 0; r < img.rows; r++)
{
    for (int c = 0; c < img.cols; c++)
    {
        pixel = Vec4b(imgB.at<uchar>(r, c), imgG.at<uchar>(r, c), imgR.at<uchar>(r, c), img.at<Vec4b>(r, c)[3]);
        res.at<Vec4b>(r, c) = pixel;
    }
}

return res;
}

【讨论】:

  • 这种方式还可以,但还是遵循不推荐的通道拆分方式。此外,您可以使用cv::mixChannels 从 4 通道图像中提取 R、G 和 B,而不是循环。
【解决方案3】:

还有python版本,@sga:

import cv2
import os

def hisEqulColor(img):
    ycrcb=cv2.cvtColor(img,cv2.COLOR_BGR2YCR_CB)
    channels=cv2.split(ycrcb)
    print len(channels)
    cv2.equalizeHist(channels[0],channels[0])
    cv2.merge(channels,ycrcb)
    cv2.cvtColor(ycrcb,cv2.COLOR_YCR_CB2BGR,img)
    return img


fname='./your.jpg'
img=cv2.imread(fname)

cv2.imshow('img', img)
img2=hisEqulColor(img)
cv2.imshow('img2',img2)

但是这会在图像中产生噪点(例如,下面的左图)

【讨论】:

  • 直方图均衡用于调整对比度,只应用于亮度(Y 或类似),而不是每个颜色通道。这是正确的。
猜你喜欢
  • 2017-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-30
相关资源
最近更新 更多