using System; using System.Collections.Generic; using System.Text; namespace HTEXScan.Models { /**文件**/ class File { /**数据**/ protected Data data = null; /**学生id**/ protected Sid sid = null; /**绑定数据**/ public void Bind(Data data) { this.data = data; } /**读取**/ public void Read() { //原图 OpenCvSharp.Mat mat = new OpenCvSharp.Mat(this.data.Path); //轮廓 OpenCvSharp.Point[] contour = this.GetExternalContours(mat, 60, 120, 10); //顶点 OpenCvSharp.Point2f[] vertex = this.GetVertexPoints(contour); //透视变换顶点 OpenCvSharp.Point2f[] wrapVertex = this.GetWarperspectivePoints(mat, vertex); //透视变换图 OpenCvSharp.Mat wpMat = this.WarpPerspective(mat, vertex, wrapVertex); //检测表格 this.sid = new Sid(); this.CheckCells(wpMat); this.data.Sid = this.sid.Get(); OpenCvSharp.Cv2.Rectangle(mat, OpenCvSharp.Cv2.BoundingRect(contour), OpenCvSharp.Scalar.Red, 5); for (int i = 0; i < vertex.Length; i++) OpenCvSharp.Cv2.Circle(mat, vertex[i].ToPoint(), 20, OpenCvSharp.Scalar.Blue, 20); this.Save(mat, wpMat); if (this.data.Show) { this.Show(mat); this.Show(wpMat); } mat.Release(); wpMat.Release(); } /**最大轮廓**/ protected int GetMaxContour(OpenCvSharp.Point[][] contours) { int i = 0, index = 0; double area = 0, maxArea = 0; for (i = 0; i < contours.Length; i++) { area = OpenCvSharp.Cv2.ContourArea(contours[i]); if (area > maxArea) { index = i; maxArea = area; } } return index; } /**获取外部最大轮廓**/ protected OpenCvSharp.Point[] GetMaxExternalContours(OpenCvSharp.Mat grayMat, double thresh) { OpenCvSharp.Point[][] contours = null; OpenCvSharp.HierarchyIndex[] hierarchly = null; //二值化 OpenCvSharp.Mat tsMat = new OpenCvSharp.Mat(); OpenCvSharp.Cv2.Threshold(grayMat, tsMat, thresh, 255, OpenCvSharp.ThresholdTypes.Tozero); //高斯模糊 OpenCvSharp.Mat blurredMat = new OpenCvSharp.Mat(); OpenCvSharp.Cv2.GaussianBlur(tsMat, blurredMat, new OpenCvSharp.Size(5, 5), 0); //边缘检测 OpenCvSharp.Mat edgedMat = new OpenCvSharp.Mat(); OpenCvSharp.Cv2.Canny(blurredMat, edgedMat, 0, 255); OpenCvSharp.Cv2.FindContours(edgedMat, out contours, out hierarchly, OpenCvSharp.RetrievalModes.External, OpenCvSharp.ContourApproximationModes.ApproxSimple); tsMat.Release(); blurredMat.Release(); edgedMat.Release(); return contours[this.GetMaxContour(contours)]; } /**获取外部轮廓**/ protected OpenCvSharp.Point[] GetExternalContours(OpenCvSharp.Mat mat, double threshStart, double threshEnd, double threshSep) { OpenCvSharp.Point[] contour = null, contourTmp; //灰度 OpenCvSharp.Mat grayMat = new OpenCvSharp.Mat(); OpenCvSharp.Cv2.CvtColor(mat, grayMat, OpenCvSharp.ColorConversionCodes.BGR2GRAY); for (double thresh = threshStart; thresh < threshEnd; thresh += threshSep) { contourTmp = this.GetMaxExternalContours(grayMat, thresh); if (contour == null || OpenCvSharp.Cv2.ContourArea(contourTmp) > OpenCvSharp.Cv2.ContourArea(contour)) contour = contourTmp; } grayMat.Release(); return contour; } /**轮廓顶点**/ protected OpenCvSharp.Point2f[] GetVertexPoints(OpenCvSharp.Point[] contours) { OpenCvSharp.Point2f[] points = new OpenCvSharp.Point2f[4]; double d0 = 0, d1 = 0, d2 = 0, d3 = 0, d = 0; OpenCvSharp.Rect rect = OpenCvSharp.Cv2.BoundingRect(contours); for (int i = 0; i < contours.Length; i++) { //矩形左上角 d = System.Math.Sqrt( System.Math.Pow(contours[i].X - rect.X, 2) + System.Math.Pow(contours[i].Y - rect.Y, 2)); if (d0 == 0 || d < d0) { d0 = d; points[0] = contours[i]; } //矩形右上角 d = System.Math.Sqrt( System.Math.Pow(contours[i].X - rect.X - rect.Width, 2) + System.Math.Pow(contours[i].Y - rect.Y, 2)); if (d1 == 0 || d < d1) { d1 = d; points[1] = contours[i]; } //矩形左下角 d = System.Math.Sqrt( System.Math.Pow(contours[i].X - rect.X, 2) + System.Math.Pow(contours[i].Y - rect.Y - rect.Height, 2)); if (d2 == 0 || d < d2) { d2 = d; points[2] = contours[i]; } //矩形右下角 d = System.Math.Sqrt( System.Math.Pow(contours[i].X - rect.X - rect.Width, 2) + System.Math.Pow(contours[i].Y - rect.Y - rect.Height, 2)); if (d3 == 0 || d < d3) { d3 = d; points[3] = contours[i]; } } return points; } /**获取透视变换点**/ protected OpenCvSharp.Point2f[] GetWarperspectivePoints(OpenCvSharp.Mat mat, OpenCvSharp.Point2f[] points) { int cx = mat.Cols / 2, cy = mat.Rows / 2; OpenCvSharp.Point2f[] dstPoints = new OpenCvSharp.Point2f[4]; for (int i = 0; i < points.Length; i++) { if (points[i].X <= cx && points[i].Y <= cy) dstPoints[i] = new OpenCvSharp.Point2f(0, 0); else if (points[i].X <= cx && points[i].Y > cy) dstPoints[i] = new OpenCvSharp.Point2f(0, mat.Rows); else if (points[i].X > cx && points[i].Y < cy) dstPoints[i] = new OpenCvSharp.Point2f(mat.Cols, 0); else dstPoints[i] = new OpenCvSharp.Point2f(mat.Cols, mat.Rows); } return dstPoints; } /**透视变换**/ protected OpenCvSharp.Mat WarpPerspective(OpenCvSharp.Mat mat, OpenCvSharp.Point2f[] points, OpenCvSharp.Point2f[] toPoints) { OpenCvSharp.Mat wpMat = new OpenCvSharp.Mat(); //获取透视变化矩阵 OpenCvSharp.Mat mm = OpenCvSharp.Cv2.GetPerspectiveTransform(points, toPoints); OpenCvSharp.Cv2.WarpPerspective(mat, wpMat, mm, mat.Size()); mm.Release(); return wpMat; } /**检测表格**/ protected void CheckCell(OpenCvSharp.Mat wpMat, OpenCvSharp.Mat mat, TemplateCell cell, OpenCvSharp.Rect matRect) { OpenCvSharp.Point[][] contours = null; OpenCvSharp.HierarchyIndex[] hierarchly = null; //二值化 OpenCvSharp.Mat tsMat = new OpenCvSharp.Mat(); OpenCvSharp.Cv2.Threshold(mat, tsMat, 0, 255, OpenCvSharp.ThresholdTypes.Binary | OpenCvSharp.ThresholdTypes.Triangle); //矩形 OpenCvSharp.Cv2.Rectangle(tsMat, new OpenCvSharp.Rect(0, 0, mat.Width, mat.Height), OpenCvSharp.Scalar.White); //高斯模糊 OpenCvSharp.Mat blurredMat = new OpenCvSharp.Mat(); OpenCvSharp.Cv2.GaussianBlur(tsMat, blurredMat, new OpenCvSharp.Size(5, 5), 0); //边缘检测 OpenCvSharp.Mat edgedMat = new OpenCvSharp.Mat(); OpenCvSharp.Cv2.Canny(blurredMat, edgedMat, 0, 255); OpenCvSharp.Cv2.FindContours(edgedMat, out contours, out hierarchly, OpenCvSharp.RetrievalModes.List, OpenCvSharp.ContourApproximationModes.ApproxSimple); for (int i = 0; i < contours.Length; i++) { OpenCvSharp.Rect rect = OpenCvSharp.Cv2.BoundingRect(contours[i]); double s1 = rect.Width * rect.Height, s2 = mat.Width * mat.Height; if (s1 >= s2 * 0.35f && s1 <= s2 * 1.2f) { int cx = matRect.X + rect.X + rect.Width / 2, cy = matRect.Y + rect.Y + rect.Height / 2; if (matRect.Contains(cx, cy)) { if (this.data.Show) { OpenCvSharp.Cv2.Circle(wpMat, new OpenCvSharp.Point(cx, cy), 5, OpenCvSharp.Scalar.Green, 2); OpenCvSharp.Cv2.Circle(wpMat, new OpenCvSharp.Point(matRect.X + matRect.Width / 2, matRect.Y + matRect.Height / 2), 15, OpenCvSharp.Scalar.Blue, 2); } if (cell.Type == 1) this.sid.Add(cell.Col, cell.Text); if(cell.Type == 2) { Subject subject =null; if (this.data.Subject == null) { this.data.Subject = new List(); subject = new Subject(); subject.I = cell.Col; subject.Answer = new List(); this.data.Subject.Add(subject); } else { for(int m = 0;m < this.data.Subject.Count;m++) { if (this.data.Subject[m].I == cell.Col) { subject = this.data.Subject[m]; break; } } if(subject == null) { subject = new Subject(); subject.I = cell.Col; subject.Answer = new List(); this.data.Subject.Add(subject); } } subject.Answer.Add(cell.Text); } break; } } } tsMat.Release(); blurredMat.Release(); edgedMat.Release(); } /**检测表格集合**/ protected void CheckCells(OpenCvSharp.Mat mat) { //灰度 OpenCvSharp.Mat grayMat = new OpenCvSharp.Mat(); OpenCvSharp.Cv2.CvtColor(mat, grayMat, OpenCvSharp.ColorConversionCodes.BGR2GRAY); float sw = mat.Width * 1.0f / this.data.Template.Bw, sh = mat.Height * 1.0f / this.data.Template.Bh; OpenCvSharp.Mat rio = null; OpenCvSharp.Rect rect = new OpenCvSharp.Rect(); for (int i = 0; i < this.data.Template.Cell.Count; i++) { rect.X = (int)(this.data.Template.Cell[i].X * sw); rect.Y = (int)(this.data.Template.Cell[i].Y * sh); rect.Width = (int)(this.data.Template.Cell[i].W * sw); rect.Height = (int)(this.data.Template.Cell[i].H * sw); rio = new OpenCvSharp.Mat(grayMat, rect); this.CheckCell(mat, rio, this.data.Template.Cell[i], rect); } grayMat.Release(); } /**保存**/ public void Save(OpenCvSharp.Mat mat, OpenCvSharp.Mat wpMat) { if(this.data.InfoPath != null) { OpenCvSharp.Cv2.ImWrite(this.data.InfoPath + "//0.jpg", mat); OpenCvSharp.Cv2.ImWrite(this.data.InfoPath + "//1.jpg", wpMat); } } protected void Show(OpenCvSharp.Mat mat) { OpenCvSharp.Size size = new OpenCvSharp.Size(mat.Size().Width * 0.5f, mat.Size().Height * 0.5f); OpenCvSharp.Mat displayMat = new OpenCvSharp.Mat(size, mat.Type()); OpenCvSharp.Cv2.Resize(mat, displayMat, size); OpenCvSharp.Cv2.ImShow("1", displayMat); OpenCvSharp.Cv2.WaitKey(); displayMat.Release(); } } }