通过强度值规范化图像的颜色通道,OpenCV

4
我已将一张图像分成了三个独立的颜色通道——蓝色、绿色和红色。我想对每个通道进行归一化处理,使其与图像的强度相匹配,其中强度=(红色+蓝色+绿色)/3。请注意,我试图制作一个由三个颜色通道中的一个组成的图像,它被图像的强度除以,其中强度由上述方程式描述。 我是OpenCV的新手,我不认为我的做法是正确的;当这些图像被显示时,所有像素都显示为黑色。 我是OpenCV的新手(我已经完成了文档附带的教程,但仅此而已),如果您能给我一些建议来解决这个归一化问题,那将非常有帮助。
谢谢! 以下是我的尝试:
int main(int argc, char** argv){
Mat sourceImage, I;
const char* redWindow = "Red Color Channel";
const char* greenWindow = "Green Color Channel";
const char* blueWindow = "Blue Color Channel";


if(argc != 2)
{
  cout << "Incorrect number of arguments" << endl;
}
/* Load the image */
sourceImage = imread(argv[1], 1);
if(!sourceImage.data)
{
  cout << "Image failed to load" << endl;
}

/* First, we have to allocate the new channels */
Mat r(sourceImage.rows, sourceImage.cols, CV_8UC1);
Mat b(sourceImage.rows, sourceImage.cols, CV_8UC1);
Mat g(sourceImage.rows, sourceImage.cols, CV_8UC1);

/* Now we put these into a matrix */
Mat out[] = {b, g, r};

/* Split the image into the three color channels */
split(sourceImage, out);

/* I = (r + b + g)/3  */
add(b, g, I);
add(I, r, I);
I = I/3;

Mat red = r/I;
Mat blue = b/I;
Mat green = g/I;

/* Create the windows */
namedWindow(blueWindow, 0);
namedWindow(greenWindow, 0);
namedWindow(redWindow, 0);

/* Show the images */
imshow(blueWindow, blue);
imshow(greenWindow, green);
imshow(redWindow, red);

waitKey(0);
return 0;
}

1
  1. 在split()中使用的通道不需要预先分配(它们将被重新分配/覆盖)。
  2. 类似r/I这样的情况会受到整数除法的影响。
  3. 不要在RGB空间中进行操作,转换为HSV,拆分,仅操作H通道,合并,再转换回RGB。
- berak
没问题 - 我正在尝试实现一个基本的显著物体检测算法。因此,显著区域将包含r、g或b颜色通道中最不可能的值。 - Nathan
啊,看到了,误解的根源在这里——我更多地是考虑均衡化方面。但是再说一遍,如果你想要除法,你可能需要先将通道转换为浮点数。否则你会遇到像这样的问题:7/12(这是整数/uchar的0)。 - berak
好的,谢谢,又一个很好的观点! - Nathan
你能否详细解释一下你所说的“仅操作h”的意思? - Nathan
显示剩余5条评论
1个回答

5
一旦你将像素值除以强度,像素值将在范围[0,1]内,但由于它们是整数,它们将是0或1。对于显示图像,白色为255,黑色为0,这就是为什么你看到的一切都是黑色的原因。
你需要使用浮点数来得到准确的结果,并且需要将结果缩放为255才能看到它。
这样做会产生这个(我不确定是否特别有用)。
图片来源:BSDS500
以下是生成它的代码:
#include <opencv2/core/core.hpp>
#include <vector>   
int main(int argc, char** argv)
{
    // READ RGB color image and convert it to Lab
    cv::Mat bgr_image = cv::imread("208001.jpg"); // BSDS500 mushroom
    cv::imshow("original image", bgr_image);
    cv::Mat bgr_image_f;
    bgr_image.convertTo(bgr_image_f, CV_32FC3);

    // Extract the color planes and calculate I = (r + g + b) / 3
    std::vector<cv::Mat> planes(3);
    cv::split(bgr_image_f, planes); 

    cv::Mat intensity_f((planes[0] + planes[1] + planes[2]) / 3.0f);
    cv::Mat intensity;
    intensity_f.convertTo(intensity, CV_8UC1);
    cv::imshow("intensity", intensity);

    //void divide(InputArray src1, InputArray src2, OutputArray dst, double scale=1, int dtype=-1)
    cv::Mat b_normalized_f;
    cv::divide(planes[0], intensity_f, b_normalized_f);
    cv::Mat b_normalized;
    b_normalized_f.convertTo(b_normalized, CV_8UC1, 255.0);
    cv::imshow("b_normalized", b_normalized);

    cv::Mat g_normalized_f;
    cv::divide(planes[1], intensity_f, g_normalized_f);
    cv::Mat g_normalized;
    g_normalized_f.convertTo(g_normalized, CV_8UC1, 255.0);
    cv::imshow("g_normalized", g_normalized);

    cv::Mat r_normalized_f;
    cv::divide(planes[2], intensity_f, r_normalized_f);
    cv::Mat r_normalized;
    r_normalized_f.convertTo(r_normalized, CV_8UC1, 255.0);
    cv::imshow("r_normalized", r_normalized);
    cv::waitKey();
}

谢谢!这非常有帮助。 - Nathan
我知道这是一个旧答案,但我想添加这个以防其他人遇到类似问题。你的归一化有点奇怪。因为你将强度除以3,一个初始值为(255,0,0)的像素将具有b_normalized_f值(3,0,0)。你可能希望保留强度作为总和而不是规范化值,这样规范化通道实际上从0到1运行。顺便说一句,这似乎是为什么你的通道倾向于在CV_8UC1显示中剪切的原因。 - jranalli
1
@jranalli 感谢您指出这一点。您所说的很有道理,但答案只是按照 OP 指定的方式进行了回答。 - Bull

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