java - OpenCV Java |在二进制图像中按区域删除 Blob

标签 java opencv image-processing

我有一张黑白图像(单 channel ,仅 0 和 255),我想使用 Java 中的 openCV 3.4.2 删除其中低于特定区域阈值的小 Blob 。

现在我已经找到了以下线程:Removing blobs from a binary image ,这几乎是一样的——但我需要一些帮助将答案翻译成 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) 以下的所有黑点:

example binary image ("testpic.png")

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

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

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

image with contours removed

最佳答案

问题出在下面的循环中:

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> 实例。 ,并用我感兴趣的轮廓填充它,并在进一步处理中使用它。

关于java - OpenCV Java |在二进制图像中按区域删除 Blob ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52156460/

相关文章:

Java 字符串 - 获取(但不包括)两个正则表达式之间的所有内容?

opencv - 将系统::绘图::位图^转换为::MAT

opencv - 使用 OpenCV 从边缘图像中去除长水平/垂直线

python - 在 Python 3.7 中更改 NIFTI 的整个图像切片

java - 继承时避免从父类(super class)转换为子类

java - 创建 bean sessionFactory 时出现不兼容的类更改错误

c++ - 在 cv::resize() 之后图像奇怪地改变了

python - 背景减法python opencv(去除颗粒)

algorithm - 如何在matlab中找到图像的动态中心点?

java - 当值大于 x 时从 map 中删除的最佳方法是什么