原图:
背景图:
C#代码相减后的图像:
核心函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
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; } |
调用示例:
1 2 3 4 5 6 |
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); } |