【问题标题】:My contours smaller than a certain value are Not being removed from list of contours, despite of correct logic. Why?尽管逻辑正确,但我的小于某个值的轮廓并未从轮廓列表中删除。为什么?
【发布时间】:2016-04-21 05:21:01
【问题描述】:

我从这张图片开始:

然后我应用 Canny 边缘检测器,例如:

Mat originalMatGreyScale = new Mat();
Imgproc.cvtColor(originalPhotoMat, originalMatGreyScale, Imgproc.COLOR_BGR2GRAY);
Mat edgesMat = new Mat();
Imgproc.Canny(originalMatGreyScale, edgesMat , 50, 70);

我明白了:

然后我通过Imgproc.findContours()找到了轮廓列表(contours)。然后我做了一些编码以(1)找到最大轮廓的区域(maximumContourArea)(2)从contours中删除任何轮廓其面积小于maximumContourArea。问题底部给出的代码。

我打电话给Imgproc.drawContours(),通过

在原始图像上绘制绿色(剩余)轮廓
for (int contourIndex = 0; contourIndex < contours.size(); contourIndex++) {
    Imgproc.drawContours(originalPhotoMat, contours, contourIndex, new Scalar(0, 255, 0));
}

我所期待的是所有这些小污迹和噪点的轮廓都应该从轮廓列表contours 中删除,但我仍然得到了这个垫子(在这些小污迹周围也绘制了绿色轮廓):

此外,以下代码中的 Log.i() 消息会打印:

初始轮廓数:27

处理后的轮廓数:27

List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(edgesMap, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);


Log.i(TAG, "Number of contours initially: " + contours.size());//check

double maximumContourArea = 0;

Iterator<MatOfPoint> contoursIterator = contours.iterator();

while(contoursIterator.hasNext()) {
    MatOfPoint nextContour = contoursIterator.next();
    double nextContourArea = Imgproc.contourArea(nextContour);

    if (nextContourArea > maximumContourArea) {
        maximumContourArea = nextContourArea;
    }
}

while(contoursIterator.hasNext()) {
    MatOfPoint nextContour = contoursIterator.next();
    if (Imgproc.contourArea(nextContour) < maximumContourArea*(10 / 100)) {
        contours.remove(contours.indexOf(nextContour));
    }
}

Log.i(TAG, "Number of contours after processing: " + contours.size());//check



编辑:

  1. 我用0.1 替换了(10/100),实际上为了清楚起见,我决定在这个例子中使用0.5。这样,所有小于最大轮廓面积一半的轮廓都应该被删除。

  2. 因此,经过几处Log.i 语句后,我意识到第二个while 循环没有被执行。经过一番摆弄Iterator,然后降级到foreach循环,我得到ConcurrentModificationException,所以我终于发现解决方案是for循环,如下。

问题: (a) 我仍然得到相同的Mats,而如果您查看以下代码 sn-p 以及 maximumContourAreacurrentContourAreas 的值从本页底部的 logcat 输出中,您会注意到只有一个轮廓,其面积为 1719.0 应保留,所有其他轮廓均应删除。 (b) 查看以下代码后的Logcat输出。

代码已更改:

Log.i(TAG, "PNM Number of contours initially: " + contours.size());//check

double maximumContourArea = 0;

for (int currentContour=0; currentContour<contours.size(); currentContour++) {
    double currentContourArea = Imgproc.contourArea(contours.get(currentContour));
    if (maximumContourArea < currentContourArea) {
        maximumContourArea = currentContourArea;
    }
}

Log.i(TAG, "PNM maximumContourArea: " + maximumContourArea);//check
Log.i(TAG, "PNM maximumContourArea*.5: " + maximumContourArea*0.5);//check

for (int currentContour=0; currentContour<contours.size(); currentContour++) {
    double currentContourArea = Imgproc.contourArea(contours.get(currentContour));
    Log.i(TAG, "PNM currentContourArea: " + currentContourArea);//check
    if (currentContourArea < maximumContourArea*0.5) {
        contours.remove(currentContour);
    }
}
Log.i(TAG, "PNM Number of contours after processing: " + contours.size());//check

Logcat 输出:

04-21 12:09:59.955: I/MainActivity(9983): PNM Number of contours initially: 27
04-21 12:09:59.957: I/MainActivity(9983): PNM maximumContourArea: 1992.0
04-21 12:09:59.957: I/MainActivity(9983): PNM maximumContourArea*.5: 996.0
04-21 12:09:59.958: I/MainActivity(9983): PNM currentContourArea: 0.0
04-21 12:09:59.958: I/MainActivity(9983): PNM currentContourArea: 0.0
04-21 12:09:59.959: I/MainActivity(9983): PNM currentContourArea: 34.0
04-21 12:09:59.959: I/MainActivity(9983): PNM currentContourArea: 40.0
04-21 12:09:59.959: I/MainActivity(9983): PNM currentContourArea: 2.5
04-21 12:09:59.959: I/MainActivity(9983): PNM currentContourArea: 0.0
04-21 12:09:59.959: I/MainActivity(9983): PNM currentContourArea: 0.0
04-21 12:09:59.960: I/MainActivity(9983): PNM currentContourArea: 0.0
04-21 12:09:59.961: I/MainActivity(9983): PNM currentContourArea: 0.5
04-21 12:09:59.961: I/MainActivity(9983): PNM currentContourArea: 1719.0
04-21 12:09:59.962: I/MainActivity(9983): PNM currentContourArea: 35.5
04-21 12:09:59.962: I/MainActivity(9983): PNM currentContourArea: 105.0
04-21 12:09:59.962: I/MainActivity(9983): PNM currentContourArea: 29.5
04-21 12:09:59.962: I/MainActivity(9983): PNM currentContourArea: 47.0
04-21 12:09:59.962: I/MainActivity(9983): PNM Number of contours after processing: 14

好的,我将contours.remove(currentContour); 替换为Log.i(TAG, "PNM A contour with an area of " + Imgproc.contourArea(contours.remove(currentContour)) + " is being removed.");,因为ArrayListremove() 方法返回被删除的东西(轮廓)。 (source)

我还在此声明后添加了currentContour--;

以下是 Logcat 消息:

04-21 14:15:19.824: I/MainActivity(11125): PNM Number of contours: 27
04-21 14:15:19.824: I/MainActivity(11125): PNM maximumContourArea: 1992.0
04-21 14:15:19.824: I/MainActivity(11125): PNM maximumContourArea*.5: 996.0
04-21 14:15:19.824: I/MainActivity(11125): PNM currentContourArea: 0.0
04-21 14:15:19.824: I/MainActivity(11125): PNM A contour with an area of 0.0 is being removed.
04-21 14:15:19.825: I/MainActivity(11125): PNM currentContourArea: 18.0
04-21 14:15:19.825: I/MainActivity(11125): PNM A contour with an area of 18.0 is being removed.
04-21 14:15:19.825: I/MainActivity(11125): PNM currentContourArea: 0.0
04-21 14:15:19.825: I/MainActivity(11125): PNM A contour with an area of 0.0 is being removed.
04-21 14:15:19.825: I/MainActivity(11125): PNM currentContourArea: 0.0
04-21 14:15:19.825: I/MainActivity(11125): PNM A contour with an area of 0.0 is being removed.
04-21 14:15:19.825: I/MainActivity(11125): PNM currentContourArea: 34.0
04-21 14:15:19.825: I/MainActivity(11125): PNM A contour with an area of 34.0 is being removed.
04-21 14:15:19.825: I/MainActivity(11125): PNM currentContourArea: 0.0
04-21 14:15:19.825: I/MainActivity(11125): PNM A contour with an area of 0.0 is being removed.
04-21 14:15:19.825: I/MainActivity(11125): PNM currentContourArea: 40.0
04-21 14:15:19.825: I/MainActivity(11125): PNM A contour with an area of 40.0 is being removed.
04-21 14:15:19.825: I/MainActivity(11125): PNM currentContourArea: 0.0
04-21 14:15:19.825: I/MainActivity(11125): PNM A contour with an area of 0.0 is being removed.
04-21 14:15:19.825: I/MainActivity(11125): PNM currentContourArea: 2.5
04-21 14:15:19.825: I/MainActivity(11125): PNM A contour with an area of 2.5 is being removed.
04-21 14:15:19.826: I/MainActivity(11125): PNM currentContourArea: 4.0
04-21 14:15:19.826: I/MainActivity(11125): PNM A contour with an area of 4.0 is being removed.
04-21 14:15:19.826: I/MainActivity(11125): PNM currentContourArea: 0.0
04-21 14:15:19.826: I/MainActivity(11125): PNM A contour with an area of 0.0 is being removed.
04-21 14:15:19.826: I/MainActivity(11125): PNM currentContourArea: 0.5
04-21 14:15:19.826: I/MainActivity(11125): PNM A contour with an area of 0.5 is being removed.
04-21 14:15:19.826: I/MainActivity(11125): PNM currentContourArea: 0.0
04-21 14:15:19.826: I/MainActivity(11125): PNM A contour with an area of 0.0 is being removed.
04-21 14:15:19.826: I/MainActivity(11125): PNM currentContourArea: 32.5
04-21 14:15:19.826: I/MainActivity(11125): PNM A contour with an area of 32.5 is being removed.
04-21 14:15:19.826: I/MainActivity(11125): PNM currentContourArea: 0.0
04-21 14:15:19.826: I/MainActivity(11125): PNM A contour with an area of 0.0 is being removed.
04-21 14:15:19.826: I/MainActivity(11125): PNM currentContourArea: 0.0
04-21 14:15:19.826: I/MainActivity(11125): PNM A contour with an area of 0.0 is being removed.
04-21 14:15:19.826: I/MainActivity(11125): PNM currentContourArea: 0.5
04-21 14:15:19.826: I/MainActivity(11125): PNM A contour with an area of 0.5 is being removed.
04-21 14:15:19.826: I/MainActivity(11125): PNM currentContourArea: 11.5
04-21 14:15:19.826: I/MainActivity(11125): PNM A contour with an area of 11.5 is being removed.
04-21 14:15:19.826: I/MainActivity(11125): PNM currentContourArea: 1719.0
04-21 14:15:19.826: I/MainActivity(11125): PNM currentContourArea: 35.5
04-21 14:15:19.826: I/MainActivity(11125): PNM A contour with an area of 35.5 is being removed.
04-21 14:15:19.827: I/MainActivity(11125): PNM currentContourArea: 59.0
04-21 14:15:19.827: I/MainActivity(11125): PNM A contour with an area of 59.0 is being removed.
04-21 14:15:19.827: I/MainActivity(11125): PNM currentContourArea: 105.0
04-21 14:15:19.827: I/MainActivity(11125): PNM A contour with an area of 105.0 is being removed.
04-21 14:15:19.827: I/MainActivity(11125): PNM currentContourArea: 1992.0
04-21 14:15:19.827: I/MainActivity(11125): PNM currentContourArea: 29.5
04-21 14:15:19.827: I/MainActivity(11125): PNM A contour with an area of 29.5 is being removed.
04-21 14:15:19.827: I/MainActivity(11125): PNM currentContourArea: 259.5
04-21 14:15:19.827: I/MainActivity(11125): PNM A contour with an area of 259.5 is being removed.
04-21 14:15:19.827: I/MainActivity(11125): PNM currentContourArea: 47.0
04-21 14:15:19.827: I/MainActivity(11125): PNM A contour with an area of 47.0 is being removed.
04-21 14:15:19.827: I/MainActivity(11125): PNM currentContourArea: 38.0
04-21 14:15:19.827: I/MainActivity(11125): PNM A contour with an area of 38.0 is being removed.
04-21 14:15:19.827: I/MainActivity(11125): PNM Number of contours after processing: 2

