C#图像处理程序实现--灰度处理以及Laplace处理 笔记整理2

上一篇博文对Laplace图像处理做了基本的阐述,但是由于使用的get和set方法,无疑无法提高图像处理的效率。这里使用另一种方式对其处理,就是最常用的并且是c#处理位图图像的重要:BitmapData ,对图像作进一步的处理。
首先来看一下bitmapData类的使用过程

在这里插入代码片
BitmapData sourceData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
byte[] pxielBuffer = new byte[sourceData.Stride * sourceData.Height];
Marshal.Copy(sourceData.Scan0, pxielBuffer, 0, pxielBuffer.Length);
bitmap.UnlockBits(sourceData);

这里关于BitmapData类的说明,论坛里有很多,这里可以看看这个博文的BitmapData类,这里不做过多的解释,参照以上的代码说几个需要注意的地方:
(1)使用时注意lockBits和unlockBits要配对使用,就是上锁和开锁要结合使用,记得释放资源。
(2)注意这里的ImagelockMode.ReadOnly,(这里这样的理解有问题,详细看第(4)条)这里是先将图片数据锁进内存中,然后把内存中的数据读出来,所以是ReadOnly,等到结尾,要把数据返回去的时候就要用ImagelockMode.WriteOnly,这两处是不一样的。
(3)使用该命令时要注意PixelFormat.Format32bppRgb,就是说这个图片是32位,还是24?16?8?因为这个参数影响着对后面编程时指针的偏移量,不然移错位了就没法显示了
(4)Marshal.Copy方法,这个刚学的是由尤其要注意,这里说一下我最开始的理解,但是不够严谨,因为数组只要实例化了,就都在内存中了,不存在复制到内存内外了!这里暂且这么帮助理解吧
我这里要复制出来的目标对象格式是byte[ ]的数组,在用的时候,一定要注意被Copy对象的格式,还有Copy目标的格式)。
还是参考一下Marshal.Copy的用法吧(怎么看?在软件界面中找到并左键Copy这个词,显示这个方法被选中,然后右键选择速览定义或者转到定义),如下图:
在这里插入图片描述
这里可以看到,Marshal.Copy的用法多达16种,刚学的新手一定要注意,Copy方法仅仅是一个复制命令,但是这个Copy相对于内存中的数据来说,是往内存中复制,还是往内存外复制,这两个过程对应的source和destination是不一样的,那用的时候就要注意要找对应的格式去套用。如果不注意,新手在照葫芦画瓢i的时候可能会一脸懵逼,一样的Copy方法,为啥前后用的时候里面的参数不一样。。。
(5)这里有一点要注意,要单独说一下,Stride,关于这个属性的说明,前面的博文链接中讲的很清楚,可以自行看,我们这里简单记一下,在bitmapdata类中用到的都是.Sride的属性,而不是.Width的属性。

基本上要注意的就这么多,下面我们来看一下具体的代码实现过程:

在这里插入代码片
​static Bitmap Laplace(Bitmap bitmap, int [,]filterMatrixOfLaplace, double factor = 1,int bias = 0)
        {
            StringBuilder sbsourcedata = new StringBuilder();

            BitmapData sourceData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
            byte[] pxielBuffer = new byte[sourceData.Stride * sourceData.Height];
            byte[] resultBuffer = new byte[sourceData.Stride * sourceData.Height];
            Marshal.Copy(sourceData.Scan0, pxielBuffer, 0, pxielBuffer.Length);
            bitmap.UnlockBits(sourceData);

            //将sourcedata数据显示出来
            sbsourcedata.Append(sourceData.ToString());
           // richTextBox1.Text = sbsourcedata.ToString();
            //将sourcedata数据显示出来
            float rgb = 0;
            for (int k = 0; k < pxielBuffer.Length; k += 4)
            {
                rgb = pxielBuffer[k] * 0.11f;
                rgb += pxielBuffer[k + 1] * 0.59f;
                rgb += pxielBuffer[k + 2] * 0.3f;

                pxielBuffer[k] = (byte)rgb;
                pxielBuffer[k + 1] = pxielBuffer[k];
                pxielBuffer[k + 2] = pxielBuffer[k];
                pxielBuffer[k + 3] = 255;
            }

            int filterWidth = filterMatrixOfLaplace.GetLength(1);
            int filterHeight = filterMatrixOfLaplace.GetLength(0);

            int filterOffset = (filterWidth - 1) / 2;
            int calcOffset = 0;

            int byteOfffset = 0;

            for (int offsetY = filterOffset; offsetY < bitmap.Height - filterOffset; offsetY++)
            {
                for (int offsetX = filterOffset; offsetX < bitmap.Width - filterOffset; offsetX++)
                {
                    double blue = 0;
                    double green = 0;
                    double red = 0;

                    byteOfffset = offsetY * sourceData.Stride + offsetX * 4;//将指针偏移到红点

                    for (int filterY = -filterOffset; filterY <= filterOffset; filterY++)
                    {
                        for (int filterX = -filterOffset; filterX <= filterOffset; filterX++)
                        {
                            //calcOffset = byteOfffset + filterX * 4 + filterY * sourceData.Stride;//将指针偏移到第一个蓝点
                            calcOffset = byteOfffset + (filterX * 4) + (filterY * sourceData.Stride);

                            blue += (double)(pxielBuffer[calcOffset]) * filterMatrixOfLaplace[filterY + filterOffset, filterX + filterOffset];
                            green += (double)(pxielBuffer[calcOffset + 1]) * filterMatrixOfLaplace[filterY + filterOffset, filterX + filterOffset];
                            red += (double)(pxielBuffer[calcOffset + 2]) * filterMatrixOfLaplace[filterY + filterOffset, filterX + filterOffset];

                        }
                    }

                    blue = blue * factor + bias;
                    green = green * factor + bias;
                    red = red * factor + bias;

                    if (blue < 0)
                    { blue = 0; }
                    else if (blue > 255)
                    { blue = 255; }

                    if (green > 255)
                    { green = 255; }
                    else if (green < 0)
                    { green = 0; }

                    if (red > 255)
                    { red = 255; }
                    else if (red < 0)
                    { red = 0; }


                    resultBuffer[byteOfffset] = (byte)blue;
                    resultBuffer[byteOfffset + 1] = (byte)green;
                    resultBuffer[byteOfffset + 2] = (byte)red;
                    resultBuffer[byteOfffset + 3] = 255;

                }
            }





            Bitmap resultBitmap = new Bitmap(bitmap.Width, bitmap.Height);
            BitmapData resultBitmapData = resultBitmap.LockBits(new Rectangle(0, 0, resultBitmap.Width, resultBitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb);
            Marshal.Copy(resultBuffer, 0, resultBitmapData.Scan0, resultBuffer.Length);
            resultBitmap.UnlockBits(resultBitmapData);
            return resultBitmap;
        }

我这里把使用bitmapData的过程写成了一个函数,这样在主程序中直接调用这个函数就可以了,这样做可以极大的精简主程序,同时也可以使程序变得更加灵活。
这里,代码的整个逻辑思维和前一篇博文的思维是一样的,做个说明如下:
在这里插入图片描述
以上博文代码我都附带发出来,大家可以相互交流学习。当然了,关于在C#中能够完成图像处理还有其他的方法,我们后续继续讨论

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值