3

当我滑过轨迹栏时,是否有更好的方法可以平滑地更改图像的色调?我正在做的是获取每个像素的 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);
        }
    }
}
4

2 回答 2

4

如果您想要一个改变色调的单色图像,那么最有效的方法是生成红色、黄色、绿色、青色、蓝色和洋红色图像,并根据需要在它们之间进行插值。

因此,要生成 10% 旋转的图像,您需要添加 50/60 * red + 10/60 * yellow 并显示它。

事实上,您并不需要生成所有 6 张图像。生成红色和黄色图像就足够了。您可以即时生成其他图像,因为例如,蓝色图像只是红色图像,但红色和蓝色像素交换了(您甚至可以从红色中导出黄色)。但最简单的方法可能是从 6 个图像开始,然后再添加优化。

生成一个初始彩色图像的代码与上面的代码相似(乍一看),但是从 HSV 到 RGB 的最后一步看起来有点可疑 - 维基百科页面很好地解释了这一点(并且 C# 可能包含一个库函数来做这个转换)。

[鉴于您的澄清,以下内容与您正在做的事情无关]

如果您想逐个像素地改变色调(因此红色变为黄色,而绿色变为青色),那么您可以先将整个图像转换为 HSV,然后再进行处理,从而节省一些时间。

您可以通过生成多个图像(例如色调每旋转 10 度)然后在它们之间进行插值来节省更多时间(在改变色调时)。但它比单色情况更复杂,因为某些像素(在插值期间色调移动通过 60 度的倍数的像素)需要特殊处理。因此,您还需要预先检测这些,然后即时计算它们。有一个权衡,因为您拥有的中间图像越多,特殊情况所需的像素就越少。在实践中,懒惰地(按需)生成单独的图像会加快启动速度,因为通常人们只做很小的改变。

于 2011-08-06T02:22:26.213 回答
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 的代码也可能是用汇编程序编写的,以获得最佳性能。

为了看看这是否会有很大的影响,你可以注释掉所有的色调计算代码,看看它是如何通过复制假数据来执行的。如果它像 Photoshop 一样灵活,那么您就知道这些计算是您的瓶颈。

于 2011-08-06T02:07:41.443 回答