ReadCodeTest.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. using OpenCvSharp;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. using System.Drawing.Imaging;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. namespace OpenCvSharpTest
  11. {
  12. public static class ReadCodeTest
  13. {
  14. public static string Read10CodeTest1(Bitmap Bitmapimage)
  15. {
  16. bool IsShuZhi = false;
  17. //读取图片
  18. //Mat image = Cv2.ImRead("D:\\work\\WindowsFormsTest\\TestImage\\20250609165353.jpg");
  19. Mat image = BitmapToMat(Bitmapimage);
  20. Mat gray = new Mat();
  21. //灰度化预处理
  22. Cv2.CvtColor(image, gray, ColorConversionCodes.BGR2GRAY);
  23. Cv2.ImShow("gray", ResizeMat(gray));
  24. //二值化
  25. Mat binary = new Mat();
  26. Cv2.Threshold(gray, binary, 100, 255, ThresholdTypes.Binary);
  27. //Cv2.ImShow("binary", ResizeMat(binary));
  28. //计算梯度
  29. Mat gradX = new Mat();
  30. if (IsShuZhi)
  31. {
  32. Cv2.Sobel(binary, gradX, MatType.CV_32F, 1, 0, 1, 1, 0, BorderTypes.Default);
  33. }
  34. else
  35. {
  36. Cv2.Sobel(binary, gradX, MatType.CV_32F, 0, 1, 1, 1, 0, BorderTypes.Default);
  37. }
  38. //Cv2.ImShow("gradX", ResizeMat(gradX));
  39. //计算绝对值
  40. Mat absGradX = new Mat();
  41. Cv2.ConvertScaleAbs(gradX, absGradX, 1, 0);
  42. //Cv2.ImShow("absGradX", ResizeMat(absGradX));
  43. //闭运算
  44. Mat kernelX = new Mat();
  45. if (IsShuZhi)
  46. {
  47. kernelX = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(80, 5));
  48. }
  49. else
  50. {
  51. kernelX = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(5, 40));
  52. }
  53. Mat closed = new Mat();
  54. Cv2.MorphologyEx(absGradX, closed, MorphTypes.Close, kernelX);
  55. Cv2.ImShow("closedimg", ResizeMat(closed));
  56. //查找轮廓
  57. OpenCvSharp.Point[][] contours;
  58. HierarchyIndex[] hierarchy;
  59. Cv2.FindContours(closed, out contours, out hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple);
  60. List<BlobInfo> filteredBlobs = new List<BlobInfo>();
  61. int minPixelCount = 1000;
  62. int maxPixelCount = 6000000;
  63. double minRectangularity = 0.6; // 最小矩形度
  64. foreach (OpenCvSharp.Point[] contour in contours)
  65. {
  66. double area = Cv2.ContourArea(contour);
  67. if (area >= minPixelCount && area <= maxPixelCount)
  68. {// 计算矩形度
  69. double rectangularity = CalculateRectangularity(contour);
  70. // 矩形度筛选
  71. if (rectangularity >= minRectangularity)
  72. {
  73. // 获取轮廓的边界矩形
  74. Rect boundingRect = Cv2.BoundingRect(contour);
  75. BlobInfo blobInfo = new BlobInfo
  76. {
  77. Contour = contour,
  78. Area = area,
  79. Rectangularity = rectangularity,
  80. BoundingRect = boundingRect,
  81. Center = new OpenCvSharp.Point(boundingRect.X + boundingRect.Width / 2,
  82. boundingRect.Y + boundingRect.Height / 2)
  83. };
  84. filteredBlobs.Add(blobInfo);
  85. Console.WriteLine($"轮廓 - 面积: {area:F0} 像素, 矩形度: {rectangularity:F2}");
  86. }
  87. }
  88. }
  89. // 在原图上绘制筛选后的轮廓
  90. //Mat outputImage = new Mat();
  91. //foreach (var blobInfo in filteredBlobs)
  92. //{
  93. // Cv2.DrawContours(image, new[] { blobInfo.Contour }, -1, Scalar.Green, 5);
  94. //}
  95. //Cv2.ImShow("Output Image", ReadCodeTest.ResizeMat(image));
  96. //if (contours.Count() == 0)
  97. // return "";
  98. ////筛选矩形并找到最大面积
  99. //var maxContour = contours.OrderByDescending(c => Cv2.ContourArea(c)).First();
  100. if (filteredBlobs.Count() == 0)
  101. {
  102. Cv2.WaitKey(0);
  103. return "";
  104. }
  105. OpenCvSharp.Rect ShowboundingRect = Cv2.BoundingRect(filteredBlobs.First().Contour);
  106. //Cv2.Rectangle(image, boundingRect, Scalar.Red, 2);
  107. OpenCvSharp.Rect roi = new OpenCvSharp.Rect(ShowboundingRect.X + (ShowboundingRect.Width / 4), ShowboundingRect.Y - 25, ShowboundingRect.Width / 2, ShowboundingRect.Height + 50);
  108. Mat roiMat = binary.SubMat(roi).Clone();
  109. Cv2.ImShow("roi", ResizeMat(roiMat));
  110. Mat binary2 = new Mat();
  111. // 使用THRESH_BINARY_INV反转黑白,黑色物体变为白色区域
  112. Cv2.Threshold(roiMat, binary2, 128, 255, ThresholdTypes.BinaryInv);
  113. OpenCvSharp.Point[][] contours1;
  114. HierarchyIndex[] hierarchy1;
  115. Cv2.FindContours(binary2, out contours1, out hierarchy1,
  116. RetrievalModes.External, ContourApproximationModes.ApproxSimple);
  117. Console.WriteLine(contours1.Count().ToString());
  118. var widths = contours1.OrderBy(c => Cv2.BoundingRect(c).Y).Select(c => Cv2.BoundingRect(c).Height).ToArray();
  119. double ave = widths.Average();
  120. var CodeResult = widths.Select(w => w > ave ? 1 : 0).ToArray();
  121. Console.WriteLine(string.Join("", CodeResult));
  122. //// 显示结果
  123. //Cv2.ImShow("Result", ResizeMat(image));
  124. Cv2.WaitKey(0);
  125. ////显示结果
  126. //Cv2.DestroyAllWindows();
  127. image.Dispose();
  128. return string.Join("", CodeResult);
  129. //return "";
  130. }
  131. public static void FindOcrCode()
  132. {
  133. Mat image1 = Cv2.ImRead("D:\\work\\WindowsFormsTest\\TestImage\\wechat_2025-09-03_112903_716.png");
  134. Mat image2 = Cv2.ImRead("D:\\work\\WindowsFormsTest\\TestImage\\wechat_2025-09-03_112903_716_1.png");
  135. // 查找轮廓
  136. OpenCvSharp.Point[][] contours1;
  137. OpenCvSharp.Point[][] contours2;
  138. Cv2.FindContours(image1, out contours1, out _, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
  139. Cv2.FindContours(image2, out contours2, out _, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
  140. // 轮廓匹配
  141. double similarity = Cv2.MatchShapes(contours1[0], contours2[0], ShapeMatchModes.I1);
  142. // 相似度值越小表示轮廓越相似
  143. if (similarity < 0.1)
  144. {
  145. Console.WriteLine("轮廓非常相似");
  146. }
  147. }
  148. public static Mat ResizeMat(Mat mat)
  149. {
  150. Mat resizedImage = new Mat();
  151. double maxSize = 800;
  152. double scale = Math.Min(maxSize / mat.Width, maxSize / mat.Height);
  153. OpenCvSharp.Size scaledSize = new OpenCvSharp.Size(mat.Width * scale, mat.Height * scale);
  154. Cv2.Resize(mat, resizedImage, scaledSize);
  155. return resizedImage;
  156. }
  157. /// <summary>
  158. /// 将Bitmap转换为Mat(输出为彩色图)
  159. /// 转换后的图像可以增加彩色框
  160. /// </summary>
  161. /// <param name="bitmap">源Bitmap</param>
  162. /// <returns>对应的Mat对象</returns>
  163. static Mat BitmapToMat(Bitmap bitmap)
  164. {
  165. using (var ms = new MemoryStream())
  166. {
  167. bitmap.Save(ms, ImageFormat.Bmp);
  168. ms.Position = 0;
  169. return Mat.FromStream(ms, ImreadModes.Color);
  170. }
  171. }
  172. /// <summary>
  173. /// 计算轮廓的矩形度
  174. /// 矩形度 = 轮廓面积 / 最小外接矩形面积
  175. /// </summary>
  176. /// <param name="contour">轮廓点集</param>
  177. /// <returns>矩形度值 (0-1)</returns>
  178. static double CalculateRectangularity(OpenCvSharp.Point[] contour)
  179. {
  180. // 计算轮廓面积
  181. double contourArea = Cv2.ContourArea(contour);
  182. // 获取最小外接矩形
  183. RotatedRect minAreaRect = Cv2.MinAreaRect(contour);
  184. // 计算最小外接矩形面积
  185. double rectArea = minAreaRect.Size.Width * minAreaRect.Size.Height;
  186. // 避免除零错误
  187. if (rectArea <= 0)
  188. return 0;
  189. // 计算矩形度
  190. double rectangularity = contourArea / rectArea;
  191. // 确保值在合理范围内
  192. return Math.Max(0, Math.Min(1, rectangularity));
  193. }
  194. }
  195. }