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

发布于 2024-09-09 12:17:07 字数 4439 浏览 0 评论 0原文

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

我的代码存在的问题如下:

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

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

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

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

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

freeimagehosting.net/uploads/fa48e5a0eb.png(用颜色调用.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 调用,似乎白色像素受到影响,并且没有正确计算渐变)

我对此代码的函数如下:< em>根据建议更新

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;
    }        

什么给出了......

我想做的事情可能吗?

可靠吗?

我的代码中是否存在错误?

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

感谢您抽出时间。

I have small function which will recolor pixels in a Bitmap from a given color to a new given color.

The problems I have with the code are as follows:

1)
The function gives results which are remapping white pixels which should not be concidered since I have a threshold... (unless I have defined this calculation wrong)

2) When certain colors are given e.g. LimeGreen wierd results are seen in the image returned from the function (I beleive this is due to overflow of the byte type in the addition or subtraction case)

The base image I am using can be found here:

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

Results I have obtained can be found here:

freeimagehosting.net/uploads/fa48e5a0eb.png (Called with Color.Magenta as remapColor, Color.Red as newColor, Seems like white pixels are effected and the end of the gradient is not colored correctly)

freeimagehosting.net/uploads/8faec6a569.png (Called with Color.Magenta as remapColor, Color.Yellow as newColor, Seems like white pixels are effected and the end of the gradient is not colored correctly)

freeimagehosting.net/uploads/2efd4c04aa.png (Called with Color.Magenta as remapColor, Color.Blue as newColor, Seems like gradient not colored correctly)

freeimagehosting.net/uploads/defdf04e16.png (Called with Color.Magenta as remapColor, Color.Teal as newColor, Seems like white pixels are effected and none of the gradient is calculated correctly)

The function I have for this code is below: UPDATED per suggestions

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;
    }        

What gives....

Is what I am trying to do possible?

Is it reliable?

Is there just a bug in my code?

Is there a better way to achive this "re-mapable technique" on bitmaps using gradients?

Thank you for your time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

紧拥背影 2024-09-16 12:17:11

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

我建议不要对光栅位图图像执行此类修改,而是以矢量形式修改图形。

该过程应该是这样的:

图形是在设计人员正在使用的任何成像套件中创建的。

它们被保存为矢量格式,例如 SVG,这将允许以编程方式命名、遍历和更改可定制的路径(并且超过使用 SVG 渲染引擎(http://svg.codeplex.com/

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

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

谢谢你们抽出时间!

I have decided that although this may be possible if I study the various materials regarding color spaces and their supporting theories. It seems that this will take a bit more than some quick threshold calculation and normalization to the remapColor.

I am going to propose that instead of performing this type of modification on a raster bitmap image that the graphics be modified in their vector form.

The process should be something like this:

The graphics are created in whatever imaging suite the designer is working in.

They are saved to a vector format e.g. SVG this will allow the customizable paths to be named, traversed and altered programmatically (and for more than color if needed) with SVG Rendering Engine(http://svg.codeplex.com/)

With this solution we can either output the SVG direct to the browser if supported and do the modifications directly on the client or use the server and output as PNG when needed.

I feel that this arrangement will provide us with more flexibility and a more robust solution than what I was initially going to hack together.

Thank you guys for your time!

高跟鞋的旋律 2024-09-16 12:17:10

您的阈值测试似乎不正确。就拿这句话来说吧:

remapColor.R - r <= rthreshold

如果当前像素是白色,那么 r 将为 255,并且无论 remapColor.Rrthreshold 是什么,测试都将始终为 true 是。

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

您的字节值越界的说法可能是正确的。修复阈值测试可能会阻止这种情况发生。否则,尝试进行一些边界检查以查看发生的情况。

It looks like your threshold test is incorrect. Take the line:

remapColor.R - r <= rthreshold

If the current pixel is white, then r will be 255, and the test will always be true, no matter what remapColor.R and rthreshold are.

I think Math.Abs(remapColor.R - r) might work.

And you're likely correct about your byte values being out of bounds. Fixing the threshold test might stop that from happening. Otherwise, try putting some bounds checking in to see where it's happening.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文