我有一张黑白图像(单 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) 以下的所有黑点:
现在让我感到惊讶的是,一些非常大的组件被删除了(例如,里面有一些小圆圈的大圆圈或巨大的矩形),而较小的组件被保留了下来。我的代码中有错误还是我误解了这里的一些概念?另外,为什么 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>
实例。 ,并用我感兴趣的轮廓填充它,并在进一步处理中使用它。
关于java - OpenCV Java |在二进制图像中按区域删除 Blob ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52156460/