繁体   English   中英

openCV Java | 在二进制图像中按区域删除blob

[英]openCV Java | Remove blobs by area in a binary image

我有一个黑白图像(单通道,0和255只),我想在Java中使用openCV 3.4.2删除低于某个区域阈值的小blob。

现在我已经找到了以下线程: 从二进制映像中删除blob ,这几乎是一样的 - 但我需要一些帮助将答案转换为Java代码。 此外,由于我想删除黑点,我在处理前后反转图像。 编辑:感谢一些建议,我设法得到一个工作代码并修改它,所以现在它是一个MCVE。

我到目前为止的尝试:

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);
    }
}
}

现在这是一个示例图片,我想删除minArea (= 10)以下的所有黑点:

示例二进制图像(“testpic.png”)

我现在感到惊讶的是,一些非常大的组件被移除(例如,内部有一些小圆圈的巨大圆圈或巨大的矩形),而较小的组件被保留。 我的代码中是否有错误,或者我在这里误解了一些概念? 另外,为什么bitwise_not还会反转temp_image ,源Mat( Core.bitwise_not(temp_image,binary_image) )?

注意:代码为每个被删除的轮廓创建一个图像,这意味着创建了74个图像。

示例输出(删除所有轮廓后的最后一个图像):

删除轮廓的图像

问题出在以下循环中:

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

请注意,您迭代contours ,同时有时会remove元素。 请记住, remove会将所有后续元素向前移动一个位置。 现在,您在每次迭代时递增索引。 这将导致您跳过每个已删除的轮廓。 由于你目前的目标只是保留足够小的轮廓,效果是一些较大的轮廓会滑过。

我解决这个问题的建议是采用稍微不同的方法 - 而不是删除不想要的轮廓,我创建一个新的ArrayList<MatOfPoint>实例,并用我感兴趣的轮廓填充它并使用它在进一步处理中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM