Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 这种深褐色色调转换算法有什么问题?_C#_.net_Colors - Fatal编程技术网

C# 这种深褐色色调转换算法有什么问题?

C# 这种深褐色色调转换算法有什么问题?,c#,.net,colors,C#,.net,Colors,我似乎有一种几乎正常工作的深褐色色调。由于某种原因,图像的一部分变成了灰绿色!有人知道我可能做错了什么吗?方法发布在下面 private void SepiaBitmap(Bitmap bmp) { Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Ima

我似乎有一种几乎正常工作的深褐色色调。由于某种原因,图像的一部分变成了灰绿色!有人知道我可能做错了什么吗?方法发布在下面

private void SepiaBitmap(Bitmap bmp)
{
    Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
    System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
        System.Drawing.Imaging.PixelFormat.Format32bppRgb);

    IntPtr ptr = bmpData.Scan0;

    int numPixels = bmpData.Width * bmp.Height;
    int numBytes = numPixels * 4;
    byte[] rgbValues = new byte[numBytes];

    System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, numBytes);
    for (int i = 0; i < rgbValues.Length; i += 4)
    {
        rgbValues[i + 2] = (byte)((.393 * rgbValues[i + 2]) + (.769 * rgbValues[i + 1]) + (.189 * (rgbValues[i + 0]))); //red
        rgbValues[i + 1] = (byte)((.349 * rgbValues[i + 2]) + (.686 * rgbValues[i + 1]) + (.168 * (rgbValues[i + 0]))); //green
        rgbValues[i + 0] = (byte)((.272 * rgbValues[i + 2]) + (.534 * rgbValues[i + 1]) + (.131 * (rgbValues[i + 0]))); //blue

        if ((rgbValues[i + 2]) > 255)
        {
            rgbValues[i + 2] = 255; 
        }

        if ((rgbValues[i + 1]) > 255)
        {
            rgbValues[i + 1] = 255;
        }
        if ((rgbValues[i + 0]) > 255)
        {
            rgbValues[i + 0] = 255;
        }
    }

    System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, numBytes);
    this.Invalidate();
    bmp.UnlockBits(bmpData);

}
private void SepiaBitmap(位图bmp)
{
矩形rect=新矩形(0,0,bmp.Width,bmp.Height);
System.Drawing.Imaging.BitmapData bmpData=bmp.LockBits(rect、System.Drawing.Imaging.ImageLockMode.ReadWrite、,
系统。绘图。成像。像素格式。格式32bpprgb);
IntPtr ptr=bmpData.Scan0;
int numPixels=bmpData.Width*bmp.Height;
int numBytes=numPixels*4;
字节[]rgbValues=新字节[numBytes];
System.Runtime.InteropServices.Marshal.Copy(ptr,rgbvalue,0,numBytes);
for(int i=0;i255)
{
RGB值[i+2]=255;
}
如果((RGB值[i+1])>255)
{
RGB值[i+1]=255;
}
如果((RGB值[i+0])>255)
{
RGB值[i+0]=255;
}
}
System.Runtime.InteropServices.Marshal.Copy(rgbvalue,0,ptr,numBytes);
这个。使无效();
bmp.UnlockBits(bmpData);
}

您的值正在溢出和环绕

您试图用
(rgbValues[i+0])>255
来防止这种情况发生的尝试没有任何效果,因为
字节[]
无论如何都不能存储超过255的值,因此一旦您将值放入
rgbValues
中,这些值就会溢出并被包装。在将它们存储到阵列中之前,需要先夹紧它们。C#有一个函数
Math.Min()
,非常适合这个用途

另一方面,考虑到溢出,您可能首先要解决这个问题-钳制会产生“过度曝光”效果(因为过度曝光就是钳制),这可能是不需要的。调整你的系数,使你改变颜色,但不改变(感知)亮度(我没有这方面的参考,对不起)

作为一个完全独立的问题,@Yacoder指出,您的第一行修改了第二行使用的输入,依此类推,因此您的计算将被关闭。您需要在临时变量中输入三个输入或三个输出


您可能还想了解
System.Drawing.Imaging
是否具有颜色矩阵图像转换操作,因为这是您在这里手工完成的操作,并且系统提供的版本可能会更快。(我不知道C,所以我不能对此发表评论。)

要解决此问题,请按如下方式更改循环:

for (int i = 0; i < rgbValues.Length; i += 4)
{
    int red = rgbValues[i + 2];
    int green = rgbValues[i + 1];
    int blue = rgbValues[i + 0];

    rgbValues[i + 2] = (byte)Math.Min((.393 * red) + (.769 * green) + (.189 * blue), 255.0); // red
    rgbValues[i + 1] = (byte)Math.Min((.349 * red) + (.686 * green) + (.168 * blue), 255.0); // green
    rgbValues[i + 0] = (byte)Math.Min((.272 * red) + (.534 * green) + (.131 * blue), 255.0); // blue
}
for(int i=0;i

在计算中会出现算术溢出,这就是错误颜色的原因。类型为
double
的表达式在与255进行比较之前显式转换为
byte
,因此它永远不会大于255。

您的算法中有两个问题(至少,如果您遵循中的算法描述)

首先,正如其他人指出的,存在字节类型溢出。 其次,所有输出颜色值必须基于输入颜色值,而不是按顺序计算

以下是固定的主循环代码:

        for (int i = 0; i < rgbValues.Length; i += 4)
        {
            int inputRed = rgbValues[i + 2];
            int inputGreen = rgbValues[i + 1];
            int inputBlue = rgbValues[i + 0];

            rgbValues[i + 2] = (byte) Math.Min(255, (int)((.393 * inputRed) + (.769 * inputGreen) + (.189 * inputBlue))); //red
            rgbValues[i + 1] = (byte) Math.Min(255, (int)((.349 * inputRed) + (.686 * inputGreen) + (.168 * inputBlue))); //green
            rgbValues[i + 0] = (byte) Math.Min(255, (int)((.272 * inputRed) + (.534 * inputGreen) + (.131 * inputBlue))); //blue
        }

请不要在标题前加上“C#”之类的前缀。这就是这些标签的作用。@KevinReid抱歉,发布这些标签有点慢!您可以使用
255.0
来明确说明255是双精度的。@YuriyGuts:我不想让它成为双精度的,我想把255从整数类型转换成字节,所以我可以相信转换在字节范围内。这是不完整的,不会产生深褐色的图像。每个颜色分量都需要单独转换,见我的答案。啊,是的,你是对的。对不起,我第一次没注意到。我编辑了我的答案,更正为+1:)
namespace ConsoleApplication8_Sepia
{
    using System;
    using System.Drawing;
    using System.Drawing.Imaging;

    class Program
    {
        static void Main(string[] args)
        {
            Bitmap b = (Bitmap)Bitmap.FromFile("c:\\temp\\source.jpg");
            SepiaBitmap(b);
            b.Save("c:\\temp\\destination.jpg", ImageFormat.Jpeg);
        }

        private static void SepiaBitmap(Bitmap bmp)
        {
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);
            IntPtr ptr = bmpData.Scan0;

            int numPixels = bmpData.Width * bmp.Height;
            int numBytes = numPixels * 4;
            byte[] rgbValues = new byte[numBytes];

            System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, numBytes);
            for (int i = 0; i < rgbValues.Length; i += 4)
            {
                int inputRed = rgbValues[i + 2];
                int inputGreen = rgbValues[i + 1];
                int inputBlue = rgbValues[i + 0];

                rgbValues[i + 2] = (byte)Math.Min(255, (int)((.393 * inputRed) + (.769 * inputGreen) + (.189 * inputBlue))); //red
                rgbValues[i + 1] = (byte)Math.Min(255, (int)((.349 * inputRed) + (.686 * inputGreen) + (.168 * inputBlue))); //green
                rgbValues[i + 0] = (byte)Math.Min(255, (int)((.272 * inputRed) + (.534 * inputGreen) + (.131 * inputBlue))); //blue
            }

            System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, numBytes);
            bmp.UnlockBits(bmpData);
        }
    }
}