Мои контуры меньше определенного значения не удаляются из списка контуров, несмотря на правильную логику. Почему?

Я начал с этого изображения:

введите здесь описание изображения

Затем я применил Canny Edge Detector, например:

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

Я получил:

введите здесь описание изображения

Затем я нашел список контуров (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, но вместо этого я все еще получил этот мат (с контурами зеленого цвета, нарисованными вокруг этих маленьких пятен):

введите здесь описание изображения

Кроме того, сообщения 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, как показано ниже.

ПРОБЛЕМА: (а) я по-прежнему получаю те же Mats, тогда как если вы посмотрите на следующий фрагмент кода и значения maximumContourArea и currentContourAreas из выходных данных 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.");, потому что метод remove() ArrayList возвращает удаляемую вещь (контур). (источник)

Я также добавил 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() для рисования контуров зеленого цвета на исходном изображении.


person Solace    schedule 21.04.2016    source источник
comment
10 / 100 равно нулю? Я не уверен, как Java справляется с этим, поэтому попробуйте вместо этого maximumContourArea*0.1. И, пожалуйста, попробуйте разные пороги, такие как maximumContourArea*0.9.   -  person Micka    schedule 21.04.2016
comment
На самом деле то, что говорит @Micka, верно, 10/100 даст 0. Либо используйте напрямую 0,1, либо используйте 10,0/100,0.   -  person api55    schedule 21.04.2016
comment
@api55 Да, он был прав. Я исправил это, но результат все еще сбивает с толку. Внес правку в вопрос.   -  person Solace    schedule 21.04.2016
comment
@Micka Да, плохо, 10/100 равно нулю. Я исправил это, но результат все еще не правильный. Я только что опубликовал редактирование в вопросе об этом.   -  person Solace    schedule 21.04.2016
comment
Недостаточно времени, чтобы полностью прочитать ваш код, но я помню, когда я делал это, я использовал последовательные фильтры расширения и эрозии, чтобы заполнить пробелы в результатах хитрости/контуров... Вы теряете «информацию», но делаете это разумно, так что это чистая хорошо.   -  person Lamar Latrell    schedule 21.04.2016
comment
Вы можете записать какое-нибудь сообщение до contours.remove(currentContour);? Вы уверены, что .remove работает так, как вам нужно? Может быть, вам нужно вставить позицию индекса вместо элемента? (извините, я понятия не имею о структурах Java)   -  person Micka    schedule 21.04.2016
comment
На самом деле должно остаться 2 контура: с районом 1992 и с районом 1719 :)   -  person api55    schedule 21.04.2016
comment
@api55 1992 — это maximumContourArea. @Micka Хорошо, просто сделаю это   -  person Solace    schedule 21.04.2016
comment
@Solace Точно, но поскольку вы не удаляете его, у вас должен быть бот. @Micka currentContour - это индекс, а не контур как таковой   -  person api55    schedule 21.04.2016
comment
@Мика Сделал это. См. редактирование.   -  person Solace    schedule 21.04.2016
comment
Можете ли вы снова вывести размер контура прямо перед рисованием контуров?   -  person Micka    schedule 21.04.2016
comment
Если contours.size() дал вам 2 (судя по логам), он не может рисовать больше вещей... Возможно, вы используете устаревший список (один без удаления вещей) или вы используете изображение, которое вы нарисовали на нем раньше.. , чтобы знать, является ли это одним из этих двух, вы должны сделать. 1) напечатать размер массива перед частью рисования и 2) показать изображение перед рисованием на нем. Если 1) дал вам число, отличное от двух, проблема заключается в массиве. Если 2) дает вам изображение с нарисованными контурами, то это использованное изображение, которое вы нарисовали на нем раньше.   -  person api55    schedule 21.04.2016
comment
вы можете попробовать нарисовать другим цветом, чтобы увидеть, работаете ли вы с изображением, на котором вы случайно нарисовали все контуры ранее (для тестирования или чего-то еще)   -  person Micka    schedule 21.04.2016
comment
@Micka @api55 Использование только что созданного Mat решило проблему =) Но просто для пояснения, даже слово originalPhotoMat не встречалось где-либо между Imgproc.cvtColor(originalPhotoMat, originalMatGreyScale, Imgproc.COLOR_BGR2GRAY); и Imgproc.drawContours(originalPhotoMat, contours, contourIndex, new Scalar(0, 255, 0)); (оба утверждения даны под вопросом) в моем коде.   -  person Solace    schedule 21.04.2016
comment
Большое спасибо вам обоим. Я никогда не хочу делать эти ошибки, но я все еще делаю их.   -  person Solace    schedule 21.04.2016


Ответы (1)


Логика в вашем цикле ошибочна...

скажем, у вас есть массив из 10 элементов, и вы узнали, что ваш второй элемент будет удален, в этот момент ваша переменная currentContour равна 1, и вы удаляете этот элемент. Тогда у вас будет 9 элементов, ваша итерация закончится, и у вас будет переменная currentContour в 2. В чем проблема до сих пор, когда вы удалили свой элемент с индексом 1, элемент с индексом 2 изменил свой индекс на 1. Итак , этот элемент никогда не будет проверен, потому что ваша переменная currentContour уже находится в 2.

Один из способов исправить это — создать новый массив и добавить контуры, которые вы хотите иметь... или после удаления элемента изменить индекс на предыдущий номер currentContour--;

person api55    schedule 21.04.2016