|
@@ -0,0 +1,330 @@
|
|
|
+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>();
|
|
|
+ subject = new Subject();
|
|
|
+ subject.I = cell.Col;
|
|
|
+ subject.Answer = new List<char>();
|
|
|
+ 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<char>();
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|