Advertisement
Guest User

FormDetection

a guest
Feb 25th, 2020
267
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 9.21 KB | None | 0 0
  1. using OpenCVForUnity.ArucoModule;
  2. using OpenCVForUnity.CoreModule;
  3. using OpenCVForUnity.ImgprocModule;
  4. using System;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using UnityEngine;
  8. using UnityEngine.Assertions;
  9.  
  10. namespace TouchVR.CV
  11. {
  12.     public class FormDetection
  13.     {
  14.         /// <summary>
  15.         /// convert a given image to gray scale
  16.         /// </summary>
  17.         /// <param name="src"></param>
  18.         /// <returns></returns>
  19.         private static Mat ToGray(Mat src)
  20.         {
  21.             Assert.IsTrue(src.type() == CvType.CV_8UC1
  22.                 || src.type() == CvType.CV_8UC3
  23.                 || src.type() == CvType.CV_8UC4);
  24.  
  25.             Mat dst = new Mat();
  26.  
  27.             if (src.type() == CvType.CV_8UC4)
  28.             {
  29.                 Imgproc.cvtColor(src, dst, Imgproc.COLOR_RGBA2GRAY);
  30.             }
  31.             else if (src.type() == CvType.CV_8UC3)
  32.             {
  33.                 Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGR2GRAY);
  34.             }
  35.             else
  36.             {
  37.                 src.copyTo(dst);
  38.             }
  39.  
  40.             return dst;
  41.         }
  42.  
  43.         /// <summary>
  44.         /// applys adaptive threshold to a given image
  45.         /// </summary>
  46.         /// <param name="src"></param>
  47.         /// <param name="dst"></param>
  48.         /// <param name="winSize"></param>
  49.         /// <param name="constant"></param>
  50.         private static void ThresholdImage(Mat src, ref Mat dst, int winSize, double constant)
  51.         {
  52.             Assert.IsTrue(winSize >= 3);
  53.             if (winSize % 2 == 0) winSize++; // must be odd
  54.             Imgproc.adaptiveThreshold(src, dst, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, winSize, constant);
  55.         }
  56.  
  57.         /// <summary>
  58.         /// find contours in a given image. The edges are created either with Canny, Threshold or Adaptive threshold
  59.         /// </summary>
  60.         /// <param name="src"></param>
  61.         /// <param name="detectorParameters"></param>
  62.         /// <param name="useThreshold"></param>
  63.         /// <param name="useAdaptiveThreshold"></param>
  64.         /// <returns></returns>
  65.         protected static List<MatOfPoint> FindContours(Mat src, DetectorParameters detectorParameters, bool useThreshold = false, bool useAdaptiveThreshold = false)
  66.         {
  67.             Mat gray = ToGray(src);
  68.             // blur
  69.             Imgproc.GaussianBlur(gray, gray, new Size(7, 7), 0, 0, Core.BORDER_DEFAULT);
  70.             Mat edged = new Mat();
  71.             Mat hierarchy = new Mat();
  72.  
  73.             List<MatOfPoint> contours = new List<MatOfPoint>();
  74.  
  75.             if (useThreshold)
  76.             {
  77.                 if (useAdaptiveThreshold)
  78.                 {
  79.                     List<MatOfPoint> tempContours = new List<MatOfPoint>();
  80.  
  81.                     Assert.IsTrue(detectorParameters.get_adaptiveThreshWinSizeMin() >= 3 && detectorParameters.get_adaptiveThreshWinSizeMax() >= 3);
  82.                     Assert.IsTrue(detectorParameters.get_adaptiveThreshWinSizeMax() >= detectorParameters.get_adaptiveThreshWinSizeMin());
  83.                     Assert.IsTrue(detectorParameters.get_adaptiveThreshWinSizeStep() > 0);
  84.  
  85.                     // number of window sizes (scales) to apply adaptive thresholding
  86.                     int nScales = (detectorParameters.get_adaptiveThreshWinSizeMax() - detectorParameters.get_adaptiveThreshWinSizeMin()) /
  87.                                   detectorParameters.get_adaptiveThreshWinSizeStep() + 1;
  88.  
  89.                     for (int i = 0; i < nScales; ++i)
  90.                     {
  91.                         int currScale = detectorParameters.get_adaptiveThreshWinSizeMin() + i * detectorParameters.get_adaptiveThreshWinSizeStep();
  92.                         ThresholdImage(gray, ref edged, currScale, detectorParameters.get_adaptiveThreshConstant());
  93.                         Imgproc.findContours(edged, tempContours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
  94.                         contours.AddRange(tempContours);
  95.                     }
  96.                 }
  97.                 else
  98.                 {
  99.                     var thresh = Imgproc.threshold(gray, edged, 100, 255, Imgproc.THRESH_BINARY);
  100.                     Imgproc.findContours(edged, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
  101.                 }
  102.             }
  103.             else
  104.             {
  105.                 Imgproc.Canny(gray, edged, 10, 50, 3);
  106.                 Imgproc.findContours(edged, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
  107.             }
  108.  
  109.             // Free storage for used Mats
  110.             edged.Dispose();
  111.             hierarchy.Dispose();
  112.             gray.Dispose();
  113.  
  114.             return contours;
  115.         }
  116.     }
  117.  
  118.     public class RectangleDetection : FormDetection
  119.     {
  120.         /// <summary>
  121.         /// Finds all rectangular contours
  122.         /// Equivalent to c++ function _findMarkerContours
  123.         /// </summary>
  124.         /// <param name="src"></param>
  125.         /// <param name="detectorParameters"></param>
  126.         /// <param name="useThreshold"></param>
  127.         /// <param name="useAdaptiveThreshold"></param>
  128.         /// <returns></returns>
  129.         public static List<MatOfPoint> FindRectangularContours(Mat src, DetectorParameters detectorParameters, bool useThreshold = false, bool useAdaptiveThreshold = false)
  130.         {
  131.             var contourCandidates = FindContours(src, detectorParameters, useThreshold, useAdaptiveThreshold);
  132.  
  133.             var filteredContours = new List<MatOfPoint>();
  134.  
  135.             var cntArray = contourCandidates.ToArray();
  136.             var cnt2fArray = new MatOfPoint2f[cntArray.Length];
  137.  
  138.             for (int i = 0; i < contourCandidates.Count; ++i)
  139.             {
  140.                 if (cntArray[i].rows() < detectorParameters.get_minMarkerPerimeterRate()
  141.                     || contourCandidates[i].rows() < detectorParameters.get_maxMarkerPerimeterRate())
  142.                 {
  143.                     continue;
  144.                 }
  145.  
  146.                 cnt2fArray[i] = new MatOfPoint2f(cntArray[i].toArray());
  147.  
  148.                 // check if square and convex
  149.                 MatOfPoint2f approxCurve = new MatOfPoint2f();
  150.                 // TODO: if
  151.                 Imgproc.approxPolyDP(cnt2fArray[i], approxCurve, contourCandidates[i].rows() * detectorParameters.get_polygonalApproxAccuracyRate(), true);
  152.                 if (approxCurve.rows() != 4 || !Imgproc.isContourConvex(new MatOfPoint(approxCurve.toArray()))) continue;
  153.  
  154.                 var approxArray = approxCurve.toArray();
  155.  
  156.                 // filter small contours
  157.                 // sum of square length of all sides
  158.                 double outlineLenght = 0;
  159.                 for (int j = 0; j < 4; j++)
  160.                 {
  161.                     // c^2 = a^2 + b^2
  162.                     outlineLenght += Math.Pow(approxArray[j].x - approxArray[(j + 1) % 4].x, 2) +
  163.                                         Math.Pow(approxArray[j].y - approxArray[(j + 1) % 4].y, 2);
  164.                 }
  165.  
  166.                 double minOutlineSqLength = 4 * Math.Pow(20, 2);
  167.                 if (outlineLenght < minOutlineSqLength) continue;
  168.  
  169.                 // check if it is too near to the image border
  170.                 var minDistanceToBorder = detectorParameters.get_minDistanceToBorder();
  171.                 bool tooNearBorder = false;
  172.                 for (int j = 0; j < 4; j++)
  173.                 {
  174.                     if (approxArray[j].x < minDistanceToBorder ||
  175.                         approxArray[j].y < minDistanceToBorder ||
  176.                         approxArray[j].x > src.cols() - 1 - minDistanceToBorder ||
  177.                         approxArray[j].y > src.rows() - 1 - minDistanceToBorder)
  178.                         tooNearBorder = true;
  179.                 }
  180.                 if (tooNearBorder) continue;
  181.  
  182.                 // passed all test -> add candidate
  183.                 var currentCandidatePoints = new List<Point>();
  184.                 for (int j = 0; j < 4; j++)
  185.                 {
  186.                     currentCandidatePoints.Add(approxArray[j]);
  187.                 }
  188.  
  189.                 filteredContours.Add(new MatOfPoint(currentCandidatePoints.ToArray()));
  190.             }
  191.  
  192.             ReorderCandidatesCorners(ref filteredContours);
  193.  
  194.             return filteredContours;
  195.         }
  196.  
  197.         /// <summary>
  198.         /// Equivalent to c++ function _reorderCandidatesCorners
  199.         /// </summary>
  200.         /// <param name="contourCandidates"></param>
  201.         private static void ReorderCandidatesCorners(ref List<MatOfPoint> contourCandidates)
  202.         {
  203.             var candidateArray = contourCandidates.ToArray();
  204.  
  205.             for (int i = 0; i < contourCandidates.Count; i++)
  206.             {
  207.                 var points = candidateArray[i].toArray();
  208.                 double dx1 = points[1].x - points[0].x;
  209.                 double dy1 = points[1].y - points[0].y;
  210.                 double dx2 = points[2].x - points[0].x;
  211.                 double dy2 = points[2].y - points[0].y;
  212.                 double crossProduct = (dx1 * dy2) - (dy1 * dx2);
  213.  
  214.                 if (crossProduct < 0.0)
  215.                 { // not clockwise direction
  216.                     var buf = points[1];
  217.                     points[1] = points[3];
  218.                     points[3] = buf;
  219.                 }
  220.             }
  221.         }
  222.     }
  223. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement