首页 > 编程 > C# > 正文

C#验证码识别类完整实例

2019-10-29 21:40:15
字体:大 中 小
来源:转载
供稿:网友

这篇文章主要介绍了C#验证码识别类,以一个完整实例形式较为详细的分析了验证码图片处理所涉及的各种常用技巧,具有一定参考借鉴价值,需要的朋友可以参考下

本文实例讲述了C#验证码识别类。分享给大家供大家参考。具体实现方法如下:

 

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

希望本文所述对大家的C#程序设计有所帮助。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表