通过强度值标准化颜色通道和图像,OpenCV
Posted
技术标签:
【中文标题】通过强度值标准化颜色通道和图像,OpenCV【英文标题】:Normalizing color channels of and image by intensity values, OpenCV 【发布时间】:2014-06-25 19:35:29 【问题描述】:我已将图像分成 3 个独立的颜色通道 - 一个蓝色、一个绿色和一个红色。我想通过图像的强度对这些通道中的每一个进行归一化,其中强度 = (red + blue + green)/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.您不需要预先分配 split() 中使用的通道(无论如何它们都会被重新分配/覆盖) 2. r/I 之类的东西会遭受整数除法 3. 不要在 rgb 空间中这样做,转换为 hsv ,拆分,仅操作 h,合并,转换回 rgb 谢谢!好的,我摆脱了预分配,我使用了除法函数而不是'/'(这样更好吗?)。另外,您能多解释一下您所说的仅操纵 h 是什么意思吗? 除法与/相同。很抱歉我的马虎,-我之前应该问过,你想通过这种标准化来实现什么? 别担心——我正在尝试实现一个基本的显着对象检测算法。因此,显着区域将包含 r、g 或 b 颜色通道中的最不可能的值 因此对每个通道进行归一化意味着某个区域将在其中一个归一化通道上显得最亮。 (理论上,至少据我了解) 【参考方案1】:除以强度后,像素值将在 [0, 1] 范围内,但由于它们是整数,因此它们将为 0 或 1。对于显示图像,白色是 255,0 是黑色,所以这是为什么一切对你来说都是黑色的。 您需要使用浮点来获得准确的结果,并且您需要将结果缩放 255 才能看到它。 这样做会导致这个(我不确定这是否特别有用)
(Image source: 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();
【讨论】:
谢谢!这很有帮助 我意识到这是一个旧答案,但我想添加它以防其他人遇到它。你的正常化有点奇怪。因为您将强度除以 3,所以初始值为 (255,0,0) 的像素的 b_normalized_f 值为 (3,0,0)。您可能希望将强度保留为总和而不是归一化值,以便归一化通道实际上从 0 运行到 1。顺便说一句,这似乎是您的通道倾向于在 CV_8UC1 显示中剪辑的原因。 @jranalli 感谢您指出这一点。你说的有道理,但答案只是遵循 OP 指定的内容。以上是关于通过强度值标准化颜色通道和图像,OpenCV的主要内容,如果未能解决你的问题,请参考以下文章
opencv学习笔记第六篇:分离颜色通道多通道图像混合和图像对比度亮度值的调整
使用Python和OpenCV在图像之间执行超快速的颜色转换