Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using OpenCVForUnity.ArucoModule;
- using OpenCVForUnity.CoreModule;
- using OpenCVForUnity.ImgprocModule;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.Assertions;
- namespace TouchVR.CV
- {
- public class FormDetection
- {
- /// <summary>
- /// convert a given image to gray scale
- /// </summary>
- /// <param name="src"></param>
- /// <returns></returns>
- private static Mat ToGray(Mat src)
- {
- Assert.IsTrue(src.type() == CvType.CV_8UC1
- || src.type() == CvType.CV_8UC3
- || src.type() == CvType.CV_8UC4);
- Mat dst = new Mat();
- if (src.type() == CvType.CV_8UC4)
- {
- Imgproc.cvtColor(src, dst, Imgproc.COLOR_RGBA2GRAY);
- }
- else if (src.type() == CvType.CV_8UC3)
- {
- Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGR2GRAY);
- }
- else
- {
- src.copyTo(dst);
- }
- return dst;
- }
- /// <summary>
- /// applys adaptive threshold to a given image
- /// </summary>
- /// <param name="src"></param>
- /// <param name="dst"></param>
- /// <param name="winSize"></param>
- /// <param name="constant"></param>
- private static void ThresholdImage(Mat src, ref Mat dst, int winSize, double constant)
- {
- Assert.IsTrue(winSize >= 3);
- if (winSize % 2 == 0) winSize++; // must be odd
- Imgproc.adaptiveThreshold(src, dst, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, winSize, constant);
- }
- /// <summary>
- /// find contours in a given image. The edges are created either with Canny, Threshold or Adaptive threshold
- /// </summary>
- /// <param name="src"></param>
- /// <param name="detectorParameters"></param>
- /// <param name="useThreshold"></param>
- /// <param name="useAdaptiveThreshold"></param>
- /// <returns></returns>
- protected static List<MatOfPoint> FindContours(Mat src, DetectorParameters detectorParameters, bool useThreshold = false, bool useAdaptiveThreshold = false)
- {
- Mat gray = ToGray(src);
- // blur
- Imgproc.GaussianBlur(gray, gray, new Size(7, 7), 0, 0, Core.BORDER_DEFAULT);
- Mat edged = new Mat();
- Mat hierarchy = new Mat();
- List<MatOfPoint> contours = new List<MatOfPoint>();
- if (useThreshold)
- {
- if (useAdaptiveThreshold)
- {
- List<MatOfPoint> tempContours = new List<MatOfPoint>();
- Assert.IsTrue(detectorParameters.get_adaptiveThreshWinSizeMin() >= 3 && detectorParameters.get_adaptiveThreshWinSizeMax() >= 3);
- Assert.IsTrue(detectorParameters.get_adaptiveThreshWinSizeMax() >= detectorParameters.get_adaptiveThreshWinSizeMin());
- Assert.IsTrue(detectorParameters.get_adaptiveThreshWinSizeStep() > 0);
- // number of window sizes (scales) to apply adaptive thresholding
- int nScales = (detectorParameters.get_adaptiveThreshWinSizeMax() - detectorParameters.get_adaptiveThreshWinSizeMin()) /
- detectorParameters.get_adaptiveThreshWinSizeStep() + 1;
- for (int i = 0; i < nScales; ++i)
- {
- int currScale = detectorParameters.get_adaptiveThreshWinSizeMin() + i * detectorParameters.get_adaptiveThreshWinSizeStep();
- ThresholdImage(gray, ref edged, currScale, detectorParameters.get_adaptiveThreshConstant());
- Imgproc.findContours(edged, tempContours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
- contours.AddRange(tempContours);
- }
- }
- else
- {
- var thresh = Imgproc.threshold(gray, edged, 100, 255, Imgproc.THRESH_BINARY);
- Imgproc.findContours(edged, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
- }
- }
- else
- {
- Imgproc.Canny(gray, edged, 10, 50, 3);
- Imgproc.findContours(edged, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
- }
- // Free storage for used Mats
- edged.Dispose();
- hierarchy.Dispose();
- gray.Dispose();
- return contours;
- }
- }
- public class RectangleDetection : FormDetection
- {
- /// <summary>
- /// Finds all rectangular contours
- /// Equivalent to c++ function _findMarkerContours
- /// </summary>
- /// <param name="src"></param>
- /// <param name="detectorParameters"></param>
- /// <param name="useThreshold"></param>
- /// <param name="useAdaptiveThreshold"></param>
- /// <returns></returns>
- public static List<MatOfPoint> FindRectangularContours(Mat src, DetectorParameters detectorParameters, bool useThreshold = false, bool useAdaptiveThreshold = false)
- {
- var contourCandidates = FindContours(src, detectorParameters, useThreshold, useAdaptiveThreshold);
- var filteredContours = new List<MatOfPoint>();
- var cntArray = contourCandidates.ToArray();
- var cnt2fArray = new MatOfPoint2f[cntArray.Length];
- for (int i = 0; i < contourCandidates.Count; ++i)
- {
- if (cntArray[i].rows() < detectorParameters.get_minMarkerPerimeterRate()
- || contourCandidates[i].rows() < detectorParameters.get_maxMarkerPerimeterRate())
- {
- continue;
- }
- cnt2fArray[i] = new MatOfPoint2f(cntArray[i].toArray());
- // check if square and convex
- MatOfPoint2f approxCurve = new MatOfPoint2f();
- // TODO: if
- Imgproc.approxPolyDP(cnt2fArray[i], approxCurve, contourCandidates[i].rows() * detectorParameters.get_polygonalApproxAccuracyRate(), true);
- if (approxCurve.rows() != 4 || !Imgproc.isContourConvex(new MatOfPoint(approxCurve.toArray()))) continue;
- var approxArray = approxCurve.toArray();
- // filter small contours
- // sum of square length of all sides
- double outlineLenght = 0;
- for (int j = 0; j < 4; j++)
- {
- // c^2 = a^2 + b^2
- outlineLenght += Math.Pow(approxArray[j].x - approxArray[(j + 1) % 4].x, 2) +
- Math.Pow(approxArray[j].y - approxArray[(j + 1) % 4].y, 2);
- }
- double minOutlineSqLength = 4 * Math.Pow(20, 2);
- if (outlineLenght < minOutlineSqLength) continue;
- // check if it is too near to the image border
- var minDistanceToBorder = detectorParameters.get_minDistanceToBorder();
- bool tooNearBorder = false;
- for (int j = 0; j < 4; j++)
- {
- if (approxArray[j].x < minDistanceToBorder ||
- approxArray[j].y < minDistanceToBorder ||
- approxArray[j].x > src.cols() - 1 - minDistanceToBorder ||
- approxArray[j].y > src.rows() - 1 - minDistanceToBorder)
- tooNearBorder = true;
- }
- if (tooNearBorder) continue;
- // passed all test -> add candidate
- var currentCandidatePoints = new List<Point>();
- for (int j = 0; j < 4; j++)
- {
- currentCandidatePoints.Add(approxArray[j]);
- }
- filteredContours.Add(new MatOfPoint(currentCandidatePoints.ToArray()));
- }
- ReorderCandidatesCorners(ref filteredContours);
- return filteredContours;
- }
- /// <summary>
- /// Equivalent to c++ function _reorderCandidatesCorners
- /// </summary>
- /// <param name="contourCandidates"></param>
- private static void ReorderCandidatesCorners(ref List<MatOfPoint> contourCandidates)
- {
- var candidateArray = contourCandidates.ToArray();
- for (int i = 0; i < contourCandidates.Count; i++)
- {
- var points = candidateArray[i].toArray();
- double dx1 = points[1].x - points[0].x;
- double dy1 = points[1].y - points[0].y;
- double dx2 = points[2].x - points[0].x;
- double dy2 = points[2].y - points[0].y;
- double crossProduct = (dx1 * dy2) - (dy1 * dx2);
- if (crossProduct < 0.0)
- { // not clockwise direction
- var buf = points[1];
- points[1] = points[3];
- points[3] = buf;
- }
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement