[英]OpenCV Java limit contours
我在Android應用程序中使用OpenCV。 我希望移動應用程序在查看矩形(例如收據形狀的東西)時自動拍照。 我正在使用Canny邊緣檢測,但是當我尋找輪廓時,數組大小大於1500。顯然,遍歷所有輪廓並找到最大的輪廓並不是最佳選擇,所以我想知道是否可以過濾出最大的輪廓通過api自動繪制輪廓?
到目前為止,我的代碼:
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;
}
編輯用戶將手持電話,並且我希望應用程序在收據查看時自動拍照。 收據示例
我已經介紹了您可能使用的基本技術,在下面的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)
輸出:
@ 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;
警惕圖像名稱,我在不同的過程中更改了它們。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.