using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Structure; using Emgu.CV.UI; using Emgu.CV.Util; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; public class CommonUse { /// /// 获取给定图像的最大矩形边界 /// /// /// public VectorOfVectorOfPoint GetBoundaryOfPic(Mat src) { Mat dst = new Mat(); Mat src_gray = new Mat(); CvInvoke.CvtColor(src, src_gray, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray); //边缘检测 CvInvoke.Canny(src_gray, dst, 20, 255, 3, true); //寻找答题卡矩形边界(最大的矩形) VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();//创建VectorOfVectorOfPoint数据类型用于存储轮廓 CvInvoke.FindContours(dst, contours, null, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);//提取轮廓 VectorOfVectorOfPoint max_contour = new VectorOfVectorOfPoint();//用于存储筛选过后的轮廓 int ksize = contours.Size; //获取连通区域个数 if (ksize == 1) { max_contour = contours; } else { //double maxLength = -1;//用于保存轮廓周长的最大值 double maxArea = -1;//面积 int index = -1;//轮廓周长的最大值的序号 for (int i = 0; i < ksize; i++) { VectorOfPoint contour = contours[i];//获取独立的连通轮廓 //double length = CvInvoke.ArcLength(contour, true);//计算连通轮廓的周长 //if (length > maxLength) //{ // maxLength = length; // index = i; //} double area = CvInvoke.ContourArea(contour, false); if (area > maxArea) { maxArea = area; index = i; } } max_contour.Push(contours[index]);//筛选后的连通轮廓 } return max_contour; } /// /// 进行透视操作,获取矫正后图像 /// /// /// public Mat MyWarpPerspective(Mat src, VectorOfVectorOfPoint max_contour) { //拟合答题卡的几何轮廓,保存点集pts并顺时针排序 VectorOfPoint pts = new VectorOfPoint();//用于存放逼近的结果 VectorOfPoint tempContour = max_contour[0];//临时用 double result_length = CvInvoke.ArcLength(tempContour, true); CvInvoke.ApproxPolyDP(tempContour, pts, result_length * 0.02, true); //几何逼近,获取矩形4个顶点坐标 if (pts.Size != 4) { //最大轮廓不是矩形时,将原图转灰度图后返回 Mat src_gray = new Mat(); CvInvoke.CvtColor(src, src_gray, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray);//转灰度图 return src_gray; } else { //Point[]转换为PointF[]类型 PointF[] pts_src = Array.ConvertAll(pts.ToArray(), new Converter(PointToPointF)); //点集顺时针排序 pts_src = SortPointsByClockwise(pts_src); //确定透视变换的宽度、高度 Size sizeOfRect = CalSizeOfRect(pts_src); int width = src.Bitmap.Width; int height = src.Bitmap.Height; //计算透视变换矩阵 PointF[] pts_target = new PointF[] { new PointF(0, 0), new PointF(width - 1, 0) , new PointF(width - 1, height - 1) ,new PointF(0, height - 1)}; //计算透视矩阵 Mat data = CvInvoke.GetPerspectiveTransform(pts_src, pts_target); //进行透视操作 Mat src_gray = new Mat(); Mat mat_Perspective = new Mat(); CvInvoke.CvtColor(src, src_gray, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray); CvInvoke.WarpPerspective(src_gray, mat_Perspective, data, new Size(width, height)); return mat_Perspective; } } /// /// 根据给定XY初始坐标、间距、数量画网格 /// /// /// /// /// /// /// /// /// public Bitmap DrawGridByXYDraw(Bitmap bmp, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num) { Mat src = new Image(bmp).Mat; //转换颜色空间 Mat mat_color = new Mat(); if (src.NumberOfChannels == 1) CvInvoke.CvtColor(src, mat_color, Emgu.CV.CvEnum.ColorConversion.Gray2Bgr); else mat_color = src; for (int i = 0; i <= x_num; i++) { //先画竖线 Point p1 = new Point(x_begin + x_interval * i, y_begin); Point p2 = new Point(x_begin + x_interval * i, y_begin + y_interval * y_num); CvInvoke.Line(mat_color, p1, p2, new MCvScalar(0, 0, 255), 2); } for (int i = 0; i <= y_num; i++) { //再画横线 Point p1 = new Point(x_begin, y_begin + y_interval * i); Point p2 = new Point(x_begin + x_interval * x_num, y_begin + y_interval * i); CvInvoke.Line(mat_color, p1, p2, new MCvScalar(0, 0, 255), 2); } return mat_color.Bitmap; } /// /// 获取偏移量 通过矩形查找 /// /// /// /// /// /// /// public Mat GetPostionXYByFindPostionAndXieLv(Mat color_mat, VectorOfVectorOfPoint selected_contours, string postionCut, out string PYPostion, Image currentFrame, out double xielv) { CommonUse commonUse = new CommonUse(); string[] postionc = postionCut.Split('^'); PYPostion = ""; Point GrXY; int PostionWW = 0; int PostionHH = 0; int Y2 = 0, Y1 = 0, X2 = 0, X1 = 0; for (int i = 0; i < postionc.Length; i++) { string[] postCutList = postionc[i].Split(','); int X = Convert.ToInt32(Convert.ToDouble(postCutList[0])); int Y = Convert.ToInt32(Convert.ToDouble(postCutList[1])); int W = Convert.ToInt32(Convert.ToDouble(postCutList[2])); int H = Convert.ToInt32(Convert.ToDouble(postCutList[3])); string mx = ""; try { mx = commonUse.GetValueAndDrawGrid_Find(color_mat.Bitmap, selected_contours, X, W, 1, Y, H, 1, "", out GrXY); } catch { xielv = -100; return null; mx = "null"; GrXY = new Point(0, 0); } if (mx.Trim() != "A") { xielv = -100; return null; break; } Point Mx = GrXY; if (i == 0)//左上角 { PYPostion = GrXY.X + "," + GrXY.Y; Y1 = GrXY.Y; X1 = GrXY.X; } if (i == 1)//右上角 { PostionWW = GrXY.X; } if (i == 2)//左下角 { PostionHH = GrXY.Y; X2 = GrXY.X; Y2 = GrXY.Y; } } string[] posList = PYPostion.Split(','); xielv = Math.Atan2((Y2 - Y1), (X2 - X1)) * 180 / Math.PI; int PostionX = Convert.ToInt32(posList[0]); int PostionY = Convert.ToInt32(posList[1]); int PostionW = PostionWW - PostionX; int PostionH = PostionHH - PostionY; //裁剪 Rectangle rectangle = new Rectangle(PostionX, PostionY, PostionW, PostionH); Image Sub = new Image(currentFrame.Bitmap).GetSubRect(rectangle); Image CropImage = new Image(Sub.Size); CvInvoke.cvCopy(Sub, CropImage, IntPtr.Zero); //获取偏移量 return CropImage.Mat; } /// /// 将给定点集顺时针排序 /// /// 四边形四个顶点组成的点集 /// public PointF[] SortPointsByClockwise(PointF[] pts_src) { if (pts_src.Length != 4) return null;//确保为四边形 //求四边形中心点?坐标 float x_average = 0; float y_average = 0; float x_sum = 0; float y_sum = 0; for (int i = 0; i < 4; i++) { x_sum += pts_src[i].X; y_sum += pts_src[i].Y; } x_average = x_sum / 4; y_average = y_sum / 4; PointF center = new PointF(x_average, y_average); PointF[] result = new PointF[4]; for (int i = 0; i < 4; i++) { if (pts_src[i].X < center.X && pts_src[i].Y < center.Y) { result[0] = pts_src[i];//左上角点 continue; } if (pts_src[i].X > center.X && pts_src[i].Y < center.Y) { result[1] = pts_src[i];//右上角点 continue; } if (pts_src[i].X > center.X && pts_src[i].Y > center.Y) { result[2] = pts_src[i];//右下角点 continue; } if (pts_src[i].X < center.X && pts_src[i].Y > center.Y) { result[3] = pts_src[i];//左下角点 continue; } } return result; } /// /// 计算给定四个坐标点四边形的宽、高 /// /// /// public Size CalSizeOfRect(PointF[] pts_src) { if (pts_src.Length != 4) return new Size(0, 0);//确保为四边形 //点集顺时针排序 pts_src = SortPointsByClockwise(pts_src); //确定透视变换的宽度、高度 int width; int height; double width1 = Math.Pow(pts_src[0].X - pts_src[1].X, 2) + Math.Pow(pts_src[0].Y - pts_src[1].Y, 2); double width2 = Math.Pow(pts_src[2].X - pts_src[3].X, 2) + Math.Pow(pts_src[2].Y - pts_src[3].Y, 2); width = width1 > width2 ? (int)Math.Sqrt(width1) : (int)Math.Sqrt(width2);//根号下a方+b方,且取宽度最大的 double height1 = Math.Pow(pts_src[0].X - pts_src[3].X, 2) + Math.Pow(pts_src[0].Y - pts_src[3].Y, 2); double height2 = Math.Pow(pts_src[1].X - pts_src[2].X, 2) + Math.Pow(pts_src[1].Y - pts_src[2].Y, 2); height = height1 > height2 ? (int)Math.Sqrt(height1) : (int)Math.Sqrt(height2); return new Size(width, height); } /// /// Point转换为PointF类型 /// /// /// public static PointF PointToPointF(Point p) { return new PointF(p.X, p.Y); } /// /// 形态学膨胀 /// /// /// public Mat MyDilate(Mat mat) { //1.膨胀,改善轮廓 Mat struct_element = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Cross, new Size(3, 3), new Point(-1, -1));//结构元素 Mat mat_dilate = new Mat(); CvInvoke.MorphologyEx(mat, mat_dilate, Emgu.CV.CvEnum.MorphOp.Dilate, struct_element, new Point(-1, -1), 1, Emgu.CV.CvEnum.BorderType.Default, new MCvScalar(0, 0, 0));//形态学膨胀 return mat_dilate; } /// /// 筛选图中符合给定条件的轮廓 /// /// 要提取轮廓的图片 /// 轮廓外接矩形大于该宽度值 /// 轮廓外接矩形小于该宽度值 /// 轮廓外接矩形大于该高度值 /// 轮廓外接矩形小于该高度值 public VectorOfVectorOfPoint GetUsefulContours(Mat mat, double ratio) { VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();//所有的轮廓 VectorOfVectorOfPoint selected_contours = new VectorOfVectorOfPoint();//用于存储筛选过后的轮廓 CvInvoke.FindContours(mat, contours, null, Emgu.CV.CvEnum.RetrType.List, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);//提取所有轮廓,操作过程中会对输入图像进行修改 //筛选轮廓。筛选条件:长宽比大于给定值 for (int i = 0; i < contours.Size; i++) { Rectangle rect = CvInvoke.BoundingRectangle(contours[i]);//外接矩形 Mat temp = new Mat(mat, rect);//提取ROI矩形区域 int pxNums = CvInvoke.CountNonZero(temp);//计算图像内非零像素个数 double area = CvInvoke.ContourArea(contours[i]);//计算连通轮廓的面积 double length = CvInvoke.ArcLength(contours[i], false); //计算连通轮廓的周长 VectorOfPoint approx_curve = new VectorOfPoint();//用于存放逼近的结果 CvInvoke.ApproxPolyDP(contours[i], approx_curve, length * 0.05, true); bool bo = ((rect.Width > 8 && rect.Height > 3) && (area > 200 && area < 8000) && (rect.Width < 50 && rect.Height < 50) && pxNums > 100); if (bo) { selected_contours.Push(contours[i]); } } return selected_contours; } /// /// 筛选图中符合给定条件的轮廓 /// /// 要提取轮廓的图片 /// 轮廓外接矩形大于该宽度值 /// 轮廓外接矩形小于该宽度值 /// 轮廓外接矩形大于该高度值 /// 轮廓外接矩形小于该高度值 public VectorOfVectorOfPoint GetUsefulContoursDingWei(Mat mat, double ratio) { VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();//所有的轮廓 VectorOfVectorOfPoint selected_contours = new VectorOfVectorOfPoint();//用于存储筛选过后的轮廓 CvInvoke.FindContours(mat, contours, null, Emgu.CV.CvEnum.RetrType.List, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);//提取所有轮廓,操作过程中会对输入图像进行修改 //筛选轮廓。筛选条件:长宽比大于给定值 for (int i = 0; i < contours.Size; i++) { Rectangle rect = CvInvoke.BoundingRectangle(contours[i]);//外接矩形 Mat temp = new Mat(mat, rect);//提取ROI矩形区域 int pxNums = CvInvoke.CountNonZero(temp);//计算图像内非零像素个数 double area = CvInvoke.ContourArea(contours[i]);//计算连通轮廓的面积 double length = CvInvoke.ArcLength(contours[i], false); //计算连通轮廓的周长 VectorOfPoint approx_curve = new VectorOfPoint();//用于存放逼近的结果 CvInvoke.ApproxPolyDP(contours[i], approx_curve, length * 0.02, true); //外接矩形宽、高需在给定范围内 // bool bo = (rect.Width / rect.Height >= ratio && (rect.Width > 3 && rect.Height > 2) && (area > 200 && area <= 4500)); bool bo = ((rect.Width > 3 && rect.Height > 2) && (area > 100 && area <= 15000)); //bool bo = pxNums > 130 && pxNums < 300; if (bo) { selected_contours.Push(contours[i]); } } return selected_contours; } /// /// 筛选图中符合给定条件的轮廓 /// /// 要提取轮廓的图片 /// 轮廓外接矩形大于该宽度值 /// 轮廓外接矩形小于该宽度值 /// 轮廓外接矩形大于该高度值 /// 轮廓外接矩形小于该高度值 public VectorOfVectorOfPoint GetUsefulContoursDingWeiSanJiao(Mat mat, double ratio) { VectorOfVectorOfPoint selected_contours = new VectorOfVectorOfPoint(); using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { // 参数:输入图像,点向量,,检索类型,方法 CvInvoke.FindContours(mat, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); for (int i = 0; i < contours.Size; i++) { using (VectorOfPoint contour = contours[i]) //点的标准矢量 using (VectorOfPoint approxContour = new VectorOfPoint()) { // CvInvoke.ApproxPolyDP:指定精度的多边形曲线 参数:输入向量(轮廓),近似轮廓,近似精度,true:则闭合形状 // CvInvoke.ArcLength:计算轮廓长度 参数:轮廓,曲线是否闭合 CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.08, true); //0.08的相似度 //CvInvoke.ContourArea:计算轮廓面积 参数:轮廓,返回值是否为绝对值 //仅考虑面积大于50的轮廓 if (CvInvoke.ContourArea(approxContour, false) > 500) { if (approxContour.Size == 3)//轮廓有3个顶点:三角形 { Point[] points = approxContour.ToArray(); //转化为数组 selected_contours.Push(contours[i]); } } } } return selected_contours; } } /// /// 筛选图中符合给定条件的轮廓 /// /// 要提取轮廓的图片 /// 轮廓外接矩形大于该宽度值 /// 轮廓外接矩形小于该宽度值 /// 轮廓外接矩形大于该高度值 /// 轮廓外接矩形小于该高度值 public VectorOfVectorOfPoint GetUsefulContoursYueJuan(Mat mat, double ratio) { VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();//所有的轮廓 VectorOfVectorOfPoint selected_contours = new VectorOfVectorOfPoint();//用于存储筛选过后的轮廓 CvInvoke.FindContours(mat, contours, null, Emgu.CV.CvEnum.RetrType.List, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);//提取所有轮廓,操作过程中会对输入图像进行修改 //筛选轮廓。筛选条件:长宽比大于给定值 for (int i = 0; i < contours.Size; i++) { Rectangle rect = CvInvoke.BoundingRectangle(contours[i]);//外接矩形 Mat temp = new Mat(mat, rect);//提取ROI矩形区域 int pxNums = CvInvoke.CountNonZero(temp);//计算图像内非零像素个数 double area = CvInvoke.ContourArea(contours[i]);//计算连通轮廓的面积 double length = CvInvoke.ArcLength(contours[i], false); //计算连通轮廓的周长 VectorOfPoint approx_curve = new VectorOfPoint();//用于存放逼近的结果 CvInvoke.ApproxPolyDP(contours[i], approx_curve, length * 0.02, true); //外接矩形宽、高需在给定范围内 bool bo = (rect.Width / rect.Height >= ratio && (rect.Width > 3 && rect.Height > 2) && (area > 200 && area <= 4500)); // bool bo = ((rect.Width > 3 && rect.Height > 2) && (area > 200 && area <= 4500)); //bool bo = ((rect.Width > 3 && rect.Height > 2) && (area > 200 && area <= 4500)); //bool bo = pxNums > 130 && pxNums < 300; if (bo) { selected_contours.Push(contours[i]); } } return selected_contours; } /// /// 根据给定的轮廓及范围信息计算涂卡的结果,返回int数组 /// /// /// /// /// /// /// /// /// public int[] GetTargetGravityFind(VectorOfVectorOfPoint contours, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num, out Point gravityXY) { int[] result = new int[x_num];//结果数组 //数组初值默认为-1 for (int i = 0; i < x_num; i++) { result[i] = -1; } int x_max = x_begin + x_interval * x_num; int y_max = y_begin + y_interval * y_num; VectorOfVectorOfPoint targetContours = new VectorOfVectorOfPoint(); Point[] gravity = GetGravityOfContours(contours);//轮廓中心点坐标 gravityXY = new Point(0, 0); for (int i = 0; i < contours.Size; i++) { VectorOfPoint contour = contours[i]; if (gravity[i].X < x_begin || gravity[i].X > x_max || gravity[i].Y < y_begin || gravity[i].Y > y_max) { continue;//判断中心点是否超出范围 } int x_id = (int)Math.Floor((double)(gravity[i].X - x_begin) / x_interval);//向下取整 int value = (int)Math.Floor((double)(gravity[i].Y - y_begin) / y_interval); if (result[x_id] != -1) { string str = string.Format("第{0}列存在多个答案!请擦拭干净后再扫描", x_id); result[x_id] = Convert.ToInt32(result[x_id].ToString() + value.ToString()); gravityXY = gravity[i]; } else { Rectangle rect = CvInvoke.BoundingRectangle(contour); //这里有修改 result[x_id] = value; gravityXY = gravity[i]; gravityXY.X = rect.X; gravityXY.Y = rect.Y; break; } } return result; } /// /// 根据给定的轮廓及范围信息计算涂卡的结果,返回int数组 /// /// /// /// /// /// /// /// /// public int[] GetTargetValues(VectorOfVectorOfPoint contours, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num) { int[] result = new int[x_num];//结果数组 //数组初值默认为-1 for (int i = 0; i < x_num; i++) { result[i] = -1; } int x_max = x_begin + x_interval * x_num; int y_max = y_begin + y_interval * y_num; VectorOfVectorOfPoint targetContours = new VectorOfVectorOfPoint(); Point[] gravity = GetGravityOfContours(contours);//轮廓中心点坐标 for (int i = 0; i < contours.Size; i++) { VectorOfPoint contour = contours[i]; if (gravity[i].X < x_begin || gravity[i].X > x_max || gravity[i].Y < y_begin || gravity[i].Y > y_max) { continue;//判断中心点是否超出范围 } int x_id = (int)Math.Floor((double)(gravity[i].X - x_begin) / x_interval);//向下取整 int value = (int)Math.Floor((double)(gravity[i].Y - y_begin) / y_interval); if (result[x_id] != -1) { string str = string.Format("第{0}列存在多个答案!请擦拭干净后再扫描", x_id); //MessageBox.Show(x_id.ToString()); result[x_id] = Convert.ToInt32(result[x_id].ToString() + value.ToString()); //result[x_id] = -1; } else { result[x_id] = value; } } return result; } /// /// 根据给定的轮廓及范围信息计算涂卡的结果,返回int数组 /// /// /// /// /// /// /// /// /// public int[] GetTargetValuesOnlyOne(VectorOfVectorOfPoint contours, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num) { int[] result = new int[x_num];//结果数组 //数组初值默认为-1 for (int i = 0; i < x_num; i++) { result[i] = -1; } int x_max = x_begin + x_interval * x_num; int y_max = y_begin + y_interval * y_num; VectorOfVectorOfPoint targetContours = new VectorOfVectorOfPoint(); Point[] gravity = GetGravityOfContours(contours);//轮廓中心点坐标 for (int i = 0; i < contours.Size; i++) { VectorOfPoint contour = contours[i]; if (gravity[i].X < x_begin || gravity[i].X > x_max || gravity[i].Y < y_begin || gravity[i].Y > y_max) { continue;//判断中心点是否超出范围 } int x_id = (int)Math.Floor((double)(gravity[i].X - x_begin) / x_interval);//向下取整 int value = (int)Math.Floor((double)(gravity[i].Y - y_begin) / y_interval); if (result[x_id] != -1) { //string str = string.Format("第{0}列存在多个答案!请擦拭干净后再扫描", x_id); //MessageBox.Show(x_id.ToString()); //result[x_id] = Convert.ToInt32(result[x_id].ToString() + value.ToString()); //result[x_id] = -1; } else { result[x_id] = value; } } return result; } // /// 根据给定的轮廓及范围信息计算涂卡的结果,返回int数组 /// /// /// /// /// /// /// /// /// public int[] GetTargetValues_L(VectorOfVectorOfPoint contours, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num) { int[] result = new int[y_num];//结果数组 //数组初值默认为-1 for (int i = 0; i < y_num; i++) { result[i] = -1; } int x_max = x_begin + x_interval * x_num; int y_max = y_begin + y_interval * y_num; VectorOfVectorOfPoint targetContours = new VectorOfVectorOfPoint(); Point[] gravity = GetGravityOfContours(contours);//轮廓中心点坐标 for (int i = 0; i < contours.Size; i++) { VectorOfPoint contour = contours[i]; if (gravity[i].X < x_begin || gravity[i].X > x_max || gravity[i].Y < y_begin || gravity[i].Y > y_max) { continue;//判断中心点是否超出范围 } int x_id = (int)Math.Floor((double)(gravity[i].Y - y_begin) / y_interval);//向右取整数 int value = (int)Math.Floor((double)(gravity[i].X - x_begin) / x_interval); if (result[x_id] != -1) { string str = string.Format("第{0}列存在多个答案!请擦拭干净后再扫描", x_id); result[x_id] = Convert.ToInt32(result[x_id].ToString() + value.ToString()); } else { result[x_id] = value; } } return result; } // /// 根据给定的轮廓及范围信息计算涂卡的结果,返回int数组 /// /// /// /// /// /// /// /// /// public int[] GetTargetValues_L_only(VectorOfVectorOfPoint contours, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num) { int[] result = new int[y_num];//结果数组 //数组初值默认为-1 for (int i = 0; i < y_num; i++) { result[i] = -1; } int x_max = x_begin + x_interval * x_num; int y_max = y_begin + y_interval * y_num; VectorOfVectorOfPoint targetContours = new VectorOfVectorOfPoint(); Point[] gravity = GetGravityOfContours(contours);//轮廓中心点坐标 for (int i = 0; i < contours.Size; i++) { VectorOfPoint contour = contours[i]; if (gravity[i].X < x_begin || gravity[i].X > x_max || gravity[i].Y < y_begin || gravity[i].Y > y_max) { continue;//判断中心点是否超出范围 } int x_id = (int)Math.Floor((double)(gravity[i].Y - y_begin) / y_interval);//向右取整数 int value = (int)Math.Floor((double)(gravity[i].X - x_begin) / x_interval); if (result[x_id] != -1) { //string str = string.Format("第{0}列存在多个答案!请擦拭干净后再扫描", x_id); //result[x_id] = Convert.ToInt32(result[x_id].ToString() + value.ToString()); } else { result[x_id] = value; } } return result; } /// /// 画出网格并返回填图结果 /// /// /// /// 左边距 /// 方块长度 /// 方块数量 /// 上边距 /// 方块高度 /// 方块竖数量 /// 输出文字 /// //public string GetValueAndDrawGridZhunKao(ImageBox img, VectorOfVectorOfPoint contours, // int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num, string strText) //{ // //画网格 // //Mat src = new Image(img.Image.Bitmap).Mat; // //Mat mat_grid = DrawGridByXY(img, x_begin, x_interval, x_num, y_begin, y_interval, y_num); // int[] intArray = GetTargetValues(contours, x_begin, x_interval, x_num, y_begin, y_interval, y_num); // int maxValue = GetMaxValueOfArray(intArray);//数组最大值 // string str = ""; // //str += Environment.NewLine;//回车 // str += strText; // str += GetStringOfIntArray(intArray); // return str; //} /// /// 画出网格并返回填图结果 /// /// /// /// 左边距 /// 方块长度 /// 方块数量 /// 上边距 /// 方块高度 /// 方块竖数量 /// 输出文字 /// public string GetValueAndDrawGridZhunKao(Bitmap img, VectorOfVectorOfPoint contours, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num, string strText) { //画网格 int[] intArray = GetTargetValuesOnlyOne(contours, x_begin, x_interval, x_num, y_begin, y_interval, y_num); int maxValue = GetMaxValueOfArray(intArray);//数组最大值 string str = ""; str += strText; str += GetStringOfIntArray(intArray); return str; } ///// ///// 画出网格并返回填图结果 ///// ///// ///// ///// 左边距 ///// 方块长度 ///// 方块数量 ///// 上边距 ///// 方块高度 ///// 方块竖数量 ///// 输出文字 ///// //public string GetValueAndDrawGrid(ImageBox img, VectorOfVectorOfPoint contours, // int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num, string strText) //{ // //画网格 // //Mat src = new Image(img.Image.Bitmap).Mat; // //Mat mat_grid = DrawGridByXY(img, x_begin, x_interval, x_num, y_begin, y_interval, y_num); // int[] intArray = GetTargetValues(contours, x_begin, x_interval, x_num, y_begin, y_interval, y_num); // int maxValue = GetMaxValueOfArray(intArray);//数组最大值 // string str = ""; // //str += Environment.NewLine;//回车 // str += strText; // if (maxValue >= 4 && maxValue <10) // { // str += GetStringOfIntArray(intArray); // } // else // { // if (maxValue >= 10) // { // str += GetStringOfIntArray(intArray, "ABCD"); // } // else // { // str += GetStringOfIntArray(intArray, "ABCD"); // } // } // return str; //} /// /// 画出网格并返回填图结果 /// /// /// /// 左边距 /// 方块长度 /// 方块数量 /// 上边距 /// 方块高度 /// 方块竖数量 /// 输出文字 /// public string GetValueAndDrawGrid(Bitmap img, VectorOfVectorOfPoint contours, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num, string strText) { //画网格 // Mat mat_grid = DrawGridByXY(img, x_begin, x_interval, x_num, y_begin, y_interval, y_num); int[] intArray = GetTargetValuesOnlyOne(contours, x_begin, x_interval, x_num, y_begin, y_interval, y_num); int maxValue = GetMaxValueOfArray(intArray);//数组最大值 string str = ""; //str += Environment.NewLine;//回车 str += strText; if (maxValue >= 4 && maxValue < 10) { str += GetStringOfIntArray(intArray, "ABCDEFG"); } else { if (maxValue >= 10) { str += GetStringOfIntArray(intArray, "ABCDEFG"); } else { str += GetStringOfIntArray(intArray, "ABCDEFG"); } } return str; } /// /// 画出网格并返回填图结果 /// /// /// /// 左边距 /// 方块长度 /// 方块数量 /// 上边距 /// 方块高度 /// 方块竖数量 /// 输出文字 /// public string GetValueAndDrawGrid_L(Bitmap img, VectorOfVectorOfPoint contours, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num, string strText) { //画网格 //Mat mat_grid = DrawGridByXY(img, x_begin, x_interval, x_num, y_begin, y_interval, y_num); int[] intArray = GetTargetValues_L_only(contours, x_begin, x_interval, x_num, y_begin, y_interval, y_num); int maxValue = GetMaxValueOfArray(intArray);//数组最大值 string str = ""; //str += Environment.NewLine;//回车 str += strText; if (maxValue >= 4 && maxValue < 10) { str += GetStringOfIntArray(intArray, "ABCDEFG"); } else { if (maxValue >= 10) { str += GetStringOfIntArray(intArray, "ABCDEFG"); } else { str += GetStringOfIntArray(intArray, "ABCDEFG"); } } return str; } /// /// 画出网格并返回填图结果 /// /// /// /// 左边距 /// 方块长度 /// 方块数量 /// 上边距 /// 方块高度 /// 方块竖数量 /// 输出文字 /// public string GetValueAndDrawGrid_Find(Bitmap img, VectorOfVectorOfPoint contours, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num, string strText, out Point pFindX) { //画网格 Point pFind; int[] intArray = GetTargetGravityFind(contours, x_begin, x_interval, x_num, y_begin, y_interval, y_num, out pFind); int maxValue = GetMaxValueOfArray(intArray);//数组最大值 pFindX = pFind; string str = ""; //str += Environment.NewLine;//回车 str += strText; if (maxValue >= 4 && maxValue < 10) { str += GetStringOfIntArray(intArray); } else { if (maxValue >= 10) { str += GetStringOfIntArray(intArray, "ABCDEF"); } else { str += GetStringOfIntArray(intArray, "ABCDEF"); } } return str; } /// /// 画出网格并返回填图结果 /// /// /// /// 左边距 /// 方块长度 /// 方块数量 /// 上边距 /// 方块高度 /// 方块竖数量 /// 输出文字 /// //public Mat GetDrawGrid(ImageBox img, VectorOfVectorOfPoint contours, // int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num, string strText) //{ // //画网格 // Mat mat_grid = DrawGridByXY(img, x_begin, x_interval, x_num, y_begin, y_interval, y_num); // return mat_grid; //} public Mat GetDrawGrid(Bitmap img, VectorOfVectorOfPoint contours, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num, string strText) { //画网格 Mat mat_grid = DrawGridByXY(img, x_begin, x_interval, x_num, y_begin, y_interval, y_num); return mat_grid; } ///// ///// 画出网格并返回填图结果 ///// ///// ///// ///// 左边距 ///// 方块长度 ///// 方块数量 ///// 上边距 ///// 方块高度 ///// 方块竖数量 ///// 输出文字 ///// //public string GetValueAndDrawGridMore(ImageBox img, VectorOfVectorOfPoint contours, // int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num, string strText) //{ // //画网格 // //Mat src = new Image(img.Image.Bitmap).Mat; // //Mat mat_grid = DrawGridByXY(img, x_begin, x_interval, x_num, y_begin, y_interval, y_num); // int[] intArray = GetTargetValues(contours, x_begin, x_interval, x_num, y_begin, y_interval, y_num); // int maxValue = GetMaxValueOfArray(intArray);//数组最大值 // string str = ""; // str += strText; // if (maxValue >= 7&& maxValue <10) // { // str += GetStringOfIntArray(intArray); // } // else // { // str += GetStringOfIntArray(intArray, "ABCDEFG"); // } // return str; //} /// /// 画出网格并返回填图结果 /// /// /// /// 左边距 /// 方块长度 /// 方块数量 /// 上边距 /// 方块高度 /// 方块竖数量 /// 输出文字 /// public string GetValueAndDrawGridMore(Bitmap img, VectorOfVectorOfPoint contours, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num, string strText) { //画网格 //Mat src = new Image(img.Image.Bitmap).Mat; //Mat mat_grid = DrawGridByXY(img, x_begin, x_interval, x_num, y_begin, y_interval, y_num); int[] intArray = GetTargetValues(contours, x_begin, x_interval, x_num, y_begin, y_interval, y_num); int maxValue = GetMaxValueOfArray(intArray);//数组最大值 string str = ""; str += strText; if (maxValue >= 7 && maxValue < 10) { str += GetStringOfIntArray(intArray); } else { str += GetStringOfIntArray(intArray, "ABCDEFG"); } return str; } /// /// 画出网格并返回填图结果 /// /// /// /// 左边距 /// 方块长度 /// 方块数量 /// 上边距 /// 方块高度 /// 方块竖数量 /// 输出文字 /// public string GetValueAndDrawGridMoreL(Bitmap img, VectorOfVectorOfPoint contours, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num, string strText) { //画网格 //Mat mat_grid = DrawGridByXY(img, x_begin, x_interval, x_num, y_begin, y_interval, y_num); int[] intArray = GetTargetValues_L(contours, x_begin, x_interval, x_num, y_begin, y_interval, y_num); int maxValue = GetMaxValueOfArray(intArray);//数组最大值 string str = ""; str += strText; if (maxValue >= 7 && maxValue < 10) { str += GetStringOfIntArray(intArray); } else { str += GetStringOfIntArray(intArray, "ABCDEFG"); } return str; } /// /// 计算轮廓中心点坐标 /// /// 要计算中心点的轮廓 /// public Point[] GetGravityOfContours(VectorOfVectorOfPoint selected_contours) { int ksize = selected_contours.Size; double[] m00 = new double[ksize]; double[] m01 = new double[ksize]; double[] m10 = new double[ksize]; Point[] gravity = new Point[ksize];//用于存储轮廓中心点坐标 MCvMoments[] moments = new MCvMoments[ksize]; for (int i = 0; i < ksize; i++) { VectorOfPoint contour = selected_contours[i]; //计算当前轮廓的矩 moments[i] = CvInvoke.Moments(contour, false); m00[i] = moments[i].M00; m01[i] = moments[i].M01; m10[i] = moments[i].M10; int x = Convert.ToInt32(m10[i] / m00[i]);//计算当前轮廓中心点坐标 int y = Convert.ToInt32(m01[i] / m00[i]); gravity[i] = new Point(x, y); } return gravity; } ///// ///// 根据给定XY初始坐标、间距、数量画网格 ///// ///// ///// ///// ///// ///// ///// ///// ///// //public Mat DrawGridByXY(ImageBox img, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num) //{ // Mat src = new Image(img.Image.Bitmap).Mat; // //转换颜色空间 // Mat mat_color = new Mat(); // if (src.NumberOfChannels == 1) // CvInvoke.CvtColor(src, mat_color, Emgu.CV.CvEnum.ColorConversion.Gray2Bgr); // else // mat_color = src; // for (int i = 0; i <= x_num; i++) // { // //先画竖线 // Point p1 = new Point(x_begin + x_interval * i, y_begin); // Point p2 = new Point(x_begin + x_interval * i, y_begin + y_interval * y_num); // CvInvoke.Line(mat_color, p1, p2, new MCvScalar(0, 0, 255), 1); // } // for (int i = 0; i <= y_num; i++) // { // //再画横线 // Point p1 = new Point(x_begin, y_begin + y_interval * i); // Point p2 = new Point(x_begin + x_interval * x_num, y_begin + y_interval * i); // CvInvoke.Line(mat_color, p1, p2, new MCvScalar(0, 0, 255), 1); // } // img.Image = mat_color; // return mat_color; //} /// /// 根据给定XY初始坐标、间距、数量画网格 /// /// /// /// /// /// /// /// /// public Mat DrawGridByXY(Bitmap img, int x_begin, int x_interval, int x_num, int y_begin, int y_interval, int y_num) { Mat src = new Image(img).Mat; //转换颜色空间 Mat mat_color = new Mat(); if (src.NumberOfChannels == 1) CvInvoke.CvtColor(src, mat_color, Emgu.CV.CvEnum.ColorConversion.Gray2Bgr); else mat_color = src; for (int i = 0; i <= x_num; i++) { //先画竖线 Point p1 = new Point(x_begin + x_interval * i, y_begin); Point p2 = new Point(x_begin + x_interval * i, y_begin + y_interval * y_num); CvInvoke.Line(mat_color, p1, p2, new MCvScalar(0, 0, 255), 1); } for (int i = 0; i <= y_num; i++) { //再画横线 Point p1 = new Point(x_begin, y_begin + y_interval * i); Point p2 = new Point(x_begin + x_interval * x_num, y_begin + y_interval * i); CvInvoke.Line(mat_color, p1, p2, new MCvScalar(0, 0, 255), 1); } //img.Image = mat_color; return mat_color; } /// /// 画出给定轮廓 /// /// /// /// public Mat DrawContours(Mat mat, VectorOfVectorOfPoint contours) { //转换颜色空间 Mat mat_color = new Mat(); CvInvoke.CvtColor(mat, mat_color, Emgu.CV.CvEnum.ColorConversion.Gray2Bgr); CvInvoke.DrawContours(mat_color, contours, -1, new MCvScalar(255, 0, 0), 2); return mat_color; } /// /// 拼接给定int数组内容,并返回拼接后字符串 /// /// /// public string GetStringOfIntArray(int[] arr) { string str = ""; foreach (int a in arr) { str += a.ToString() + ""; } return str; } /// /// 拼接给定int数组内容,并返回拼接后字符串 /// /// /// public string GetStringOfIntArray(int[] arr, string ss = "ABCD") { string str = ""; //char[] ch = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G' }; char[] ch = ss.ToCharArray(); foreach (int a in arr) { /// if (a >= 10) { string x = a.ToString(); char[] cc = x.ToArray(); int[] result = new int[cc.Length]; for (int i = 0; i < cc.Length; i++) { result[i] = Convert.ToInt32(x.Substring(i, 1)); } Array.Sort(result); int[] finalResult = result; for (int j = 0; j < finalResult.Length; j++) { if (finalResult[j] == -1) { str += "null"; } else { str += ch[finalResult[j]]; } } str += " "; } else { if (a == -1) { str += "null ";//未识别时,标示为空 } else { str += ch[a] + " "; } } } return str; } /// /// 获取一维int数组中最大值 /// /// /// public int GetMaxValueOfArray(int[] arr) { int[] dst = new int[arr.Length]; Array.Copy(arr, dst, arr.Length);//深度复制数组,防止排序对原数组产生影响 Array.Sort(dst);//数组排序 int maxValue = dst[arr.Length - 1];//数组最大值 return maxValue; } /// /// 显示图像,并等待按下任意按键后继续 /// /// /// /// public void ShowMatWaitKey(string title, Mat mat, double zoomRatio) { CvInvoke.Resize(mat, mat, new Size(), zoomRatio, zoomRatio, Inter.Cubic); CvInvoke.Imshow(title, mat); CvInvoke.WaitKey(0); } public Bitmap RotateByOrientation(Bitmap bitmap) { // 获取图片的方向信息并根据方向调整图片 if (bitmap.PropertyIdList.Contains(0x0112)) { var orientation = (int)bitmap.GetPropertyItem(0x0112).Value[0]; switch (orientation) { case 2: bitmap.RotateFlip(RotateFlipType.RotateNoneFlipX); break; case 3: bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone); break; case 4: bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); break; case 5: bitmap.RotateFlip(RotateFlipType.Rotate90FlipX); break; case 6: bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone); break; case 7: bitmap.RotateFlip(RotateFlipType.Rotate270FlipX); break; case 8: bitmap.RotateFlip(RotateFlipType.Rotate270FlipNone); break; } } return bitmap; } } public class ZhuguantiList { public int QuestionSmallNum { get; set; } public Bitmap btm { get; set; } public string num { get; set; } } public class otherBitmaplist { public Bitmap btm { get; set; } public string Text { get; set; } }