计划
我的项目能够捕获目标窗口的位图并将其转换为IplImage
,然后将该图像显示在 中cvNamedWindow
,可以进行进一步处理。
为了测试,我将图像加载到 MSPaint 中,如下所示:
然后,允许用户在图像内任意数量的像素上单击并拖动鼠标,以创建vector<cv::Scalar_<BYTE>>
包含这些 RGB 颜色值的图像。
然后,在 的帮助下ColorRGBToHLS()
,这个数组然后按色调从左到右排序,如下所示:
// PixelColor is just a cv::Scalar_<BYTE>
bool comparePixelColors( PixelColor& pc1, PixelColor& pc2 ) {
WORD h1 = 0, h2 = 0;
WORD s1 = 0, s2 = 0;
WORD l1 = 0, l2 = 0;
ColorRGBToHLS(RGB(pc1.val[2], pc1.val[1], pc1.val[0]), &h1, &l1, &s1);
ColorRGBToHLS(RGB(pc2.val[2], pc2.val[1], pc2.val[0]), &h2, &l2, &s2);
return ( h1 < h2 );
}
//..(elsewhere in code)
std::sort(m_colorRange.begin(), m_colorRange.end(), comparePixelColors);
...然后显示在一个 newcvNamedWindow
中,看起来像:
问题
现在,这里的想法是创建一个二进制阈值图像(或“蒙版”),其中这个选定的颜色范围变为白色,而源图像的其余部分变为黑色......类似于“按颜色选择”工具的方式在 GIMP 中运行,或者“魔术棒”工具在 Photoshop 中运行……除了将自己限制在特定的轮廓选择之外,我们实际上是在对整个图像进行操作。
我读过cvInRangeS
,听起来这正是我所需要的。
但是,无论出于何种原因,阈值图像总是最终完全是黑色的......
VOID ShowThreshedImage(const IplImage* src, const PixelColor& min, const PixelColor& max)
{
IplImage* imgHSV = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 3);
cvCvtColor(src, imgHSV, CV_RGB2HLS);
cvNamedWindow("T1");
cvShowImage("T1", imgHSV); // <-- Shows up like the image below
IplImage* imgThreshed = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
cvInRangeS(imgHSV, min, max, imgThreshed);
cvNamedWindow("T2");
cvShowImage("T2", imgThreshed); // <-- SHOWS UP PITCH BLACK!
}
这就是"T1"
窗口最终的样子(我想这是正确的?):
请记住,由于颜色范围向量存储为 RGB (并且 OpenCV 在内部将此顺序反转为 BGR),因此我已将最小/最大值转换为 HLS,然后再将它们传递给ShowThreshedImage()
如下所示:
CvScalar rgbPixelToHSV(const PixelColor& pixelColor)
{
WORD h = 0, s = 0, l = 0;
ColorRGBToHLS(RGB(pixelColor.val[2], pixelColor.val[1], pixelColor.val[0]), &h, &l, &s);
return PixelColor(h, s, l);
}
//...(elsewhere in code)
if(m_colorRange.size() > 0)
m_minHSV = rgbPixelToHSV(m_colorRange[0]);
if(m_colorRange.size() > 1)
m_maxHSV = rgbPixelToHSV(m_colorRange[m_colorRange.size() - 1]);
ShowThreshedImage(m_imgSrc, m_minHSV, m_maxHSV);
...但是即使没有这种转换并且只是简单地传递 RGB 值,结果仍然是一个完全黑色的图像。我什至尝试过手动插入某些最小/最大值,我得到的最好结果是几个点亮的像素(尽管是不正确的像素)。
问题:
我在这里做错了什么?
该方法有什么我不明白的地方cvInRangeS
吗?我是否需要逐步检查每一种颜色才能正确地将所选范围从源图像中设置为阈值?
有没有其他方法可以做到这一点?
感谢您的时间。
更新:
我发现cvInRangeS
期望所有值都min
低于max
。But when a range of colors are selected, there doesn't appear to be any guarantee that this will be the case, often resulting in a black thresholded image. 并且交换值以强制执行此规则可能会导致新范围内出现不需要的颜色(在某些情况下,这可能包括所有颜色而不仅仅是所需的颜色)。
所以我想这里真正的问题是:
“你如何分割一组 RGB 颜色,并使用它们来阈值图像?”