从图像中提取特定颜色通道时,以下代码用于EMGU CV:
EMGU.CV.UI.ImageBox originalImage;
EMGU.CV.UI.ImageBox bChannel;
...
Image<Bgra, Byte> image = new Image<Bgra, Byte>(filename);
originalImage = image;
bChannel = image[0]; // Index 0 is the blue channel (for BGRA).
不幸的是,分配给ImageBox bChannel
的结果图像是灰度,不是蓝色。如何以自己的色调显示图像(在本例中为蓝色)?
最终我想提出一个类似于以下内容的用户界面:
答案 0 :(得分:1)
这真的不是我的领域,但没有一个正确理解的人已经引起了兴趣,所以不幸的是你现在一直困扰着我。
有多种“正确”的方法可以做到这一点。您的第一次尝试,将“关闭色调”通道设置为零,简单明了,毫无疑问具有隔离颜色通道的效果,但它与沙漠拱示例完全不同。视觉效果非常不同。
为简单起见,我只讨论“隔离”红色通道。同样的原则大致适用于其他两个原则(后面会详细介绍)。
沙漠拱示例的作用大致是保留整体亮度:原始图像中的白色像素最终作为结果中的白色像素;黑色像素同样如此。 R = 128的像素应为红色(依此类推,以获得平滑的曲线)。
如何红色?
对于我们这里的目的,当我们说颜色是“红色”时,我们的意思是G和B通道是相同的,并且该值小于R.也许少一点,也许少一点。当我们在低端接近黑色时,值会向零收敛,当我们在高端接近白色时,值会收敛到255.在中间,它们发散相当大的数量(如果有规范正确金额,我希望知道比我更多的人在某个时候出现。它们越分散,你的红色就越饱和。曲线在这里看起来像这种高度复杂的技术数据可视化:
下曲线描述函数f(R),其中f(0)= 0,f(255)= 255,f(128)等于小于128的某个数。如果你想要颜色是明显是红色,最好少得多。
当我数到十岁时,我脱掉了鞋子,所以我将上面的图片通过电子邮件发送给了一位坚持不懈的朋友。他提出了以下“幂律”公式:
x = 1.5
f(R) = 255 * Math.Pow(R/255, x);
...其中x
是指数。如果是x = 1.0
,那么f(R)=R
就没用多少了。从1.5
到2.5
的x值对我有用。您可以将x
调整为零以获得正确的视觉效果。
所以如果你要隔离R,
G = B = f(R)
如果您正在隔离G,
R = B = f(G)
如果您正在隔离B,
R = G = f(B)
然而,事实证明,在实践中,三个通道并不是完全对称的。粗略地说,#00ff00比#ff0000更亮,它比#0000ff更亮。从摆弄上述功能,我认为产生你的例子的算法可能会考虑到这一点。
如果我是你,我会根据您“隔离”哪个频道分别调整x,以最佳地逼近原始图像。在一些快速摆弄中,我最终使用x = 2.0表示R,x = 2.5表示G,x = 1.6表示B.
我很确定它仍然是错误的曲线,但这是正确的总体思路。根据你有多接近这个东西,你可能想要谷歌“幂律”并尝试不同的曲线功能。
答案 1 :(得分:0)
在发布我的问题之后,我意识到我可以通过将所有其他通道值设置为0(黑色)来隔离通道。这是我的代码:
Image<Bgra, Byte> img = new Image<Bgra, Byte>(filename);
Image<Bgra, Byte> blue = img.Copy();
Image<Bgra, Byte> green = img.Copy();
Image<Bgra, Byte> red = img.Copy();
Bgra tmp;
double saveGreen;
double saveRed;
for (int ii = 0; ii < img.Height; ii++)
{
for (int jj = 0; jj < img.Width; jj++)
{
tmp = img[ii,jj];
saveGreen = tmp.Green;
saveRed = tmp.Red;
// Blue
tmp.Green = 0;
tmp.Red = 0;
blue[ii,jj] = tmp;
// Green
tmp.Green = saveGreen;
tmp.Blue = 0;
green[ii, jj] = tmp;
// Red
tmp.Red = saveRed;
tmp.Green = 0;
red[ii,jj] = tmp;
}
}
imageBox1.Image = img;
imageBox2.Image = blue;
imageBox3.Image = green;
imageBox4.Image = red;
生成的UI如下:
如果您认为生成的频道图片看起来不正确,或者您可以考虑更快的方法而无需访问每个像素,请发布回答或评论。
编辑#1在ED PLUNKETT的评论之后:
我实现了以下用于设置通道颜色的代码:
Bgra tmp;
Bgra save;
for (int ii = 0; ii < img.Height; ii++)
{
for (int jj = 0; jj < img.Width; jj++)
{
tmp = img[ii,jj];
save = tmp;
// Red channel.
if (tmp.Red == 255)
{
tmp.Blue = tmp.Green = 255;
}
else
if (tmp.Red == 0)
{
tmp.Blue = tmp.Green = 0;
}
else
if (tmp.Red < 128)
{
tmp.Blue = tmp.Green = tmp.Red / 2;
}
red[ii, jj] = tmp;
// Green channel.
tmp = save;
if (tmp.Green == 255)
{
tmp.Blue = tmp.Red = 255;
}
else
if (tmp.Green == 0)
{
tmp.Blue = tmp.Red = 0;
}
else
if (tmp.Green < 128)
{
tmp.Blue = tmp.Red = tmp.Green / 2;
}
green[ii, jj] = tmp;
// Blue channel.
tmp = save;
if (tmp.Blue == 255)
{
tmp.Green = tmp.Red = 255;
}
else
if (tmp.Blue == 0)
{
tmp.Green = tmp.Red = 0;
}
else
if (tmp.Blue < 128)
{
tmp.Green = tmp.Red = tmp.Blue / 2;
}
blue[ii, jj] = tmp;
}
}
此外,我使用了沙漠图像并移动了通道,因此顺序与样本图像中的RGB顺序相匹配。这是输出:
它不完全相同(红色通道太像原始图像)但整体看起来更像是沙漠样本中使用的分割。
编辑#2在ED PLUNKETT的回答之后:
这里输出的是pow = 1.5:
pow = 2.0的输出:
pow = 2.5的输出:
粉末的输出=红色为2.0,绿色为2.5,蓝色为1.6: