C#中如何高性能地把图像转换成grayscale的

C#里把图片灰度化: 先是用以下代码, 能转换, 但经测试性能比较低, 在窗口中预览灰度化的采集视频, 相当卡顿, 这是因为在两重循环里大量调用GetPixel和SetPixel

        private Bitmap rgb2gray(Bitmap bm)
        {
            //Row-wise iteration through the Bitmap 
            for (int y = 0; y < bm.Height; y++)
            {
                for (int x = 0; x < bm.Width; x++)
                {
                    Color pixelColor = bm.GetPixel(x, y);
 
                    int pixelLuminance = (int)(pixelColor.R * 0.2126 + pixelColor.G * 0.7152 + pixelColor.B * 0.0722);
 
                    bm.SetPixel(x, y, Color.FromArgb(pixelLuminance, pixelLuminance, pixelLuminance));
                }//for
            }//for
 
            return bm;
        }//rgb2gray(Bitmap)

 

经搜索, 在http://stackoverflow.com/questions/1580130/high-speed-performance-of-image-filtering-in-c-sharp 里找到以下代码: 

public static void GrayScaleImage(Bitmap image)
{
    if (image == null)
        throw new ArgumentNullException("image");

    // lock the bitmap.
    var data = image.LockBits(
                  new Rectangle(0, 0, image.Width, image.Height), 
                  ImageLockMode.ReadWrite, image.PixelFormat);
    try
    {
        unsafe
        {
            // get a pointer to the data.
            byte* ptr = (byte*)data.Scan0;

            // loop over all the data.
            for (int i = 0; i < data.Height; i++)
            {
                for (int j = 0; j < data.Width; j++)
                {
                    // calculate the gray value.
                    byte y = (byte)(
                        (0.299 * ptr[2]) + 
                        (0.587 * ptr[1]) + 
                        (0.114 * ptr[0]));

                    // set the gray value.
                    ptr[0] = ptr[1] = ptr[2] = y;

                    // increment the pointer.
                    ptr += 3;
                }

                // move on to the next line.
                ptr += data.Stride - data.Width * 3;
            }
        }
    }
    finally
    {
        // unlock the bits when done or when 
        // an exception has been thrown.
        image.UnlockBits(data);
    }
}

 

 改用以上代码, 经测试, 性能可以, 但是处理后的图片有些问题, 左边的大部分灰度化的区域有栅格, 右边有一小段区域没有灰度化.  这当然难不倒老杨,  老杨感觉是ptr指向的索引不正确的问题,  参考了下其他代码(https://github.com/baobaohuang/Graphic_gray/blob/cd1d9b543762c23a8fc232e21f8de15dd810e8b2/gray/Program.cs  , 这个也可以工作, 性能高于最初的代码,但低于上面的代码),  修正代码如下: 

        public static void GrayScaleImage(Bitmap image)
        {
            if (image == null)
                throw new ArgumentNullException("image");

            // lock the bitmap.
            var data = image.LockBits(
                          new Rectangle(0, 0, image.Width, image.Height),
                          ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            try
            {
                unsafe
                {
                    // get a pointer to the data.
                    byte* ptr = (byte*)data.Scan0;

                    // loop over all the data.
                    for (int i = 0; i < data.Height; i++)
                    {
                        ptr = (byte*)data.Scan0 + i*data.Stride;
                        for (int j = 0; j < data.Width; j++)
                        {
                            // calculate the gray value.
                            byte y = (byte)(
                                (0.299 * ptr[2]) +
                                (0.587 * ptr[1]) +
                                (0.114 * ptr[0]));

                            // set the gray value.
                            ptr[0] = ptr[1] = ptr[2] = y;

                            // increment the pointer.
                            ptr += 3;
                        }

                    }
                }
            }
            finally
            {
                // unlock the bits when done or when 
                // an exception has been thrown.
                image.UnlockBits(data);
            }
        }

 

最后测试, 以上代码效果perfect !  不过后来发现, 其实两段代码的处理ptr的方式都一样可以, 主要是

var data = image.LockBits(
                          new Rectangle(0, 0, image.Width, image.Height),
                          ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

 这里必须用PixelFormat.Format24bppRgb

在C++,利用VTK库(Visualization Toolkit)处理多帧灰度图像并将其转换为RGB图像,首先你需要确保每个灰度图像是一系列连续的帧,每帧都是单通道(通常是灰度)。VTK本身不直接支持图像序列的操作,但你可以结合其他库如ITK(Insight Toolkit)或OpenCV来辅助处理。 以下是一种可能的做法,假设你已经有了一个灰度图像序列作为vtkImageData对象: 1. **读取灰度图像**: 使用VTK的`vtkSmartPointer<vtkImageReader>`从文件或内存读取灰度图像序列。 2. **获取图像信息**: 获得图像的宽度、高度和帧数等属性。 3. **创建RGB图像**: 创建一个与原图像同样大小的新vtkImageData对象,用于存储RGB数据。这里每个像素将包含三个分量(红、绿、蓝)。 4. **逐帧转换**: 使用循环遍历每一帧,将灰度图像的单通道数据复制到RGB图像的对应位置。例如,对于第一个像素,将第一帧灰度数据分别分配给红色、绿色和蓝色分量。 ```cpp void grayscaleToRGB(vtkSmartPointer<vtkImageData> grayscale, vtkSmartPointer<vtkImageData>& rgb) { int width = grayscale->GetWidth(); int height = grayscale->GetHeight(); int numFrames = grayscale->GetNumberOfScalarComponents(); // 遍历每一帧 for (int frame = 0; frame < numFrames; ++frame) { double* grayData = grayscale->GetScalarPointer(0, 0, frame); double* rgbData = rgb->GetScalarPointer(0, 0, frame * 3); // RGB图像每帧是三倍灰度帧 for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { rgbData[frame * width * height + y * width + x] = grayData[y * width + x]; // 将灰度值复制到红色 rgbData[frame * width * height + y * width + x + 1] = grayData[y * width + x]; // 到绿色和蓝色 } } } // 根据需求设置RGB图像的通道数 rgb->SetNumberOfScalarComponents(3); } ``` 注意这只是一个基本示例,实际应用可能还需要考虑错误检查和性能优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值