C# 图像相减(指针法、高速)

1.请参考 C#图片的像素格式问题研究 

2.请参考 C# 指针操作图像

3.图像减法核心函数

        protected unsafe Bitmap ImageDifference(Bitmap imageT, Bitmap overlayT, int Threshold)
        {
            if (Threshold < 0) Threshold = 0;
            #region 图像相减
            PixelFormat pixelFormat = imageT.PixelFormat;
            // get image dimension
            int width = imageT.Width;
            int height = imageT.Height;
            Rectangle rect = new Rectangle(0, 0, width, height);
            BitmapData image = new BitmapData(); BitmapData overlay = new BitmapData();
            image = imageT.LockBits(rect, ImageLockMode.ReadWrite, pixelFormat);
            overlay = overlayT.LockBits(rect, ImageLockMode.ReadWrite, pixelFormat);
            // pixel value
            int[,] M = new int[height, width];//存放相减阈值后的数据
            int inttemp = 0;
            //初始化各项数组
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    M[i, j] = 0;
                }
            }

            if (
                (pixelFormat == PixelFormat.Format8bppIndexed) ||
                (pixelFormat == PixelFormat.Format24bppRgb) ||
                (pixelFormat == PixelFormat.Format32bppRgb) ||
                (pixelFormat == PixelFormat.Format32bppArgb))
            {
                // initialize other variables
                int pixelSize = (pixelFormat == PixelFormat.Format8bppIndexed) ? 1 :
                    (pixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4;
                int lineSize = width * pixelSize;
                int srcOffset = image.Stride - lineSize;
                int ovrOffset = overlay.Stride - lineSize;

                // do the job
                byte* ptr = (byte*)image.Scan0.ToPointer();
                byte* ovr = (byte*)overlay.Scan0.ToPointer();

                // for each line
                for (int y = 0; y < height; y++)
                {
                    // for each pixel
                    for (int x = 0; x < lineSize; x++, ptr += pixelSize, ovr += pixelSize)
                    {
                        // abs(sub)
                        inttemp = (int)*ptr - (int)*ovr;
                        M[y, x] = (inttemp < Threshold) ? (byte)0 : (byte)inttemp;//阈值TH处理
                    }
                    ptr += srcOffset;
                    ovr += ovrOffset;
                }
            }
            else
            {
                // initialize other variables
                int pixelSize = (pixelFormat == PixelFormat.Format16bppGrayScale) ? 1 :
                    (pixelFormat == PixelFormat.Format48bppRgb) ? 3 : 4;
                int lineSize = width * pixelSize;
                int srcStride = image.Stride;
                int ovrStride = overlay.Stride;

                // do the job
                byte* basePtr = (byte*)image.Scan0.ToPointer();
                byte* baseOvr = (byte*)overlay.Scan0.ToPointer();

                // for each line
                for (int y = 0; y < height; y++)
                {
                    ushort* ptr = (ushort*)(basePtr + y * srcStride);
                    ushort* ovr = (ushort*)(baseOvr + y * ovrStride);

                    // for each pixel
                    for (int x = 0; x < lineSize; x++, ptr++, ovr++)
                    {
                        // abs(sub)
                        inttemp = (int)*ptr - (int)*ovr;
                        M[y, x] = (inttemp < Threshold) ? (byte)0 : (byte)inttemp;//阈值TH处理
                    }
                }
            }
#endregion
            #region 数据矩阵转为灰度图像
            // 8bit索引方式位图,设置灰度调色板
            var fmt = PixelFormat.Format8bppIndexed;
            var bmp = new Bitmap(width, height, fmt);
            var palette = bmp.Palette;
            for (var i = 0; i < 256; i++)
            {
                palette.Entries[i] = Color.FromArgb(i, i, i);
            }
            bmp.Palette = palette;

            // 把数据映射到256灰度,unsafe填充到位图
            var step = 255f / (256 - 1);
            var bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, fmt);
            unsafe
            {
                var p = (byte*)bmpData.Scan0;
                for (var i = 0; i < M.GetLength(0); i++)
                {
                    for (var j = 0; j < M.GetLength(1);j++ )
                    {
                        *p = (byte)(step * M[i,j]);
                        p++;
                    }
                }
            }
            bmp.UnlockBits(bmpData);
            //bmp.Save(@"e:\x.png");
            #endregion
            return bmp;
        }
View Code

4. Demo

        private void button4_Click(object sender, EventArgs e)
        {
            Bitmap image = new Bitmap(System.Environment.CurrentDirectory + "\\ImageStore\\I.png");
            Bitmap bg = new Bitmap(System.Environment.CurrentDirectory + "\\ImageStore\\B.png");
            pictureBox1.Image = ImageDifference(image, bg, 0);
        }
View Code

5. 程序校验部分

采用MATLAB进行校验

原图:

背景图:

C#代码相减后的图像:

利用MATLAB做图像减法:

代码如下:

I=imread('I.png');
B=imread('B.png');
M = I-B;
figure;imshow(M);
X=imread('x.png');

减法后的图像:

 

对比两个图片的 

max(max(M-X))

ans =

    0

所以,校对完毕。C#图像相减代码正确

posted on 2017-04-20 14:50  小圈子  阅读(1057)  评论(1编辑  收藏  举报

导航