OPENCV Java | Remover manchas de área en una imagen binaria

user4429422:

Tengo una imagen en blanco y negro (un solo canal, de 0 y sólo 255 de) y me gustaría para eliminar pequeñas manchas en los mismos que están por debajo de un cierto umbral área usando OpenCV 3.4.2 en Java.

Ahora ya me encontré con el siguiente hilo: Eliminación de manchas de una imagen binaria , que es más o menos la misma - pero necesito ayuda para traducir la respuesta en código Java. También, ya que me gustaría para eliminar puntos negros, que invertir la imagen antes y después del procesamiento. EDIT: gracias a algunas sugerencias tipo que lograron obtener un código de trabajo y modificar lo que ahora se trata de una MCVE.

Mi intento hasta el momento:

import java.util.ArrayList;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class contourCheck {

public static void main(String[] args) {

    // initialises openCV   
    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);   

    // reads original black&white image
    Mat binary_image =  Imgcodecs.imread("C:/Users/MyName/Desktop/TestImages/testpic.png", Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);

    // creates temporary Mat
    Mat temp_image = binary_image;

    // inverts image
    Core.bitwise_not(temp_image,temp_image);

    // finds all contours in the image
    ArrayList<MatOfPoint> contours = new ArrayList<MatOfPoint>();
    Imgproc.findContours(temp_image, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_NONE);

    // deletes contours above minArea to keep only the contours that are supposed to be removed from the image
    int minArea = 10;
    for (int i = 0; i < contours.size(); i++) {
        double area = Imgproc.contourArea(contours.get(i));
        if (area > minArea) {
            contours.remove(i);
        }   
    } 
    System.out.println("number of contours remaining: " + contours.size());  
    for (int j = 0; j < contours.size(); j++) {

        if (j > 0) { // apparently temp_image gets also inverted, therefore it gets inverted here once again
            Core.bitwise_not(temp_image,temp_image);
        }
        // fills in small (<= minArea) contours with 0's  
        Imgproc.drawContours(temp_image, contours,j, new Scalar(0),Core.FILLED);

        // inverts image once again to get the original state
        Core.bitwise_not(temp_image,binary_image);

        // writes image with filtered contours
        Imgcodecs.imwrite("C:/Users/MyName/Desktop/TestImages/test/testpic_filtered" + j + ".png", binary_image);
    }
}
}

Ahora aquí está una imagen ejemplo en el que me gustaría para eliminar todos los puntos negros que están por debajo minArea(= 10):

imagen de ejemplo binario ( "testpic.png")

Lo que me sorprende ahora es que algunos de los muy grandes componentes se eliminan (por ejemplo, el gran círculo con algunos pequeños círculos en el interior o la enorme rectángulo), mientras que los más pequeños se mantienen. ¿Hay un error en mi código o estoy entendiendo mal algunos conceptos aquí? Además, ¿por qué bitwise_not también invertido temp_image, la fuente Mat ( Core.bitwise_not(temp_image,binary_image))?

Nota: el código crea una imagen para cada contorno que se elimina, lo que significa que 74 imágenes se crean.

Ejemplo de salida (última imagen después de eliminar todos los contornos):

imagen con contornos retira

Dan Masek:

Las mentiras de problemas en el siguiente bucle:

for (int i = 0; i < contours.size(); i++) {
    double area = Imgproc.contourArea(contours.get(i));
    if (area > minArea) {
        contours.remove(i);
    }   
}

Aviso, que permite repetir contours, y al mismo tiempo, a veces removeelementos. Hay que recordar que removese desplazará todos los elementos posteriores hacia delante en una posición. Ahora, se incrementa el índice en cada iteración. Esto provocará que se salte un contorno, por cada uno que haya eliminado. Dado que su objetivo actual es mantener únicamente las pequeñas contornos suficientes, el efecto es que algunos de los más grandes se deslizan a través.

Mi sugerencia para resolver este problema sería la de adoptar un enfoque ligeramente diferente - en lugar de eliminar los contornos indeseables, me gustaría crear una nueva instancia de ArrayList<MatOfPoint>, y rellenarla con los contornos que estoy interesado y el uso que, en su posterior procesamiento.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=221198&siteId=1
Recomendado
Clasificación