2016-12-26 113 views
0

我在Android应用程序中使用OpenCV。我想让移动应用程序在矩形(例如收据形状的东西)在视图中时自动拍照。我正在使用Canny边缘检测,但是当我查找轮廓时,数组大小大于1500.显然,循环遍历所有轮廓并找到最大轮廓并不是最佳选择,所以我想知道是否可以筛选出最大通过api自动轮廓?OpenCV Java极限轮廓

我迄今为止代码:

ArrayList contours; 

    @Override 
    public Mat onCameraFrame(final CameraBridgeViewBase.CvCameraViewFrame inputFrame) { 

    // Clear contours array on each frame 
    contours.clear(); 

    // Get Grayscale image 
    final Mat gray = inputFrame.gray(); 

    // Canny edge detection 
    Imgproc.Canny(gray, gray, 300, 1000, 5, true); 

    // New empty black matrix to store the edges captured 
    Mat dest = new Mat(); 
    Core.add(dest, Scalar.all(0), dest); 

    // Copy the edge data over to the empty black matrix 
    gray.copyTo(dest); 

    // Is there a way to filter the size of contours so that not everything is returned? Right now this function is returning a lot of contours (1500 +) 
    Imgproc.findContours(gray, contours, hirearchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); 

    return dest; 
} 

编辑 用户会拿着电话,我希望应用程序自动拍摄照片时的收据是在视图中。 Example receipt

+0

可能是因为如果你提供了一些输入图像,那么可以建议一些比Canny更好的技术,因为canny用于检测边缘,使用canny结果检测物体不是一个明智的想法,可能会丢失噪声即使在调整参数之后,所以我建议你去使用颜色分割,就像事先知道接受者将要使用的颜色一样,并调整颜色限制的阈值一点以抵消输入图像中的亮度变化 – ZdaR

+0

收据图像将是黑色和白色。我想要一种让相机从背景中检测收据并自动拍摄照片的方法。 –

+0

如果这个人拿着虚假的空白纸,或者在背景中有一些其他白色物体会怎么样? – ZdaR

回答

0

我已经介绍了您可能会使用的基本技术,在下面的Python代码中,在您选择的语言(在这种情况下为java)中翻译代码并不困难。因此,该技术涉及:

  • 估计要细分对象的颜色,这是你的情况白色,那么在安全范围上限和下限可近似为:

    RECEIPT_LOWER_BOUND = np.array([200, 200, 200]) 
    RECEIPT_UPPER_BOUND = np.array([255, 255, 255]) 
    
  • 应用一些模糊输入图像使颜色分布平滑,这将减少未来较小的轮廓。

    img_blurred = cv2.blur(img, (5, 5)) 
    
  • 应用扩张到二进制图像去除相邻的小轮廓包围你的目标最大的轮廓

    kernel = np.ones((10, 10), dtype=np.uint8) 
    mask = cv2.dilate(mask, kernel) 
    
  • 现在发现在面具的轮廓将上述操作后并过滤掉轮廓contourArea的基础。

    im, contours, hierarchy = cv2.findContours(receipt_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) 
    largest_contour = max(contours, key=lambda x: cv2.contourArea(x)) 
    
  • 最后,您可以在该区域应用一些阈值以验证输入是否真的是票证。

代码:

import cv2 
import numpy as np 


# You may change the following ranges to define your own lower and upper BGR bounds. 
RECEIPT_LOWER_BOUND = np.array([200, 200, 200]) 
RECEIPT_UPPER_BOUND = np.array([255, 255, 255]) 


def segment_receipt(img): 
    # Blur the input image to reduce the noise which in-turn reduces the number of contours 
    img_blurred = cv2.blur(img, (5, 5)) 
    mask = cv2.inRange(img_blurred, RECEIPT_LOWER_BOUND, RECEIPT_UPPER_BOUND) 

    # Also dilate the binary mask which further reduces the salt and pepper noise 
    kernel = np.ones((10, 10), dtype=np.uint8) 
    mask = cv2.dilate(mask, kernel) 
    return mask 


def get_largest_contour_rect(image): 
    receipt_mask = segment_receipt(image) 
    im, contours, hierarchy = cv2.findContours(receipt_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) 
    print "Number of contours found :", len(contours) 

    # Sorting the contours to get the largest one 
    largest_contour = max(contours, key=lambda x: cv2.contourArea(x)) 

    # Return the last contour in sorted list as the list is sorted in increasing order. 
    return cv2.boundingRect(largest_contour) 

image = cv2.imread("path/to/your/image.jpg") 
rect = get_largest_contour_rect(image) 

输出:

enter image description here

0

@ J.Doe我目前的工作在这样一个项目,我已经成功地能经过大量处理后,隔离图像中最大的轮廓。剩下的唯一部分是识别矩形轮廓并拍摄照片。

mRgba = inputFrame.rgba(); 
    Imgproc.Canny(mRgba,mCanny,50,200); 
    Imgproc.cvtColor(mRgba, mGray, Imgproc.COLOR_RGB2GRAY); 

    Imgproc.GaussianBlur(mGray, mGray1, new Size(3, 3), 1); 
    Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,new Size(9,9)); 

    Imgproc.dilate(mGray1, mGray2, kernel); 
    Imgproc.Canny(mGray2, mCanny, 50, 200); 

    Imgproc.findContours(mCanny,contours,hierarchy,Imgproc.RETR_TREE,Imgproc.CHAIN_APPROX_SIMPLE); 
    double maxVal = 0; 
    int maxValIdx = 0; 
    for(int contourIdx = 0; contourIdx < contours.size(); contourIdx++){ 
     double contourArea = Imgproc.contourArea(contours.get(contourIdx)); 
     if(maxVal < contourArea) 
     { 
      maxVal = contourArea; 
      maxValIdx = contourIdx; 
     } 
    } 
    Imgproc.drawContours(mRgba,contours,maxValIdx,new Scalar(0,255,255),-1); 
    return mRgba; 

小心图像名称我改变了他们在不同的过程。