InstructionManualTest.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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. using CvPoint = OpenCvSharp.Point;
  11. using CvSize = OpenCvSharp.Size;
  12. namespace OpenCvSharpTest
  13. {
  14. public static class InstructionManualTest
  15. {
  16. public static void InstructionManualTest1()
  17. {
  18. //读取图片
  19. Bitmap Bitmapimage = new Bitmap("D:\\work\\WindowsFormsTest\\OpenCvSharpTest\\20251108153639.jpg");
  20. //Mat image = Cv2.ImRead("D:\\work\\WindowsFormsTest\\OpenCvSharpTest\\20251108153840.jpg");
  21. Mat image = BitmapToMat(Bitmapimage);
  22. Mat gray = new Mat();
  23. //灰度化预处理
  24. Cv2.CvtColor(image, gray, ColorConversionCodes.BGR2GRAY);
  25. //Cv2.ImShow("gray", gray);
  26. //二值化
  27. Mat binary = new Mat();
  28. Cv2.Threshold(gray, binary, 90, 255, ThresholdTypes.Binary);
  29. //Cv2.ImShow("binary", ReadCodeTest.ResizeMat(binary));
  30. //闭运算
  31. Mat kernelX = new Mat();
  32. kernelX = Cv2.GetStructuringElement(MorphShapes.Rect, new CvSize(15, 15));
  33. Mat Open = new Mat();
  34. Cv2.MorphologyEx(binary, Open, MorphTypes.Open, kernelX);
  35. Cv2.ImShow("Opendimg", ReadCodeTest.ResizeMat(Open));
  36. // 查找轮廓
  37. CvPoint[][] contours;
  38. HierarchyIndex[] hierarchy;
  39. Cv2.FindContours(Open, out contours, out hierarchy,
  40. RetrievalModes.External, ContourApproximationModes.ApproxSimple);
  41. // 筛选轮廓(根据面积)
  42. List<BlobInfo> filteredBlobs = new List<BlobInfo>();
  43. int minPixelCount = 2000000;
  44. int maxPixelCount = 6000000;
  45. double minRectangularity = 0.8; // 最小矩形度
  46. foreach (CvPoint[] contour in contours)
  47. {
  48. double area = Cv2.ContourArea(contour);
  49. if (area >= minPixelCount && area <= maxPixelCount)
  50. {// 计算矩形度
  51. double rectangularity = CalculateRectangularity(contour);
  52. // 矩形度筛选
  53. if (rectangularity >= minRectangularity)
  54. {
  55. // 获取轮廓的边界矩形
  56. Rect boundingRect = Cv2.BoundingRect(contour);
  57. BlobInfo blobInfo = new BlobInfo
  58. {
  59. Contour = contour,
  60. Area = area,
  61. Rectangularity = rectangularity,
  62. BoundingRect = boundingRect,
  63. Center = new CvPoint(boundingRect.X + boundingRect.Width / 2,
  64. boundingRect.Y + boundingRect.Height / 2)
  65. };
  66. filteredBlobs.Add(blobInfo);
  67. Console.WriteLine($"轮廓 - 面积: {area:F0} 像素, 矩形度: {rectangularity:F2}");
  68. }
  69. }
  70. }
  71. Console.WriteLine($"原始轮廓数量: {contours.Length}");
  72. Console.WriteLine($"筛选后轮廓数量: {filteredBlobs.Count}");
  73. if (filteredBlobs.Count == 1)
  74. {
  75. Console.WriteLine("有说明书,输出状态为正常");
  76. }
  77. else
  78. {
  79. Console.WriteLine("没有说明书或是识别出多个说明书,输出状态为异常");
  80. }
  81. // 在原图上绘制筛选后的轮廓
  82. Mat outputImage = new Mat();
  83. foreach (var blobInfo in filteredBlobs)
  84. {
  85. Cv2.DrawContours(image, new[] { blobInfo.Contour }, -1, Scalar.Green, 100);
  86. }
  87. Cv2.ImShow("Output Image", ReadCodeTest.ResizeMat(image));
  88. // 显示统计信息
  89. if (filteredBlobs.Count > 0)
  90. {
  91. double avgRectangularity = filteredBlobs.Average(b => b.Rectangularity);
  92. double maxRectangularity = filteredBlobs.Max(b => b.Rectangularity);
  93. double minRectangularityFound = filteredBlobs.Min(b => b.Rectangularity);
  94. Console.WriteLine($"\n统计信息:");
  95. Console.WriteLine($"平均矩形度: {avgRectangularity:F2}");
  96. Console.WriteLine($"最大矩形度: {maxRectangularity:F2}");
  97. Console.WriteLine($"最小矩形度: {minRectangularityFound:F2}");
  98. }
  99. Cv2.WaitKey(0);
  100. }
  101. /// <summary>
  102. /// 计算轮廓的矩形度
  103. /// 矩形度 = 轮廓面积 / 最小外接矩形面积
  104. /// </summary>
  105. /// <param name="contour">轮廓点集</param>
  106. /// <returns>矩形度值 (0-1)</returns>
  107. static double CalculateRectangularity(CvPoint[] contour)
  108. {
  109. // 计算轮廓面积
  110. double contourArea = Cv2.ContourArea(contour);
  111. // 获取最小外接矩形
  112. RotatedRect minAreaRect = Cv2.MinAreaRect(contour);
  113. // 计算最小外接矩形面积
  114. double rectArea = minAreaRect.Size.Width * minAreaRect.Size.Height;
  115. // 避免除零错误
  116. if (rectArea <= 0)
  117. return 0;
  118. // 计算矩形度
  119. double rectangularity = contourArea / rectArea;
  120. // 确保值在合理范围内
  121. return Math.Max(0, Math.Min(1, rectangularity));
  122. }
  123. /// <summary>
  124. /// 将Bitmap转换为Mat
  125. /// </summary>
  126. /// <param name="bitmap">源Bitmap</param>
  127. /// <returns>对应的Mat对象</returns>
  128. static Mat BitmapToMat(Bitmap bitmap)
  129. {
  130. using (var ms = new MemoryStream())
  131. {
  132. bitmap.Save(ms, ImageFormat.Bmp);
  133. ms.Position = 0;
  134. return Mat.FromStream(ms, ImreadModes.Color);
  135. }
  136. }
  137. }
  138. /// <summary>
  139. /// Blob信息类
  140. /// </summary>
  141. class BlobInfo
  142. {
  143. /// <summary>
  144. /// 轮廓点集
  145. /// </summary>
  146. public CvPoint[] Contour { get; set; }
  147. /// <summary>
  148. /// 轮廓面积(像素数量)
  149. /// </summary>
  150. public double Area { get; set; }
  151. /// <summary>
  152. /// 矩形度 (0-1)
  153. /// </summary>
  154. public double Rectangularity { get; set; }
  155. /// <summary>
  156. /// 边界矩形
  157. /// </summary>
  158. public Rect BoundingRect { get; set; }
  159. /// <summary>
  160. /// 中心点
  161. /// </summary>
  162. public CvPoint Center { get; set; }
  163. }
  164. }