尽管逻辑正确,但我的轮廓小于某个值并未从轮廓列表中删除。为什么呢?

时间:2016-04-21 05:21:02

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

我从这张图片开始:

enter image description here

然后我应用了Canny Edge Detector,如:

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

我得到了:

enter image description here

然后我找到contours的轮廓列表(Imgproc.findContours())。然后我做了一些编码,以便(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中移除,但我仍然得到这个垫子(在那些小污迹周围绘制绿色轮廓)同样):

enter image description here

此外,以下代码中的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. 我将(10/100)替换为0.1,实际上为了清楚起见,我决定在这个例子中使用0.5。这样,应移除小于最大轮廓面积一半的所有轮廓。

  2. 所以在这里和那里发表了几个Log.i语句之后,我意识到第二个while循环没有被执行。在使用Iterator进行一些调整然后逐步调整到foreach循环后,我得到ConcurrentModificationException,因此我终于发现解决方案是for循环,如下所示。

  3. 问题:(a)我仍然得到相同的Mat s,而如果您查看以下代码段和maximumContourArea的值以及{currentContourArea的值1}}来自本页底部的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.");,因为ArrayList的{​​{1}}方法会返回要删除的内容(轮廓)。 (source

    在此声明之后我还添加了remove()

    以下是Logcat消息:

    currentContour--;

    ^似乎正在运作。 现在仍然存在的唯一问题是,当执行最后一次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 以在原始图像上绘制绿色轮廓时,为什么我会绘制所有绘制的轮廓(甚至是那些肮脏的污迹)。

1 个答案:

答案 0 :(得分:2)

循环中的逻辑存在缺陷......

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

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