当我滑过轨迹栏时,是否有更好的方法可以平滑地更改图像的色调?我正在做的是获取每个像素的RGB值,计算饱和度和亮度,然后将值放入。图像的大小会影响色调的更新速度。 Photoshop的图像色调功能可以平滑地将色调从0变为360,这是我想要尝试的内容。
data = editImage.LockBits(new Rectangle(0, 0, editWidth, editHeight),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte* dataPtr = (byte*)data.Scan0;
h = trackBar1.Value / 60.0;
D = 1 - Math.Abs((h % 2) - 1);
if (h >= 0 && h < 1)
{
for (int i = 0; i < editHeight; i++)
{
offsetStride = i * data.Stride;
for (int j = 0; j < editWidth; j++)
{
blue = dataPtr[(j * 3) + offsetStride];
green = dataPtr[(j * 3) + offsetStride + 1];
red = dataPtr[(j * 3) + offsetStride + 2];
if (green > blue) max = green;
else max = blue;
if (red > max) max = red;
if (green < blue) min = green;
else min = blue;
if (red < min) min = red;
s = (max == 0) ? 0 : 1d - (1d * min / max);
v = max / 255d;
C = v * s;
X = C * D;
E = v - C;
dataPtr[(j * 3) + offsetStride] = (byte)(min);
dataPtr[(j * 3) + offsetStride + 1] = (byte)((X + E) * 255);
dataPtr[(j * 3) + offsetStride + 2] = (byte)(max);
}
}
}
答案 0 :(得分:4)
如果你想要一个改变色调的单色图像,那么最有效的方法是生成红色,黄色,绿色,青色,蓝色和洋红色图像,并根据需要在它们之间进行插值。
因此,要生成10%旋转的图像,您可以添加50/60 *红色+ 10/60 *黄色并显示。
实际上,您并不需要生成所有6张图像。生成红色和黄色图像就足够了。你可以动态生成其他的,因为,例如,蓝色图像只是红色图像,但红色和蓝色像素交换(你甚至可以从红色中获得黄色)。但是从6张图片开始然后再添加优化可能是最简单的。
生成一个初始彩色图像的代码与上面的内容相似(乍一看),但是从HSV到RGB的最后一步看起来有点怀疑 - 维基百科页面很擅长解释这个(并且它是可能的C#包含一个库函数来进行这种转换。)
[鉴于您的澄清,下面与您正在做的事情无关]
如果你想逐个像素地移动色调(所以当绿色移动到青色时红色移动到黄色)然后你可以节省一些时间,首先将整个图像转换为HSV,然后再使用它。
您可以通过生成多个图像(比如每10度旋转一次)来节省更多时间(换色调时),然后在它们之间进行插值。但它比单色情况更复杂,因为一些像素(色调在插值过程中移动了60度的倍数)需要特殊处理。因此,您还需要预先检测这些,然后即时计算它们。有一个权衡,因为你拥有的中间图像越多,你需要的特殊像素就越少。在实践中,懒洋洋地(按需)生成单独的图像将会更快地启动,因为通常人们只会进行小的更改。
答案 1 :(得分:2)
您可以尝试使用查找表来摆脱's'的计算,因为min和max的范围只能是0到255.所以你有s = getS(min, max)
。 C和E的值也可以保存在这个表中(但是它已经很晚了,我看起来并不那么难)。
getS表的每个元素都将预先计算为
for (int min = 0; min < 255; min++)
{
for (int max = 0; max < 255; max++)
{
tableS[min, max] = (max == 0) ? 0 : 1d - (1d * min / max);
}
}
Photoshop的代码可能也是用汇编语言编写的,以获得最大的性能。
为了查看这是否会产生很大影响,您可以注释掉所有Hue计算代码,并通过复制假数据来查看它的执行情况。如果它像Photoshop一样活泼,那么你知道这些计算是你的瓶颈。