title: Android Paper Detection using OpenCV
body: <p>I am trying to implement Paper detection through OpenCV. I am able to understand the concept of how can I get it,</p>
  
  <p><em>Input-> Canny-> Blur-> Find Conture-> Search (closed)Quadrilateral-> Draw Conture</em></p>
  
  <p>but still, I am new to OpenCV programming. So having issues in implementing it. I was able to find help through this answer</p>
  
  <p><a href="https://stackoverflow.com/questions/31310315/android-opencv-paper-sheet-detection">Android OpenCV Paper Sheet detection
  </a></p>
  
  <p>but it's drawing contour on every possible lining. Here is the code I am trying to implement.</p>
  
  <pre><code>public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
  
      mRgba = inputFrame.rgba(); 
      Imgproc.drawContours(mRgba,findContours(mRgba), 0, new Scalar(0 , 255, 0), 5);
      return mRgba; 
  }
  
  public static class Quadrilateral {
      public MatOfPoint contour;
      public Point[] points;
  
      public Quadrilateral(MatOfPoint contour, Point[] points) {
          this.contour = contour;
          this.points = points;
      }
  }
  
  public static Quadrilateral findDocument( Mat inputRgba ) {
      ArrayList&lt;MatOfPoint&gt; contours = findContours(inputRgba);
      Quadrilateral quad = getQuadrilateral(contours);
      return quad;
  }
  
  private static ArrayList&lt;MatOfPoint&gt; findContours(Mat src) {
  
      double ratio = src.size().height / 500;
      int height = Double.valueOf(src.size().height / ratio).intValue();
      int width = Double.valueOf(src.size().width / ratio).intValue();
      Size size = new Size(width,height);
  
      Mat resizedImage = new Mat(size, CvType.CV_8UC4);
      Mat grayImage = new Mat(size, CvType.CV_8UC4);
      Mat cannedImage = new Mat(size, CvType.CV_8UC1);
  
      Imgproc.resize(src,resizedImage,size);
      Imgproc.cvtColor(resizedImage, grayImage, Imgproc.COLOR_RGBA2GRAY, 4);
      Imgproc.GaussianBlur(grayImage, grayImage, new Size(5, 5), 0);
      Imgproc.Canny(grayImage, cannedImage, 75, 200);
  
      ArrayList&lt;MatOfPoint&gt; contours = new ArrayList&lt;MatOfPoint&gt;();
      Mat hierarchy = new Mat();
  
      Imgproc.findContours(cannedImage, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
  
      hierarchy.release();
  
      Collections.sort(contours, new Comparator&lt;MatOfPoint&gt;() {
  
          @Override
          public int compare(MatOfPoint lhs, MatOfPoint rhs) {
              return Double.valueOf(Imgproc.contourArea(rhs)).compareTo(Imgproc.contourArea(lhs));
          }
      });
  
      resizedImage.release();
      grayImage.release();
      cannedImage.release();
  
      return contours;
  }
  
  private static Quadrilateral getQuadrilateral(ArrayList&lt;MatOfPoint&gt; contours) {
  
      for ( MatOfPoint c: contours ) {
          MatOfPoint2f c2f = new MatOfPoint2f(c.toArray());
          double peri = Imgproc.arcLength(c2f, true);
          MatOfPoint2f approx = new MatOfPoint2f();
          Imgproc.approxPolyDP(c2f, approx, 0.02 * peri, true);
  
          Point[] points = approx.toArray();
  
          // select biggest 4 angles polygon
          if (points.length == 4) {
              Point[] foundPoints = sortPoints(points);
  
              return new Quadrilateral(c, foundPoints);
          }
      }
  
      return null;
  }
  
  private static Point[] sortPoints(Point[] src) {
  
      ArrayList&lt;Point&gt; srcPoints = new ArrayList&lt;&gt;(Arrays.asList(src));
  
      Point[] result = { null , null , null , null };
  
      Comparator&lt;Point&gt; sumComparator = new Comparator&lt;Point&gt;() {
          @Override
          public int compare(Point lhs, Point rhs) {
              return Double.valueOf(lhs.y + lhs.x).compareTo(rhs.y + rhs.x);
          }
      };
  
      Comparator&lt;Point&gt; diffComparator = new Comparator&lt;Point&gt;() {
  
          @Override
          public int compare(Point lhs, Point rhs) {
              return Double.valueOf(lhs.y - lhs.x).compareTo(rhs.y - rhs.x);
          }
      };
  
      // top-left corner = minimal sum
      result[0] = Collections.min(srcPoints, sumComparator);
  
      // bottom-right corner = maximal sum
      result[2] = Collections.max(srcPoints, sumComparator);
  
      // top-right corner = minimal diference
      result[1] = Collections.min(srcPoints, diffComparator);
  
      // bottom-left corner = maximal diference
      result[3] = Collections.max(srcPoints, diffComparator);
  
      return result;
  }
  </code></pre>
  
  <p>The answer suggests that I should use Quadrilateral Object and call it with Imgproc.drawContours(), but this function takes in ArrayList as argument where as Quadrilateral object contains MatofPoint and Point[]. Can someone help me through this..I am using OpenCV(3.3) and Android (1.5.1)?</p>
  
  <p>Here is the sample what it should look like 
  <a href="https://i.stack.imgur.com/hhGvR.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/hhGvR.jpg" alt="Expected Output"></a></p>