我目前的目标是调整图像中的红色像素(更具体地说,是用于消除闪光引起的红眼的眼睛区域),这很有效,但我有时会遇到这个问题皮肤上出现绿色斑块。
这是一个很好的结果(之前和之后):
我意识到为什么会发生这种情况,但是当我将阈值调整到更高的值(意味着红色强度必须更强)时,更少的红色像素被拾取和更改,即:
阈值越低,皮肤上出现的绿色就越多。
我想知道我目前在改变红色像素方面是否有其他方法?
int lcount = 0;
for(int y=0;y<lcroppedEye.rows;y++)
{
for(int x=0;x<lcroppedEye.cols;x++)
{
double b = lcroppedEye.at<cv::Vec3b>(y, x)[0];
double g = lcroppedEye.at<cv::Vec3b>(y, x)[1];
double r = lcroppedEye.at<cv::Vec3b>(y, x)[2];
double redIntensity = r / ((g + b) / 2);
//currently causes issues with non-red-eye images
if (redIntensity >= 1.8)
{
double newRedValue = (g + b) / 2;
cv::Vec3b pixelColor(newRedValue,g,b);
lroi.at<cv::Vec3b>(cv::Point(x,y)) = pixelColor;
lcount++;
}
}
}
编辑:我可以添加一个检查以确保新的RGB值足够低,因此R,G,B值是相似/接近的值,因此写出黑色/灰色像素只有...或者有一系列不允许的RGB值(绿色)...会起作用吗?
答案 0 :(得分:3)
改变
可能更好double redIntensity = r / ((g + b) / 2);
到
double redIntensity = r / ((g+b+1) / 2);
因为g + b可以等于0,你就会得到NAN。
另请参阅cv :: floodfill方法。
答案 1 :(得分:3)
调整RGB空间中的颜色需要注意您所面临的绿色区域。将R,G,B值转换为更好的色彩空间,如HSV或LUV。
我建议你去HSV检测并改变红眼颜色。 R /(G + B)不是计算红色强度的好方法。这意味着你正在调用(R = 10,G = 1,B = 0)一种非常红的颜色,但它是致命的黑色。看看下面的比较:
因此,您最好检查饱和度和值是否为高值,红眼颜色就是这种情况。如果遇到其他高强度颜色,可以检查Hue是否在[0-20]和[340-359]之间。但是如果没有这个,你仍然可以安全地对抗白色本身,因为它具有非常低的饱和度并且你无论如何都不会选择白色区域。
那是为了选择,为了改变颜色,最好不要使用RGB,因为当我们感知颜色时,那个空间的变化不是线性的。看看上面的图像,你可以看到降低饱和度和值都是一个好的开始。但是你可以尝试一下,看看看起来更好看。也许你总是可以使用深灰色,这意味着将饱和度设置为零,并将值降低一点。您可能会认为深棕色会更好,但要求低饱和度和值,但将Hue设置为大约30度。
可能对您有帮助的参考资料:
答案 2 :(得分:1)
(在继续进行连通分量分析之前,您可能需要对maskImage进行一些预处理。此外,您可以使用split,divide和threshold函数替换问题中的代码段,除非有特殊原因迭代像素)
答案 3 :(得分:1)
一旦红色区域中的颜色信息被额外的红色值扭曲太多,可能最好忽略红色区域的颜色信息。所以新的价值观可能是:
newRedValue =(g + b)/ 2; newGreenValue = newRedValue; newBlueValue = newRedValue;
即使您检测到错误的红色区域,其饱和度也会比绿色区域产生更好的效果。 您还可以使用morphological closing operations(使用圆形结构元素)来避免红色区域遮罩中的间隙。因此,您需要执行3个步骤:1。找到红色区域并为此创建遮罩2.执行红色区域遮罩形态关闭操作3.使用此遮罩去饱和图像
是的,不要使用&#34; r /((g + b)/ 2)&#34;因为它可以导致除零错误。
答案 4 :(得分:1)
问题似乎是无论是否存在任何红眼都会替换,所以你必须以某种方式测试是否有任何高红色值(比你的皮肤更红)。
我猜测那里有反射的区域也会有特定的蓝色和绿色值,无论是高值还是低值都要检查,以便你需要高红色值和低蓝色和/或低绿色值。
// first pass, getting the highest red value
int highRed = 0;
cv::Point redPos = cv::Point(0,0);
int lcount = 0;
for(int y=0;y<lcroppedEye.rows;y++)
{
for(int x=0;x<lcroppedEye.cols;x++)
{
double r = lcroppedEye.at<cv::Vec3b>(y, x)[2];
if (redIntensity > highRed)
{
highRed = redIntensity ;
redPos = cv::Point(x,y);
}
}
}
// decide if its red enough, need to find a good minRed value.
if (highRed < minRed)
return;
此处的原始代码包含以下更改。
// avoid division by zero, code from @AndreySmorodov
double redIntensity = r / ((g+b+1) / 2);
// add check for actual red colour.
if (redIntensity >= 1.8 && r > highRed*0.75)
// potential add check for low absolute r/b values.
{
double newRedValue = (g + b) / 2;
cv::Vec3b pixelColor(newRedValue,g,b);
lroi.at<cv::Vec3b>(cv::Point(x,y)) = pixelColor;
lcount++;
}
}