C# 图像相减(指针法、高速)
1.请参考 C#图片的像素格式问题研究
2.请参考 C# 指针操作图像
3.图像减法核心函数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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; }
4. Demo
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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); }
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#图像相减代码正确