^ 似乎正在工作。 现在唯一存在的问题是,当执行最后一个 drawContours() 以在原始图像上绘制绿色轮廓时,为什么要绘制所有轮廓(甚至是那些围绕着那些小污迹的轮廓)。强>

【问题讨论】:

  • 10 / 100 等于零吗?我不确定 Java 是如何处理这个问题的,所以请改用maximumContourArea*0.1。请尝试不同的阈值,例如maximumContourArea*0.9
  • 其实@Micka 说的是对的,10/100 会产生 0。要么直接使用 0.1,要么使用 10.0 / 100.0。
  • 没有足够的时间来完全阅读您的代码,但我记得当我这样做时,我使用顺序扩张和侵蚀过滤器来填补精明/轮廓结果中的空白......你丢失了“信息” ,但要聪明地这样做,所以它是一个很好的网络。
  • 你能在contours.remove(currentContour);之前记录一些消息吗?你确定.remove 可以按照你想要的方式工作吗?也许你必须在那里插入一个索引位置而不是元素? (抱歉,对 Java 结构一无所知)
  • @Solace 没错,但既然你没有删除那个,你应该有机器人。 @Micka currentContour 是索引而不是轮廓本身

标签: opencv image-processing opencv3.0 opencv4android opencv-contour


【解决方案1】:

循环中的逻辑有缺陷...

假设您有一个包含 10 个元素的数组,并且您发现您的第二个元素将被删除,此时您的 currentContour 变量为 1,并且您删除了该元素。然后您将有 9 个元素,您的迭代结束,您将在 2 中拥有 currentContour 变量。到目前为止,当您删除索引为 1 的元素时,索引为 2 的元素的索引更改为 1 . 所以,这个元素永远不会被检查,因为你的 currentContour 变量已经在 2 中了。

解决此问题的一种方法是创建一个新数组并添加您想要的轮廓...或者在删除一个元素后将索引更改为以前的数字currentContour--;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-25
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    相关资源
    最近更新 更多