如何在 Android 中使用 OpenCV 去除轮廓的背景?
how to remove the background of a contour using OpenCV in Android?
扫描的示例令牌:https://ibin.co/3irqGlxXezL3.jpg
输入图像:https://ibin.co/3irmfXKjYocz.jpg
Output Image
如您所见,我已经应用了 .submat,但我不确定为什么它会掩盖轮廓的内部而不是外表面。此外,过滤最大轮廓也不一致。关于如何根据票证的尺寸使其更强大的任何想法,因为我的目标是扫描尺寸完全相同的票证。
作为一个新手 OpenCV 爱好者,我希望有人能指导我完成我在这里的最终任务,即从工单中的日历中获取年、月、日和时间,并以文本形式显示。
票上会有打孔作为标记。所以,我的想法是跟踪每个(孔)斑点并将其连同周围的数字一起提取,以了解它基于周围的数字,并对所有具有一定层次结构的斑点(孔)执行此操作知道提取是分别来自 'year' 字段还是月或日字段。或者还有其他更好的方法吗?
@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
Mat srcMat = inputFrame.rgba();
Mat processedMat = new Mat();
Imgproc.cvtColor(srcMat, processedMat, Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur(processedMat, processedMat, new Size(3, 3), 0);
Imgproc.threshold(processedMat, processedMat, 98, 255, Imgproc.THRESH_BINARY);
List<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(processedMat, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
Log.e(TAG, "ContourSize: " + contours.size());
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(srcMat, contours, maxValIdx, new Scalar(0, 255, 0), -2);
if (!contours.isEmpty()) {
Log.e("largestContour", "" + contours.get(maxValIdx));
Rect rect = Imgproc.boundingRect(contours.get(maxValIdx));
srcMat.submat(rect);
}
return srcMat;
}
嗯,
首先,您使用的是 drawContours 方法的重载版本。
负厚度表示将绘制填充轮廓。
因此,尝试将-2更改为正数以获得所需的轮廓。
现在让我试着说说我检测机票上这些日期的第一种方法是什么:
1) 使用透视变换将轮廓转换为垂直视图:
在 Python 中查看此 example。
2) 使用斑点检测找到你的斑点:
在 Python 和 C++ 中查看此 example。
如果您有明确定义的票证布局模型,它应该可以工作。
扫描的示例令牌:https://ibin.co/3irqGlxXezL3.jpg
输入图像:https://ibin.co/3irmfXKjYocz.jpg
Output Image
如您所见,我已经应用了 .submat,但我不确定为什么它会掩盖轮廓的内部而不是外表面。此外,过滤最大轮廓也不一致。关于如何根据票证的尺寸使其更强大的任何想法,因为我的目标是扫描尺寸完全相同的票证。
作为一个新手 OpenCV 爱好者,我希望有人能指导我完成我在这里的最终任务,即从工单中的日历中获取年、月、日和时间,并以文本形式显示。
票上会有打孔作为标记。所以,我的想法是跟踪每个(孔)斑点并将其连同周围的数字一起提取,以了解它基于周围的数字,并对所有具有一定层次结构的斑点(孔)执行此操作知道提取是分别来自 'year' 字段还是月或日字段。或者还有其他更好的方法吗?
@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
Mat srcMat = inputFrame.rgba();
Mat processedMat = new Mat();
Imgproc.cvtColor(srcMat, processedMat, Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur(processedMat, processedMat, new Size(3, 3), 0);
Imgproc.threshold(processedMat, processedMat, 98, 255, Imgproc.THRESH_BINARY);
List<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(processedMat, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
Log.e(TAG, "ContourSize: " + contours.size());
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(srcMat, contours, maxValIdx, new Scalar(0, 255, 0), -2);
if (!contours.isEmpty()) {
Log.e("largestContour", "" + contours.get(maxValIdx));
Rect rect = Imgproc.boundingRect(contours.get(maxValIdx));
srcMat.submat(rect);
}
return srcMat;
}
嗯,
首先,您使用的是 drawContours 方法的重载版本。 负厚度表示将绘制填充轮廓。
因此,尝试将-2更改为正数以获得所需的轮廓。
现在让我试着说说我检测机票上这些日期的第一种方法是什么:
1) 使用透视变换将轮廓转换为垂直视图:
在 Python 中查看此 example。
2) 使用斑点检测找到你的斑点:
在 Python 和 C++ 中查看此 example。
如果您有明确定义的票证布局模型,它应该可以工作。