替换透明图像中的颜色渐变

时间:2010-07-13 17:28:56

标签: c# bitmap bitmapdata bitmapimage

我有一个小函数,可以将Bitmap中的像素从给定颜色重新着色为新的给定颜色。

我对代码的问题如下:

1) 该函数给出了重新映射白色像素的结果,因为我有一个阈值,所以不应该这样的结果......(除非我已经定义了这个计算错误)

2)当给出某些颜色时,例如LimeGreen在函数返回的图像中看到了奇怪的结果(我相信这是由于在加法或减法情况下字节类型的溢出)

我正在使用的基本图像可以在这里找到:

http://www.freeimagehosting.net/uploads/c8745a9de1.png

我获得的结果可以在这里找到:

freeimagehosting.net/uploads/fa48e5a0eb.png(使用Color.Magenta作为remapColor调用,Color.Red作为newColor,看起来像白色像素受影响,渐变的结尾没有正确着色)

freeimagehosting.net/uploads/8faec6a569.png(使用Color.Magenta作为remapColor调用,Color.Yellow作为newColor调用,看起来像白色像素受影响,渐变的结尾没有正确着色)

freeimagehosting.net/uploads/2efd4c04aa.png(用Color.Magenta作为remapColor调用,Color.Blue作为newColor调用,看起来像渐变没有正确着色)

freeimagehosting.net/uploads/defdf04e16.png(使用Color.Magenta作为remapColor调用,Color.Teal作为newColor调用,看起来像白色像素一样,并且没有正确计算渐变)

我对此代码的功能如下:按建议更新

public unsafe static Bitmap RecolorImage(Bitmap original, Color remapColor, Color newColor)
    {
        Bitmap result = new Bitmap(original.Width, original.Height);

        //lock the original bitmap in memory
        BitmapData originalData = original.LockBits(
           new Rectangle(0, 0, original.Width, original.Height),
           ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

        //lock the new bitmap in memory
        BitmapData newData = result.LockBits(
           new Rectangle(0, 0, original.Width, original.Height),
           ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

        //set the number of bytes per pixel
        int pixelSize = 4;

        int rthreshold = 128;
        int gthreshold = 128;
        int bthreshold = 128;

        for (int y = 0; y < original.Height; y++)
        {
            //get the data from the original image
            byte* oRow = (byte*)originalData.Scan0 + (y * originalData.Stride);

            //get the data from the new image
            byte* nRow = (byte*)newData.Scan0 + (y * newData.Stride);

            for (int x = 0; x < original.Width; x++)
            {
                //examine the rgb values
                byte r = (byte)((oRow[x * pixelSize]));
                byte g = (byte)((oRow[x * pixelSize + 1]));
                byte b = (byte)((oRow[x * pixelSize + 2]));
                byte a = (byte)((oRow[x * pixelSize + 3]));

                if (a > 0 && 
                    Math.Abs(remapColor.R - r) <= rthreshold &&
                    Math.Abs(remapColor.B - b) <= bthreshold &&
                    Math.Abs(remapColor.G - g) <= gthreshold 
                    )
                {
                    if (newColor.R == 0)
                    {
                        r = 0;
                    }
                    else
                    {
                        if (newColor.R > remapColor.R)
                            r = (byte)(r - newColor.R);
                        else
                            r = (byte)(r + newColor.R);
                    }

                    if (newColor.G == 0)
                    {
                        g = 0;
                    }
                    else
                    {
                        if (newColor.G > remapColor.G)
                            g = (byte)(g - newColor.G);
                        else
                            g = (byte)(g + newColor.G);
                    }

                    if (newColor.B == 0)
                    {
                        b = 0;
                    }
                    else
                    {
                        if (newColor.B > remapColor.B)
                            b = (byte)(b - newColor.B);
                        else
                            b = (byte)(b + newColor.B);
                    }
                }


                //set the new image's pixel remaped pixel color
                nRow[x * pixelSize] = b; //B
                nRow[x * pixelSize + 1] = g; //G
                nRow[x * pixelSize + 2] = r; //R
                nRow[x * pixelSize + 3] = a; //A
            }
        }

        original.UnlockBits(originalData);
        result.UnlockBits(newData);


        return result;
    }        

是什么给了......

我正在尝试做什么?

可靠吗?

我的代码中只有一个错误吗?

是否有更好的方法可以使用渐变在位图上实现这种“可重映射技术”?

感谢您的时间。

2 个答案:

答案 0 :(得分:0)

看起来您的阈值测试不正确。走线:

remapColor.R - r <= rthreshold

如果当前像素为白色,则r将为255,无论remapColor.Rrthreshold是什么,测试始终为真。

我认为Math.Abs(remapColor.R - r)可能有用。

你可能对你的字节值超出界限是正确的。修复阈值测试可能会阻止这种情况发生。否则,尝试检查一些边界以查看它发生的位置。

答案 1 :(得分:0)

我已经决定,如果我研究有关色彩空间及其支持理论的各种材料,这可能是可能的。看起来这需要比一些快速阈值计算和remapColor的标准化要多一些。

我建议不要在栅格位图图像上执行这种类型的修改,而是以矢量形式修改图形。

这个过程应该是这样的:

图形是在设计师工作的任何成像套件中创建的。

它们被保存为矢量格式,例如SVG这将允许使用SVG渲染引擎(http://svg.codeplex.com/)编程,遍历和更改可自定义路径(如果需要,可以更多颜色){/ 3}}

使用此解决方案,如果支持,我们可以直接将SVG输出到浏览器,并直接在客户端上进行修改,或者在需要时使用服务器并输出为PNG。

我觉得这种安排将为我们提供比我最初破解的更多灵活性和更强大的解决方案。

谢谢你们的时间!