原文 C# 验证识别基类
网上找了些代码 自己又改了下 先放出来了 处理简单的验证码足够了 001 using System; 002 using System.Collections.Generic; 003 using System.Linq; 004 using System.Text; 005 using System.Drawing; 006 using System.Drawing.Imaging; 007 using System.Runtime.InteropServices; 008 009 namespace 验证码处理 010 { 011 class VerifyCode 012 { 013 public Bitmap bmpobj; 014 015 public VerifyCode(Bitmap pic) 016 { 017 bmpobj = new Bitmap(pic); //转换为Format32bppRgb 018 } 019 020 /// <summary> 021 /// 根据RGB,计算灰度值 022 /// </summary> 023 /// <param name="posClr">Color值</param> 024 /// <returns>灰度值,整型</returns> 025 private int GetGrayNumColor(System.Drawing.Color posClr) 026 { 027 return (posClr.R * 19595 + posClr.G * 38469 + posClr.B * 7472) >> 16; 028 } 029 030 /// <summary> 031 /// 灰度转换,逐点方式 032 /// </summary> 033 public void GrayByPixels() 034 { 035 for (int i = 0; i < bmpobj.Height; i++) 036 { 037 for (int j = 0; j < bmpobj.Width; j++) 038 { 039 int tmpValue = GetGrayNumColor(bmpobj.GetPixel(j, i)); 040 bmpobj.SetPixel(j, i, Color.FromArgb(tmpValue, tmpValue, tmpValue)); 041 } 042 } 043 } 044 045 /// <summary> 046 /// 去图形边框 047 /// </summary> 048 /// <param name="borderWidth"></param> 049 public void ClearPicBorder(int borderWidth) 050 { 051 for (int i = 0; i < bmpobj.Height; i++) 052 { 053 for (int j = 0; j < bmpobj.Width; j++) 054 { 055 if (i < borderWidth || j < borderWidth || j > bmpobj.Width - 1 - borderWidth || i > bmpobj.Height - 1 - borderWidth) 056 bmpobj.SetPixel(j, i, Color.FromArgb(255, 255, 255)); 057 } 058 } 059 } 060 061 /// <summary> 062 /// 灰度转换,逐行方式 063 /// </summary> 064 public void GrayByLine() 065 { 066 Rectangle rec = new Rectangle(0, 0, bmpobj.Width, bmpobj.Height); 067 BitmapData bmpData = bmpobj.LockBits(rec, ImageLockMode.ReadWrite, bmpobj.PixelFormat);// PixelFormat.Format32bppPArgb); 068 // bmpData.PixelFormat = PixelFormat.Format24bppRgb; 069 IntPtr scan0 = bmpData.Scan0; 070 int len = bmpobj.Width * bmpobj.Height; 071 int[] pixels = new int[len]; 072 Marshal.Copy(scan0, pixels, 0, len); 073 074 //对图片进行处理 075 int GrayValue = 0; 076 for (int i = 0; i < len; i++) 077 { 078 GrayValue = GetGrayNumColor(Color.FromArgb(pixels[i])); 079 pixels[i] = (byte)(Color.FromArgb(GrayValue, GrayValue, GrayValue)).ToArgb(); //Color转byte 080 } 081 082 bmpobj.UnlockBits(bmpData); 083 084 ////输出 085 //GCHandle gch = GCHandle.Alloc(pixels, GCHandleType.Pinned); 086 //bmpOutput = new Bitmap(bmpobj.Width, bmpobj.Height, bmpData.Stride, bmpData.PixelFormat, gch.AddrOfPinnedObject()); 087 //gch.Free(); 088 } 089 090 /// <summary> 091 /// 得到有效图形并调整为可平均分割的大小 092 /// </summary> 093 /// <param name="dgGrayValue">灰度背景分界值</param> 094 /// <param name="CharsCount">有效字符数</param> 095 /// <returns></returns> 096 public void GetPicValidByValue(int dgGrayValue, int CharsCount) 097 { 098 int posx1 = bmpobj.Width; int posy1 = bmpobj.Height; 099 int posx2 = 0; int posy2 = 0; 100 for (int i = 0; i < bmpobj.Height; i++) //找有效区 101 { 102 for (int j = 0; j < bmpobj.Width; j++) 103 { 104 int pixelValue = bmpobj.GetPixel(j, i).R; 105 if (pixelValue < dgGrayValue) //根据灰度值 106 { 107 if (posx1 > j) posx1 = j; 108 if (posy1 > i) posy1 = i; 109 110 if (posx2 < j) posx2 = j; 111 if (posy2 < i) posy2 = i; 112 }; 113 }; 114 }; 115 // 确保能整除 116 int Span = CharsCount - (posx2 - posx1 + 1) % CharsCount; //可整除的差额数 117 if (Span < CharsCount) 118 { 119 int leftSpan = Span / 2; //分配到左边的空列 ,如span为单数,则右边比左边大1 120 if (posx1 > leftSpan) 121 posx1 = posx1 - leftSpan; 122 if (posx2 + Span - leftSpan < bmpobj.Width) 123 posx2 = posx2 + Span - leftSpan; 124 } 125 //复制新图 126 Rectangle cloneRect = new Rectangle(posx1, posy1, posx2 - posx1 + 1, posy2 - posy1 + 1); 127 bmpobj = bmpobj.Clone(cloneRect, bmpobj.PixelFormat); 128 } 129 130 /// <summary> 131 /// 得到有效图形,图形为类变量 132 /// </summary> 133 /// <param name="dgGrayValue">灰度背景分界值</param> 134 /// <param name="CharsCount">有效字符数</param> 135 /// <returns></returns> 136 public void GetPicValidByValue(int dgGrayValue) 137 { 138 int posx1 = bmpobj.Width; int posy1 = bmpobj.Height; 139 int posx2 = 0; int posy2 = 0; 140 for (int i = 0; i < bmpobj.Height; i++) //找有效区 141 { 142 for (int j = 0; j < bmpobj.Width; j++) 143 { 144 int pixelValue = bmpobj.GetPixel(j, i).R; 145 if (pixelValue < dgGrayValue) //根据灰度值 146 { 147 if (posx1 > j) posx1 = j; 148 if (posy1 > i) posy1 = i; 149 150 if (posx2 < j) posx2 = j; 151 if (posy2 < i) posy2 = i; 152 }; 153 }; 154 }; 155 //复制新图 156 Rectangle cloneRect = new Rectangle(posx1, posy1, posx2 - posx1 + 1, posy2 - posy1 + 1); 157 bmpobj = bmpobj.Clone(cloneRect, bmpobj.PixelFormat); 158 } 159 160 /// <summary> 161 /// 得到有效图形,图形由外面传入 162 /// </summary> 163 /// <param name="dgGrayValue">灰度背景分界值</param> 164 /// <param name="CharsCount">有效字符数</param> 165 /// <returns></returns> 166 public Bitmap GetPicValidByValue(Bitmap singlepic, int dgGrayValue) 167 { 168 int posx1 = singlepic.Width; int posy1 = singlepic.Height; 169 int posx2 = 0; int posy2 = 0; 170 for (int i = 0; i < singlepic.Height; i++) //找有效区 171 { 172 for (int j = 0; j < singlepic.Width; j++) 173 { 174 int pixelValue = singlepic.GetPixel(j, i).R; 175 if (pixelValue < dgGrayValue) //根据灰度值 176 { 177 if (posx1 > j) posx1 = j; 178 if (posy1 > i) posy1 = i; 179 180 if (posx2 < j) posx2 = j; 181 if (posy2 < i) posy2 = i; 182 }; 183 }; 184 }; 185 //复制新图 186 Rectangle cloneRect = new Rectangle(posx1, posy1, posx2 - posx1 + 1, posy2 - posy1 + 1); 187 return singlepic.Clone(cloneRect, singlepic.PixelFormat); 188 } 189 190 /// <summary> 191 /// 平均分割图片 192 /// </summary> 193 /// <param name="RowNum">水平上分割数</param> 194 /// <param name="ColNum">垂直上分割数</param> 195 /// <returns>分割好的图片数组</returns> 196 public Bitmap [] GetSplitPics(int RowNum,int ColNum) 197 { 198 if (RowNum == 0 || ColNum == 0) 199 return null; 200 int singW = bmpobj.Width / RowNum; 201 int singH = bmpobj.Height / ColNum; 202 Bitmap [] PicArray=new Bitmap[RowNum*ColNum]; 203 204 Rectangle cloneRect; 205 for (int i = 0; i < ColNum; i++) //找有效区 206 { 207 for (int j = 0; j < RowNum; j++) 208 { 209 cloneRect = new Rectangle(j*singW, i*singH, singW , singH); 210 PicArray[i*RowNum+j]=bmpobj.Clone(cloneRect, bmpobj.PixelFormat);//复制小块图 211 } 212 } 213 return PicArray; 214 } 215 216 /// <summary> 217 /// 返回灰度图片的点阵描述字串,1表示灰点,0表示背景 218 /// </summary> 219 /// <param name="singlepic">灰度图</param> 220 /// <param name="dgGrayValue">背前景灰色界限</param> 221 /// <returns></returns> 222 public string GetSingleBmpCode(Bitmap singlepic, int dgGrayValue) 223 { 224 Color piexl; 225 string code = ""; 226 for (int posy = 0; posy < singlepic.Height; posy++) 227 for (int posx = 0; posx < singlepic.Width; posx++) 228 { 229 piexl = singlepic.GetPixel(posx, posy); 230 if (piexl.R < dgGrayValue) // Color.Black ) 231 code = code + "1"; 232 else 233 code = code + "0"; 234 } 235 return code; 236 } 237 238 /// <summary> 239 /// 得到灰度图像前景背景的临界值 最大类间方差法 240 /// </summary> 241 /// <returns>前景背景的临界值</returns> 242 public int GetDgGrayValue() 243 { 244 int[] pixelNum = new int[256]; //图象直方图,共256个点 245 int n, n1, n2; 246 int total; //total为总和,累计值 247 double m1, m2, sum, csum, fmax, sb; //sb为类间方差,fmax存储最大方差值 248 int k, t, q; 249 int threshValue = 1; // 阈值 250 //生成直方图 251 for (int i = 0; i < bmpobj.Width; i++) 252 { 253 for (int j = 0; j < bmpobj.Height; j++) 254 { 255 //返回各个点的颜色,以RGB表示 256 pixelNum[bmpobj.GetPixel(i, j).R]++; //相应的直方图加1 257 } 258 } 259 //直方图平滑化 260 for (k = 0; k <= 255; k++) 261 { 262 total = 0; 263 for (t = -2; t <= 2; t++) //与附近2个灰度做平滑化,t值应取较小的值 264 { 265 q = k + t; 266 if (q < 0) //越界处理 267 q = 0; 268 if (q > 255) 269 q = 255; 270 total = total + pixelNum[q]; //total为总和,累计值 271 } 272 pixelNum[k] = (int)((float)total / 5.0 + 0.5); //平滑化,左边2个+中间1个+右边2个灰度,共5个,所以总和除以5,后面加0.5是用修正值 273 } 274 //求阈值 275 sum = csum = 0.0; 276 n = 0; 277 //计算总的图象的点数和质量矩,为后面的计算做准备 278 for (k = 0; k <= 255; k++) 279 { 280 sum += (double)k * (double)pixelNum[k]; //x*f(x)质量矩,也就是每个灰度的值乘以其点数(归一化后为概率),sum为其总和 281 n += pixelNum[k]; //n为图象总的点数,归一化后就是累积概率 282 } 283 284 fmax = -1.0; //类间方差sb不可能为负,所以fmax初始值为-1不影响计算的进行 285 n1 = 0; 286 for (k = 0; k < 256; k++) //对每个灰度(从0到255)计算一次分割后的类间方差sb 287 { 288 n1 += pixelNum[k]; //n1为在当前阈值遍前景图象的点数 289 if (n1 == 0) { continue; } //没有分出前景后景 290 n2 = n - n1; //n2为背景图象的点数 291 if (n2 == 0) { break; } //n2为0表示全部都是后景图象,与n1=0情况类似,之后的遍历不可能使前景点数增加,所以此时可以退出循环 292 csum += (double)k * pixelNum[k]; //前景的“灰度的值*其点数”的总和 293 m1 = csum / n1; //m1为前景的平均灰度 294 m2 = (sum - csum) / n2; //m2为背景的平均灰度 295 sb = (double)n1 * (double)n2 * (m1 - m2) * (m1 - m2); //sb为类间方差 296 if (sb > fmax) //如果算出的类间方差大于前一次算出的类间方差 297 { 298 fmax = sb; //fmax始终为最大类间方差(otsu) 299 threshValue = k; //取最大类间方差时对应的灰度的k就是最佳阈值 300 } 301 } 302 return threshValue; 303 } 304 305 /// <summary> 306 /// 去掉杂点(适合杂点/杂线粗为1) 307 /// </summary> 308 /// <param name="dgGrayValue">背前景灰色界限</param> 309 /// <returns></returns> 310 public void ClearNoise(int dgGrayValue, int MaxNearPoints) 311 { 312 Color piexl; 313 int nearDots = 0; 314 //逐点判断 315 for (int i = 0; i < bmpobj.Width; i++) 316 for (int j = 0; j < bmpobj.Height; j++) 317 { 318 piexl = bmpobj.GetPixel(i, j); 319 if (piexl.R < dgGrayValue) 320 { 321 nearDots = 0; 322 //判断周围8个点是否全为空 323 if (i == 0 || i == bmpobj.Width - 1 || j == 0 || j == bmpobj.Height - 1) //边框全去掉 324 { 325 bmpobj.SetPixel(i, j, Color.FromArgb(255, 255, 255)); 326 } 327 else 328 { 329 if (bmpobj.GetPixel(i - 1, j - 1).R < dgGrayValue) nearDots++; 330 if (bmpobj.GetPixel(i, j - 1).R < dgGrayValue) nearDots++; 331 if (bmpobj.GetPixel(i + 1, j - 1).R < dgGrayValue) nearDots++; 332 if (bmpobj.GetPixel(i - 1, j).R < dgGrayValue) nearDots++; 333 if (bmpobj.GetPixel(i + 1, j).R < dgGrayValue) nearDots++; 334 if (bmpobj.GetPixel(i - 1, j + 1).R < dgGrayValue) nearDots++; 335 if (bmpobj.GetPixel(i, j + 1).R < dgGrayValue) nearDots++; 336 if (bmpobj.GetPixel(i + 1, j + 1).R < dgGrayValue) nearDots++; 337 } 338 339 if (nearDots < MaxNearPoints) 340 bmpobj.SetPixel(i, j, Color.FromArgb(255, 255, 255)); //去掉单点 && 粗细小3邻边点 341 } 342 else //背景 343 bmpobj.SetPixel(i, j, Color.FromArgb(255, 255, 255)); 344 } 345 } 346 347 /// <summary> 348 /// 3×3中值滤波除杂 349 /// </summary> 350 /// <param name="dgGrayValue"></param> 351 public void ClearNoise(int dgGrayValue) 352 { 353 int x, y; 354 byte[] p = new byte[9]; //最小处理窗口3*3 355 byte s; 356 //byte[] lpTemp=new BYTE[nByteWidth*nHeight]; 357 int i, j; 358 //--!!!!!!!!!!!!!!下面开始窗口为3×3中值滤波!!!!!!!!!!!!!!!! 359 for (y = 1; y < bmpobj.Height - 1; y++) //--第一行和最后一行无法取窗口 360 { 361 for (x = 1; x < bmpobj.Width - 1; x++) 362 { 363 //取9个点的值 364 p[0] = bmpobj.GetPixel(x - 1, y - 1).R; 365 p[1] = bmpobj.GetPixel(x, y - 1).R; 366 p[2] = bmpobj.GetPixel(x + 1, y - 1).R; 367 p[3] = bmpobj.GetPixel(x - 1, y).R; 368 p[4] = bmpobj.GetPixel(x, y).R; 369 p[5] = bmpobj.GetPixel(x + 1, y).R; 370 p[6] = bmpobj.GetPixel(x - 1, y + 1).R; 371 p[7] = bmpobj.GetPixel(x, y + 1).R; 372 p[8] = bmpobj.GetPixel(x + 1, y + 1).R; 373 //计算中值 374 for (j = 0; j < 5; j++) 375 { 376 for (i = j + 1; i < 9; i++) 377 { 378 if (p[j] > p[i]) 379 { 380 s = p[j]; 381 p[j] = p[i]; 382 p[i] = s; 383 } 384 } 385 } 386 // if (bmpobj.GetPixel(x, y).R < dgGrayValue) 387 bmpobj.SetPixel(x, y, Color.FromArgb(p[4], p[4], p[4])); //给有效值付中值 388 } 389 } 390 } 391 392 /// <summary> 393 /// 该函数用于对图像进行腐蚀运算。结构元素为水平方向或垂直方向的三个点, 394 /// 中间点位于原点;或者由用户自己定义3×3的结构元素。 395 /// </summary> 396 /// <param name="dgGrayValue">前后景临界值</param> 397 /// <param name="nMode">腐蚀方式:0表示水平方向,1垂直方向,2自定义结构元素。</param> 398 /// <param name="structure"> 自定义的3×3结构元素</param> 399 public void ErosionPic(int dgGrayValue, int nMode, bool[,] structure) 400 { 401 int lWidth = bmpobj.Width; 402 int lHeight = bmpobj.Height; 403 Bitmap newBmp = new Bitmap(lWidth, lHeight); 404 405 int i, j, n, m; //循环变量 406 407 if (nMode == 0) 408 { 409 //使用水平方向的结构元素进行腐蚀 410 // 由于使用1×3的结构元素,为防止越界,所以不处理最左边和最右边 411 // 的两列像素 412 for (j = 0; j < lHeight; j++) 413 { 414 for (i = 1; i < lWidth - 1; i++) 415 { 416 //目标图像中的当前点先赋成黑色 417 newBmp.SetPixel(i, j, Color.Black); 418 419 //如果源图像中当前点自身或者左右有一个点不是黑色, 420 //则将目标图像中的当前点赋成白色 421 if (bmpobj.GetPixel(i - 1, j).R > dgGrayValue || 422 bmpobj.GetPixel(i, j).R > dgGrayValue || 423 bmpobj.GetPixel(i + 1, j).R > dgGrayValue) 424 newBmp.SetPixel(i, j, Color.White); 425 } 426 } 427 } 428 else if (nMode == 1) 429 { 430 //使用垂真方向的结构元素进行腐蚀 431 // 由于使用3×1的结构元素,为防止越界,所以不处理最上边和最下边 432 // 的两行像素 433 for (j = 1; j < lHeight - 1; j++) 434 { 435 for (i = 0; i < lWidth; i++) 436 { 437 //目标图像中的当前点先赋成黑色 438 newBmp.SetPixel(i, j, Color.Black); 439 440 //如果源图像中当前点自身或者左右有一个点不是黑色, 441 //则将目标图像中的当前点赋成白色 442 if (bmpobj.GetPixel(i, j - 1).R > dgGrayValue || 443 bmpobj.GetPixel(i, j).R > dgGrayValue || 444 bmpobj.GetPixel(i, j + 1).R > dgGrayValue) 445 newBmp.SetPixel(i, j, Color.White); 446 } 447 } 448 } 449 else 450 { 451 if (structure.Length != 9) //检查自定义结构 452 return; 453 //使用自定义的结构元素进行腐蚀 454 // 由于使用3×3的结构元素,为防止越界,所以不处理最左边和最右边 455 // 的两列像素和最上边和最下边的两列像素 456 for (j = 1; j < lHeight - 1; j++) 457 { 458 for (i = 1; i < lWidth - 1; i++) 459 { 460 //目标图像中的当前点先赋成黑色 461 newBmp.SetPixel(i, j, Color.Black); 462 //如果原图像中对应结构元素中为黑色的那些点中有一个不是黑色, 463 //则将目标图像中的当前点赋成白色 464 for (m = 0; m < 3; m++) 465 { 466 for (n = 0; n < 3; n++) 467 { 468 if (!structure[m, n]) 469 continue; 470 if (bmpobj.GetPixel(i + m - 1, j + n - 1).R > dgGrayValue) 471 { 472 newBmp.SetPixel(i, j, Color.White); 473 break; 474 } 475 } 476 } 477 } 478 } 479 } 480 bmpobj = newBmp; 481 } 482 483 /// <summary> 484 /// 该函数用于对图像进行细化运算。要求目标图像为灰度图像 485 /// </summary> 486 /// <param name="dgGrayValue"></param> 487 public void ThiningPic(int dgGrayValue) 488 { 489 int lWidth = bmpobj.Width; 490 int lHeight = bmpobj.Height; 491 // Bitmap newBmp = new Bitmap(lWidth, lHeight); 492 493 bool bModified; //脏标记 494 int i, j, n, m; //循环变量 495 496 //四个条件 497 bool bCondition1; 498 bool bCondition2; 499 bool bCondition3; 500 bool bCondition4; 501 502 int nCount; //计数器 503 int[,] neighbour = new int[5, 5]; //5×5相邻区域像素值 504 505 506 507 bModified = true; 508 while (bModified) 509 { 510 bModified = false; 511 512 //由于使用5×5的结构元素,为防止越界,所以不处理外围的几行和几列像素 513 for (j = 2; j < lHeight - 2; j++) 514 { 515 for (i = 2; i < lWidth - 2; i++) 516 { 517 bCondition1 = false; 518 bCondition2 = false; 519 bCondition3 = false; 520 bCondition4 = false; 521 522 if (bmpobj.GetPixel(i, j).R > dgGrayValue) 523 { 524 if (bmpobj.GetPixel(i, j).R < 255) 525 bmpobj.SetPixel(i, j, Color.White); 526 continue; 527 } 528 529 //获得当前点相邻的5×5区域内像素值,白色用0代表,黑色用1代表 530 for (m = 0; m < 5; m++) 531 { 532 for (n = 0; n < 5; n++) 533 { 534 neighbour[m, n] = bmpobj.GetPixel(i + m - 2, j + n - 2).R < dgGrayValue ? 1 : 0; 535 } 536 } 537 538 //逐个判断条件。 539 //判断2<=NZ(P1)<=6 540 nCount = neighbour[1, 1] + neighbour[1, 2] + neighbour[1, 3] 541 + neighbour[2, 1] + neighbour[2, 3] + 542 +neighbour[3, 1] + neighbour[3, 2] + neighbour[3, 3]; 543 if (nCount >= 2 && nCount <= 6) 544 { 545 bCondition1 = true; 546 } 547 548 //判断Z0(P1)=1 549 nCount = 0; 550 if (neighbour[1, 2] == 0 && neighbour[1, 1] == 1) 551 nCount++; 552 if (neighbour[1, 1] == 0 && neighbour[2, 1] == 1) 553 nCount++; 554 if (neighbour[2, 1] == 0 && neighbour[3, 1] == 1) 555 nCount++; 556 if (neighbour[3, 1] == 0 && neighbour[3, 2] == 1) 557 nCount++; 558 if (neighbour[3, 2] == 0 && neighbour[3, 3] == 1) 559 nCount++; 560 if (neighbour[3, 3] == 0 && neighbour[2, 3] == 1) 561 nCount++; 562 if (neighbour[2, 3] == 0 && neighbour[1, 3] == 1) 563 nCount++; 564 if (neighbour[1, 3] == 0 && neighbour[1, 2] == 1) 565 nCount++; 566 if (nCount == 1) 567 bCondition2 = true; 568 569 //判断P2*P4*P8=0 or Z0(p2)!=1 570 if (neighbour[1, 2] * neighbour[2, 1] * neighbour[2, 3] == 0) 571 { 572 bCondition3 = true; 573 } 574 else 575 { 576 nCount = 0; 577 if (neighbour[0, 2] == 0 && neighbour[0, 1] == 1) 578 nCount++; 579 if (neighbour[0, 1] == 0 && neighbour[1, 1] == 1) 580 nCount++; 581 if (neighbour[1, 1] == 0 && neighbour[2, 1] == 1) 582 nCount++; 583 if (neighbour[2, 1] == 0 && neighbour[2, 2] == 1) 584 nCount++; 585 if (neighbour[2, 2] == 0 && neighbour[2, 3] == 1) 586 nCount++; 587 if (neighbour[2, 3] == 0 && neighbour[1, 3] == 1) 588 nCount++; 589 if (neighbour[1, 3] == 0 && neighbour[0, 3] == 1) 590 nCount++; 591 if (neighbour[0, 3] == 0 && neighbour[0, 2] == 1) 592 nCount++; 593 if (nCount != 1) 594 bCondition3 = true; 595 } 596 597 //判断P2*P4*P6=0 or Z0(p4)!=1 598 if (neighbour[1, 2] * neighbour[2, 1] * neighbour[3, 2] == 0) 599 { 600 bCondition4 = true; 601 } 602 else 603 { 604 nCount = 0; 605 if (neighbour[1, 1] == 0 && neighbour[1, 0] == 1) 606 nCount++; 607 if (neighbour[1, 0] == 0 && neighbour[2, 0] == 1) 608 nCount++; 609 if (neighbour[2, 0] == 0 && neighbour[3, 0] == 1) 610 nCount++; 611 if (neighbour[3, 0] == 0 && neighbour[3, 1] == 1) 612 nCount++; 613 if (neighbour[3, 1] == 0 && neighbour[3, 2] == 1) 614 nCount++; 615 if (neighbour[3, 2] == 0 && neighbour[2, 2] == 1) 616 nCount++; 617 if (neighbour[2, 2] == 0 && neighbour[1, 2] == 1) 618 nCount++; 619 if (neighbour[1, 2] == 0 && neighbour[1, 1] == 1) 620 nCount++; 621 if (nCount != 1) 622 bCondition4 = true; 623 } 624 625 if (bCondition1 && bCondition2 && bCondition3 && bCondition4) 626 { 627 bmpobj.SetPixel(i, j, Color.White); 628 bModified = true; 629 } 630 else 631 { 632 bmpobj.SetPixel(i, j, Color.Black); 633 } 634 } 635 } 636 } 637 // 复制细化后的图像 638 // bmpobj = newBmp; 639 } 640 641 /// <summary> 642 /// 锐化要启用不安全代码编译 643 /// </summary> 644 /// <param name="val">锐化程度。取值[0,1]。值越大锐化程度越高</param> 645 /// <returns>锐化后的图像</returns> 646 public void Sharpen(float val) 647 { 648 int w = bmpobj.Width; 649 int h = bmpobj.Height; 650 Bitmap bmpRtn = new Bitmap(w, h, PixelFormat.Format24bppRgb); 651 BitmapData srcData = bmpobj.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); 652 BitmapData dstData = bmpRtn.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); 653 unsafe 654 { 655 byte* pIn = (byte*)srcData.Scan0.ToPointer(); 656 byte* pOut = (byte*)dstData.Scan0.ToPointer(); 657 int stride = srcData.Stride; 658 byte* p; 659 660 for (int y = 0; y < h; y++) 661 { 662 for (int x = 0; x < w; x++) 663 { 664 //取周围9点的值。位于边缘上的点不做改变。 665 if (x == 0 || x == w - 1 || y == 0 || y == h - 1) 666 { 667 //不做 668 pOut[0] = pIn[0]; 669 pOut[1] = pIn[1]; 670 pOut[2] = pIn[2]; 671 } 672 else 673 { 674 int r1, r2, r3, r4, r5, r6, r7, r8, r0; 675 int g1, g2, g3, g4, g5, g6, g7, g8, g0; 676 int b1, b2, b3, b4, b5, b6, b7, b8, b0; 677 678 float vR, vG, vB; 679 680 //左上 681 p = pIn - stride - 3; 682 r1 = p[2]; 683 g1 = p[1]; 684 b1 = p[0]; 685 686 //正上 687 p = pIn - stride; 688 r2 = p[2]; 689 g2 = p[1]; 690 b2 = p[0]; 691 692 //右上 693 p = pIn - stride + 3; 694 r3 = p[2]; 695 g3 = p[1]; 696 b3 = p[0]; 697 698 //左侧 699 p = pIn - 3; 700 r4 = p[2]; 701 g4 = p[1]; 702 b4 = p[0]; 703 704 //右侧 705 p = pIn + 3; 706 r5 = p[2]; 707 g5 = p[1]; 708 b5 = p[0]; 709 710 //右下 711 p = pIn + stride - 3; 712 r6 = p[2]; 713 g6 = p[1]; 714 b6 = p[0]; 715 716 //正下 717 p = pIn + stride; 718 r7 = p[2]; 719 g7 = p[1]; 720 b7 = p[0]; 721 722 //右下 723 p = pIn + stride + 3; 724 r8 = p[2]; 725 g8 = p[1]; 726 b8 = p[0]; 727 728 //自己 729 p = pIn; 730 r0 = p[2]; 731 g0 = p[1]; 732 b0 = p[0]; 733 734 vR = (float)r0 - (float)(r1 + r2 + r3 + r4 + r5 + r6 + r7 + r8) / 8; 735 vG = (float)g0 - (float)(g1 + g2 + g3 + g4 + g5 + g6 + g7 + g8) / 8; 736 vB = (float)b0 - (float)(b1 + b2 + b3 + b4 + b5 + b6 + b7 + b8) / 8; 737 738 vR = r0 + vR * val; 739 vG = g0 + vG * val; 740 vB = b0 + vB * val; 741 742 if (vR > 0) 743 { 744 vR = Math.Min(255, vR); 745 } 746 else 747 { 748 vR = Math.Max(0, vR); 749 } 750 751 if (vG > 0) 752 { 753 vG = Math.Min(255, vG); 754 } 755 else 756 { 757 vG = Math.Max(0, vG); 758 } 759 760 if (vB > 0) 761 { 762 vB = Math.Min(255, vB); 763 } 764 else 765 { 766 vB = Math.Max(0, vB); 767 } 768 769 pOut[0] = (byte)vB; 770 pOut[1] = (byte)vG; 771 pOut[2] = (byte)vR; 772 } 773 pIn += 3; 774 pOut += 3; 775 }// end of x 776 pIn += srcData.Stride - w * 3; 777 pOut += srcData.Stride - w * 3; 778 } // end of y 779 } 780 bmpobj.UnlockBits(srcData); 781 bmpRtn.UnlockBits(dstData); 782 bmpobj = bmpRtn; 783 } 784 785 /// <summary> 786 /// 图片二值化 787 /// </summary> 788 /// <param name="hsb"></param> 789 public void BitmapTo1Bpp(Double hsb) 790 { 791 int w = bmpobj.Width; 792 int h = bmpobj.Height; 793 Bitmap bmp = new Bitmap(w, h, PixelFormat.Format1bppIndexed); 794 BitmapData data = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed); 795 for (int y = 0; y < h; y++) 796 { 797 byte[] scan = new byte[(w + 7) / 8]; 798 for (int x = 0; x < w; x++) 799 { 800 Color c = bmpobj.GetPixel(x, y); 801 if (c.GetBrightness() >= hsb) scan[x / 8] |= (byte)(0x80 >> (x % 8)); 802 } 803 Marshal.Copy(scan, 0, (IntPtr)((int)data.Scan0 + data.Stride * y), scan.Length); 804 } 805 bmp.UnlockBits(data); 806 bmpobj = bmp; 807 } 808 } 809 }
时间: 2024-10-03 08:07:15