首先根据图片进行裁剪 得到有用的数据
1 public static int[,] RGB2Gray(Bitmap srcBitmap) 2 { 3 4 int wide = srcBitmap.Width; 5 6 int height = srcBitmap.Height; 7 8 Rectangle rect = new Rectangle(0, 0, wide, height); 9 10 // 将Bitmap锁定到系统内存中, 获得BitmapData 11 12 BitmapData srcBmData = srcBitmap.LockBits(rect, 13 14 ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); 15 16 //创建Bitmap 17 18 Bitmap dstBitmap = CreateGrayscaleImage(wide, height);//这个函数在后面有定义 19 20 BitmapData dstBmData = dstBitmap.LockBits(rect, 21 22 ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed); 23 24 // 位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行 25 26 System.IntPtr srcPtr = srcBmData.Scan0; 27 28 System.IntPtr dstPtr = dstBmData.Scan0; 29 30 // 将Bitmap对象的信息存放到byte数组中 31 32 int src_bytes = srcBmData.Stride * height; 33 34 byte[] srcValues = new byte[src_bytes]; 35 36 int dst_bytes = dstBmData.Stride * height; 37 38 byte[] dstValues = new byte[dst_bytes]; 39 40 //复制GRB信息到byte数组 41 42 System.Runtime.InteropServices.Marshal.Copy(srcPtr, srcValues, 0, src_bytes); 43 44 System.Runtime.InteropServices.Marshal.Copy(dstPtr, dstValues, 0, dst_bytes); 45 46 int unm = 365; 47 // 根据Y=0.299*R+0.114*G+0.587B,Y为亮度 48 int[,] imgData = new int[wide, height - 365 - 37]; 49 50 for (int i = 365; i < height - 37; i++) 51 52 for (int j = 0; j < wide; j++) 53 54 { 55 56 //只处理每行中图像像素数据,舍弃未用空间 57 58 //注意位图结构中RGB按BGR的顺序存储 59 60 int k = 3 * j; 61 62 double temp = srcValues[i * srcBmData.Stride + k + 1];// (double)(srcValues[i * srcBmData.Stride + k + 2] * .299 63 64 //+ srcValues[i * srcBmData.Stride + k + 1] * .587 + srcValues[i * srcBmData.Stride + k] * .114); 65 66 dstValues[i * dstBmData.Stride + j] = (byte)temp; 67 //imgData[j,i,0] = srcValues[i * srcBmData.Stride + k + 2]; 68 imgData[j, i - 365] = srcValues[i * srcBmData.Stride + k + 1]; 69 //imgData[j, i, 2] = srcValues[i * srcBmData.Stride + k ]; 70 } 71 72 //将更改过的byte[]拷贝到原位图 73 74 System.Runtime.InteropServices.Marshal.Copy(dstValues, 0, dstPtr, dst_bytes); 75 76 77 78 // 解锁位图 79 80 srcBitmap.UnlockBits(srcBmData); 81 82 dstBitmap.UnlockBits(dstBmData); 83 dstBitmap.Save("1.jpg"); 84 return imgData; 85 86 87 88 }//# 89 public static Bitmap CreateGrayscaleImage(int width, int height) 90 91 { 92 93 // create new image 94 95 Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed); 96 97 // set palette to grayscale 98 99 // check pixel format 100 101 if (bmp.PixelFormat != PixelFormat.Format8bppIndexed) 102 103 throw new ArgumentException(); 104 105 106 107 // get palette 108 109 ColorPalette cp = bmp.Palette; 110 111 // init palette 112 113 for (int i = 0; i < 256; i++) 114 115 { 116 117 cp.Entries[i] = Color.FromArgb(i, i, i); 118 119 } 120 121 // set palette back 122 123 bmp.Palette = cp; 124 125 // return new image 126 127 return bmp; 128 129 }//# 130
然后对其进行调用
1 private void setImgData() 2 { 3 try 4 { 5 Bitmap img = new Bitmap(imgname); 6 int wide = img.Width; 7 int height = img.Height - 365 - 37; 8 9 var data1 = RGB2Gray(img); 10 var val = CalcRec.GetLimetImage(data1, valColor, valContinuou); //返回缺陷级别 11 string isokstr = "正常"; 12 switch (val) 13 { 14 case 0: 15 isokstr = "正常"; 16 break; 17 case 1: 18 isokstr = "裂纹"; 19 break; 20 case 2: 21 isokstr = "焊缝"; 22 break; 23 default: 24 isokstr = "未知"; 25 break; 26 } 27 label_res.Text = isokstr; 28 int ii = 0; 29 30 for (int i = 0; i < wide; i++) 31 { 32 33 for (int j = 0; j < height; j++) 34 { 35 uint setColor = 0; 36 if (data1[i, j] == 0) 37 { 38 setColor = (uint)ColorTranslator.ToOle(Color.FromArgb(0, 0, 200)); 39 } 40 else 41 { 42 int color = PraseColor((data1[i, j])); 43 setColor = (uint)ColorTranslator.ToOle(Color.FromArgb(color, color, 0));// PraseColor(data1[i, j]); 44 } 45 axTChart9.Series(0).asSurface.AddXYZ(i, data1[i, j], j, "", setColor); //向Tower序列中添加数据 46 } 47 ii++; 48 if (ii > 1000) 49 { 50 ii = 0; 51 Application.DoEvents(); 52 } 53 } 54 55 56 } 57 catch (Exception pe) 58 { 59 60 throw pe; 61 } 62 } 63 64 private int PraseColor(int v) 65 { 66 int input_start = valColor; //最低数量范围的输入。 67 int input_end = 255; //最低数量范围的输入。 68 int out_start = 10; //编号最小的范围内输出。 69 int out_end = 255; //范围输出中人数最多的。INT输入= 127; //输入值。 70 int res = 0; 71 if (v > 0) 72 { 73 res = (out_start + ((out_end - out_start) / (input_end - input_start)) * (v - input_start)); 74 } 75 76 return res; 77 } 78 private float PraseColor(double v, int inputEnd) 79 { 80 float input_start = 0; //最低数量范围的输入。 81 float input_end = 5000f; //最低数量范围的输入。 82 float out_start = 0f; //编号最小的范围内输出。 83 float out_end = 255f; //范围输出中人数最多的。INT输入= 127; //输入值。 84 float res = 0; 85 if (v > 1000) 86 { 87 res = (out_start + ((out_end - out_start) / (input_end - input_start)) * ((int)v - input_start)); 88 } 89 90 return res; 91 } 92
其中关键是 这个方法 对数据进行处理 GetLimetImage 对图像的相关 R G B 中的一层进行 判断
这个方法的逻辑是
1 public static int GetLimetImage(int[,] imageGreen, int a1, int a2) 2 { 3 List<int> coumindex = new List<int>(); 4 HashSet<int> y = new HashSet<int>(); 5 for (int i = 0; i < imageGreen.GetLength(0); i++) 6 { 7 int gcontiu = 0; 8 int contiu = 0; 9 for (int j = 0; j < imageGreen.GetLength(1); j++) 10 { 11 imageGreen[i, j] = -imageGreen[i, j] + 255; 12 if (imageGreen[i, j] < a1) 13 { 14 imageGreen[i, j] = 0; 15 } 16 else 17 { 18 contiu++; 19 if (contiu == a2) 20 { 21 gcontiu++; 22 23 } 24 } 25 } 26 if (gcontiu == 0) 27 { 28 for (int k = 0; k < imageGreen.GetLength(1); k++) 29 { 30 imageGreen[i, k] = 0; 31 } 32 } 33 else 34 { 35 coumindex.Add(i); 36 for (int j = 0; j < imageGreen.GetLength(1); j++) 37 { 38 if (imageGreen[i, j] != 0) 39 { 40 y.Add(j); 41 } 42 } 43 } 44 } 45 int p = coumindex.Count >0?1:0; 46 for (int i = 0; i < coumindex.Count - 1; i++) 47 { 48 if (coumindex[i + 1] - coumindex[i] != 1) 49 { 50 p++; 51 } 52 } 53 54 var Val = 0; 55 if (coumindex.Count == 0|| y.Count==0) { 56 return Val; 57 } 58 if (p == 1) { 59 Val = 1; 60 } else { 61 long allpoint = 0; 62 int[,] allpointDel = new int[coumindex.Count, y.Count]; 63 64 for (int i = 0; i < coumindex.Count; i++) 65 { 66 for (int j = 0; j < y.Count; j++) 67 { 68 allpointDel[i, j] = imageGreen[coumindex[i], y.ElementAt(j)]; 69 allpoint = allpoint + imageGreen[coumindex[i], y.ElementAt(j)]; 70 } 71 } 72 var mevn = allpoint / (coumindex.Count * y.Count * 1.0); 73 if (mevn < 40) { 74 Val = 0; 75 } else { 76 Val = 2; 77 } 78 } 79 return Val; 80 }
上图是MatLab 的mesh 下图是 TeeChar2017
直接调用的class
1 using System; 2 using System.Collections.Generic; 3 using System.Drawing; 4 using System.Drawing.Imaging; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace ConsoleApplication1 10 { 11 12 13 public class CalcRec 14 { 15 static int valColor = 150; 16 static int valContinuou = 15; 17 static string imgname = "2.png"; 18 19 public static void setImgData() 20 { 21 try 22 { 23 24 Bitmap img = new Bitmap(imgname); 25 int wide = img.Width; 26 int height = img.Height - 365 - 37; 27 28 var data1 = RGB2Gray(img); 29 var val = CalcRec.GetLimetImage(data1, valColor, valContinuou); //返回缺陷级别 30 string isokstr = "正常"; 31 switch (val) 32 { 33 case 0: 34 isokstr = "正常"; 35 break; 36 case 1: 37 isokstr = "裂纹"; 38 break; 39 case 2: 40 isokstr = "焊缝"; 41 break; 42 default: 43 isokstr = "未知"; 44 break; 45 } 46 //label_res.Text = isokstr; 47 int ii = 0; 48 49 //for (int i = 0; i < wide; i++) 50 //{ 51 52 // for (int j = 0; j < height; j++) 53 // { 54 // uint setColor = 0; 55 // if (data1[i, j] == 0) 56 // { 57 // setColor = (uint)ColorTranslator.ToOle(Color.FromArgb(0, 0, 200)); 58 // } 59 // else 60 // { 61 // int color = PraseColor((data1[i, j])); 62 // setColor = (uint)ColorTranslator.ToOle(Color.FromArgb(color, color, 0));// PraseColor(data1[i, j]); 63 // } 64 // axTChart9.Series(0).asSurface.AddXYZ(i, data1[i, j], j, "", setColor); //向Tower序列中添加数据 65 // } 66 // ii++; 67 // if (ii > 1000) 68 // { 69 // ii = 0; 70 // Application.DoEvents(); 71 // } 72 //} 73 74 75 } 76 catch (Exception pe) 77 { 78 79 throw pe; 80 } 81 } 82 public static int[,] RGB2Gray(Bitmap srcBitmap) 83 { 84 85 int wide = srcBitmap.Width; 86 87 int height = srcBitmap.Height; 88 89 Rectangle rect = new Rectangle(0, 0, wide, height); 90 91 // 将Bitmap锁定到系统内存中, 获得BitmapData 92 93 BitmapData srcBmData = srcBitmap.LockBits(rect, 94 95 ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); 96 97 //创建Bitmap 98 99 Bitmap dstBitmap = CreateGrayscaleImage(wide, height);//这个函数在后面有定义 100 101 BitmapData dstBmData = dstBitmap.LockBits(rect, 102 103 ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed); 104 105 // 位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行 106 107 System.IntPtr srcPtr = srcBmData.Scan0; 108 109 System.IntPtr dstPtr = dstBmData.Scan0; 110 111 // 将Bitmap对象的信息存放到byte数组中 112 113 int src_bytes = srcBmData.Stride * height; 114 115 byte[] srcValues = new byte[src_bytes]; 116 117 int dst_bytes = dstBmData.Stride * height; 118 119 byte[] dstValues = new byte[dst_bytes]; 120 121 //复制GRB信息到byte数组 122 123 System.Runtime.InteropServices.Marshal.Copy(srcPtr, srcValues, 0, src_bytes); 124 125 System.Runtime.InteropServices.Marshal.Copy(dstPtr, dstValues, 0, dst_bytes); 126 127 int unm = 365; 128 // 根据Y=0.299*R+0.114*G+0.587B,Y为亮度 129 int[,] imgData = new int[wide, height - 365 - 37]; 130 131 for (int i = 365; i < height - 37; i++) 132 133 for (int j = 0; j < wide; j++) 134 135 { 136 137 //只处理每行中图像像素数据,舍弃未用空间 138 139 //注意位图结构中RGB按BGR的顺序存储 140 141 int k = 3 * j; 142 143 double temp = srcValues[i * srcBmData.Stride + k + 1];// (double)(srcValues[i * srcBmData.Stride + k + 2] * .299 144 145 //+ srcValues[i * srcBmData.Stride + k + 1] * .587 + srcValues[i * srcBmData.Stride + k] * .114); 146 147 dstValues[i * dstBmData.Stride + j] = (byte)temp; 148 //imgData[j,i,0] = srcValues[i * srcBmData.Stride + k + 2]; 149 imgData[j, i - 365] = srcValues[i * srcBmData.Stride + k + 1]; 150 //imgData[j, i, 2] = srcValues[i * srcBmData.Stride + k ]; 151 } 152 153 //将更改过的byte[]拷贝到原位图 154 155 System.Runtime.InteropServices.Marshal.Copy(dstValues, 0, dstPtr, dst_bytes); 156 157 158 159 // 解锁位图 160 161 srcBitmap.UnlockBits(srcBmData); 162 163 dstBitmap.UnlockBits(dstBmData); 164 dstBitmap.Save("1.jpg"); 165 return imgData; 166 167 168 169 }//# 170 public static Bitmap CreateGrayscaleImage(int width, int height) 171 172 { 173 174 // create new image 175 176 Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed); 177 178 // set palette to grayscale 179 180 // check pixel format 181 182 if (bmp.PixelFormat != PixelFormat.Format8bppIndexed) 183 184 throw new ArgumentException(); 185 186 187 188 // get palette 189 190 ColorPalette cp = bmp.Palette; 191 192 // init palette 193 194 for (int i = 0; i < 256; i++) 195 196 { 197 198 cp.Entries[i] = Color.FromArgb(i, i, i); 199 200 } 201 202 // set palette back 203 204 bmp.Palette = cp; 205 206 // return new image 207 208 return bmp; 209 210 }//# 211 private int PraseColor(int v) 212 { 213 int input_start = valColor; //最低数量范围的输入。 214 int input_end = 255; //最低数量范围的输入。 215 int out_start = 10; //编号最小的范围内输出。 216 int out_end = 255; //范围输出中人数最多的。INT输入= 127; //输入值。 217 int res = 0; 218 if (v > 0) 219 { 220 res = (out_start + ((out_end - out_start) / (input_end - input_start)) * (v - input_start)); 221 } 222 223 return res; 224 } 225 /// <summary> 226 /// 将图像的输入值映射到 别的范围 227 /// </summary> 228 /// <param name="v"></param> 229 /// <param name="inputEnd"></param> 230 /// <returns></returns> 231 private float PraseColor(double v, int inputEnd) 232 { 233 float input_start = 0; //最低数量范围的输入。 234 float input_end = 5000f; //最低数量范围的输入。 235 float out_start = 0f; //编号最小的范围内输出。 236 float out_end = 255f; //范围输出中人数最多的。INT输入= 127; //输入值。 237 float res = 0; 238 if (v > 1000) 239 { 240 res = (out_start + ((out_end - out_start) / (input_end - input_start)) * ((int)v - input_start)); 241 } 242 243 return res; 244 } 245 246 247 public static int GetLimetImage(int[,] imageGreen, int a1, int a2) 248 { 249 List<int> coumindex = new List<int>(); 250 HashSet<int> y = new HashSet<int>(); 251 for (int i = 0; i < imageGreen.GetLength(0); i++) 252 { 253 int gcontiu = 0; 254 int contiu = 0; 255 for (int j = 0; j < imageGreen.GetLength(1); j++) 256 { 257 imageGreen[i, j] = -imageGreen[i, j] + 255; 258 if (imageGreen[i, j] < a1) 259 { 260 imageGreen[i, j] = 0; 261 } 262 else 263 { 264 contiu++; 265 if (contiu == a2) 266 { 267 gcontiu++; 268 269 } 270 } 271 } 272 if (gcontiu == 0) 273 { 274 for (int k = 0; k < imageGreen.GetLength(1); k++) 275 { 276 imageGreen[i, k] = 0; 277 } 278 } 279 else 280 { 281 coumindex.Add(i); 282 for (int j = 0; j < imageGreen.GetLength(1); j++) 283 { 284 if (imageGreen[i, j] != 0) 285 { 286 y.Add(j); 287 } 288 } 289 } 290 } 291 int p = coumindex.Count >0?1:0; 292 for (int i = 0; i < coumindex.Count - 1; i++) 293 { 294 if (coumindex[i + 1] - coumindex[i] != 1) 295 { 296 p++; 297 } 298 } 299 300 var Val = 0; 301 if (coumindex.Count == 0|| y.Count==0) { 302 return Val; 303 } 304 if (p == 1) { 305 Val = 1; 306 } else { 307 long allpoint = 0; 308 int[,] allpointDel = new int[coumindex.Count, y.Count]; 309 310 for (int i = 0; i < coumindex.Count; i++) 311 { 312 for (int j = 0; j < y.Count; j++) 313 { 314 allpointDel[i, j] = imageGreen[coumindex[i], y.ElementAt(j)]; 315 allpoint = allpoint + imageGreen[coumindex[i], y.ElementAt(j)]; 316 } 317 } 318 var mevn = allpoint / (coumindex.Count * y.Count * 1.0); 319 if (mevn < 40) { 320 Val = 0; 321 } else { 322 Val = 2; 323 } 324 } 325 return Val; 326 } 327 328 } 329 }
1 public static bool GetRGB(Bitmap Source, out int[,] R, out int[,] G, out int[,] B) 2 { 3 try 4 { 5 int iWidth = Source.Width; 6 int iHeight = Source.Height; 7 Rectangle rect = new Rectangle(0, 0, iWidth, iHeight); 8 System.Drawing.Imaging.BitmapData bmpData = Source.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, Source.PixelFormat); 9 IntPtr iPtr = bmpData.Scan0; 10 int iBytes = iWidth * iHeight * 3; 11 byte[] PixelValues = new byte[iBytes]; 12 System.Runtime.InteropServices.Marshal.Copy(iPtr, PixelValues, 0, iBytes); 13 Source.UnlockBits(bmpData); 14 // 注意这个地方图像的两维方向与数组两维的方向是转置的关系 15 R = new int[iHeight, iWidth]; 16 G = new int[iHeight, iWidth]; 17 B = new int[iHeight, iWidth]; 18 int iPoint = 0; 19 for (int i = 0; i < iHeight; i++) 20 { 21 for (int j = 0; j < iWidth; j++) 22 { 23 // 注意,Windows 中三基色的排列顺序是 BGR 而不是 RGB! 24 B[i, j] = Convert.ToInt32(PixelValues[iPoint++]); 25 G[i, j] = Convert.ToInt32(PixelValues[iPoint++]); 26 R[i, j] = Convert.ToInt32(PixelValues[iPoint++]); 27 } 28 } 29 30 return true; 31 } 32 catch (Exception) 33 { 34 R = null; 35 G = null; 36 B = null; 37 38 return false; 39 } 40 } 41
1 public static int[,] RGB2Gray(Bitmap srcBitmap) 2 { 3 int wide = srcBitmap.Width; 4 int height = srcBitmap.Height; 5 Rectangle rect = new Rectangle(0, 0, wide, height); 6 // 将Bitmap锁定到系统内存中, 获得BitmapData 7 BitmapData srcBmData = srcBitmap.LockBits(rect, 8 ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); 9 //创建Bitmap 10 Bitmap dstBitmap = CreateGrayscaleImage(wide, height);//这个函数在后面有定义 11 BitmapData dstBmData = dstBitmap.LockBits(rect, 12 ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed); 13 // 位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行 14 System.IntPtr srcPtr = srcBmData.Scan0; 15 System.IntPtr dstPtr = dstBmData.Scan0; 16 // 将Bitmap对象的信息存放到byte数组中 17 int src_bytes = srcBmData.Stride * height; 18 byte[] srcValues = new byte[src_bytes]; 19 int dst_bytes = dstBmData.Stride * height; 20 byte[] dstValues = new byte[dst_bytes]; 21 //复制GRB信息到byte数组 22 System.Runtime.InteropServices.Marshal.Copy(srcPtr, srcValues, 0, src_bytes); 23 System.Runtime.InteropServices.Marshal.Copy(dstPtr, dstValues, 0, dst_bytes); 24 int unm = 365; 25 // 根据Y=0.299*R+0.114*G+0.587B,Y为亮度 26 int[,] imgData = new int[wide, height - 365 - 37]; 27 for (int i = 365; i < height - 37; i++) 28 for (int j = 0; j < wide; j++) 29 { 30 //只处理每行中图像像素数据,舍弃未用空间 31 //注意位图结构中RGB按BGR的顺序存储 32 int k = 3 * j; 33 double temp = srcValues[i * srcBmData.Stride + k + 1]; 34 dstValues[i * dstBmData.Stride + j] = (byte)temp; 35 imgData[j, i - 365] = srcValues[i * srcBmData.Stride + k + 1]; 36 } 37 //将更改过的byte[]拷贝到原位图 38 System.Runtime.InteropServices.Marshal.Copy(dstValues, 0, dstPtr, dst_bytes); 39 // 解锁位图 40 srcBitmap.UnlockBits(srcBmData); 41 dstBitmap.UnlockBits(dstBmData); 42 43 return imgData; 44 }
参考: https://www.cnblogs.com/yiyiruohan/archive/2010/08/24/1807533.html