在 OpenCV (Java) 中增强边缘,同时去除噪声
Enhance edges in OpenCV (Java) while removing noise
我正在尝试在 Java 中编写一个 OpenCV 程序,该程序拍摄带有 phone 的标记的照片并在标记上找到圆形轮廓。我已经让它在 Android 模拟器(照片具有完美的照明条件)中工作,但无法让它与 phone 本身一起工作。
这是我要捕获的标记:
在使用转换为灰度、高斯模糊和 Canny 边缘检测器的组合后,我得到了这个输出:
如果我随后尝试在图像上找到轮廓,返回的轮廓数量确实很多(超过 1000 个),但它们并没有闭合(因为边缘似乎太弱了。
在原始图像上绘制的轮廓:
这是我用于分割的代码:
Mat processed = new Mat(original.height(), original.width(), original.type());
Imgproc.cvtColor(original, processed, Imgproc.COLOR_RGB2GRAY);
Imgproc.GaussianBlur(processed, processed, new Size(7, 7), 0.1);
Imgproc.Canny(processed, processed, 50, 50*3, 3, false);
我尝试调整不同的参数(阈值等),但感觉这不是理想的解决方案。我在想必须有一种方法来增强 canny 检测器返回的边缘,但我自己还没有找到任何东西。
感谢任何帮助!
您可以查看 dilation
在 opencv 中的操作以增强边缘。
https://docs.opencv.org/4.x/db/df6/tutorial_erosion_dilatation.html
另请查看下面的示例,其中包含 Canny
边缘检测、approxPolyDP
和 minEnclosingCircle
。非常接近你的问题。
https://docs.opencv.org/4.x/da/d0c/tutorial_bounding_rects_circles.html
https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#ga0012a5fdaea70b8a9970165d98722b4c
https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#ga8ce13c24081bbc7151e9326f412190f1
你想要这样的东西吗?
噪声通常存在 - 它可以减少 - 你可以用 adaptiveThreshold 区分圆圈,然后使用我下面描述的方法找到圆圈。关键是,您从相机获得的真实世界图像可能包含一大堆其他圆圈 - 因此最好找到所有圆圈。比较它们的大小。找出在颜色、大小和位置方面与您的标记最相似的 4 个圆圈。
快速python区分圆圈的代码:
# Make a gray version
gry = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# Thresh
ada = cv2.adaptiveThreshold(
gry, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2
)
# Remove noises
out = cv2.medianBlur(ada, 7)
# Invert colors (Not needed)
out = ~out
我测试了 Python 代码并且它有效;您可以找到 Java 或 C++ 的等价物。我试图解释 Java 代码,但我是临时写的,没有测试它。我写的 Java 代码可能有错误,但它确实抓住了要点。稍微改变一下可能会起作用。我还编写了应该将圆圈作为最后一个块的代码。使用它很棘手,需要调整参数。
Java:
...
Imgproc.cvtColor(im, gry, Imgproc.COLOR_RGBA2GRAY);
Imgproc.adaptiveThreshold(gry, ada, 255,
Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 11, 2);
Imgproc.medianBlur(ada, out, 7);
...
寻找圈子:
Java:
...
SimpleBlobDetector_Params params = new SimpleBlobDetector_Params();
params.set_filterByCircularity(true);
params.set_minCircularity(0.01f);
params.set_maxArea(50000);//important
SimpleBlobDetector detector = SimpleBlobDetector.create(params);
// List of detected points
MatOfKeyPoint keyPoints = new MatOfKeyPoint();
detector.detect(ada, keyPoints);
// Draw circles on final image
Scalar color = new Scalar(127, 0, 255);
for (KeyPoint key: keyPoints.toList()) {
Imgproc.circle(im, key.pt, (int) (key.size / 2.0f), color, 3/*Thickness*/);
}
...
我正在尝试在 Java 中编写一个 OpenCV 程序,该程序拍摄带有 phone 的标记的照片并在标记上找到圆形轮廓。我已经让它在 Android 模拟器(照片具有完美的照明条件)中工作,但无法让它与 phone 本身一起工作。 这是我要捕获的标记:
在使用转换为灰度、高斯模糊和 Canny 边缘检测器的组合后,我得到了这个输出:
如果我随后尝试在图像上找到轮廓,返回的轮廓数量确实很多(超过 1000 个),但它们并没有闭合(因为边缘似乎太弱了。 在原始图像上绘制的轮廓:
这是我用于分割的代码:
Mat processed = new Mat(original.height(), original.width(), original.type());
Imgproc.cvtColor(original, processed, Imgproc.COLOR_RGB2GRAY);
Imgproc.GaussianBlur(processed, processed, new Size(7, 7), 0.1);
Imgproc.Canny(processed, processed, 50, 50*3, 3, false);
我尝试调整不同的参数(阈值等),但感觉这不是理想的解决方案。我在想必须有一种方法来增强 canny 检测器返回的边缘,但我自己还没有找到任何东西。
感谢任何帮助!
您可以查看 dilation
在 opencv 中的操作以增强边缘。
https://docs.opencv.org/4.x/db/df6/tutorial_erosion_dilatation.html
另请查看下面的示例,其中包含 Canny
边缘检测、approxPolyDP
和 minEnclosingCircle
。非常接近你的问题。
https://docs.opencv.org/4.x/da/d0c/tutorial_bounding_rects_circles.html
https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#ga0012a5fdaea70b8a9970165d98722b4c
https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#ga8ce13c24081bbc7151e9326f412190f1
你想要这样的东西吗?
噪声通常存在 - 它可以减少 - 你可以用 adaptiveThreshold 区分圆圈,然后使用我下面描述的方法找到圆圈。关键是,您从相机获得的真实世界图像可能包含一大堆其他圆圈 - 因此最好找到所有圆圈。比较它们的大小。找出在颜色、大小和位置方面与您的标记最相似的 4 个圆圈。
快速python区分圆圈的代码:
# Make a gray version
gry = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# Thresh
ada = cv2.adaptiveThreshold(
gry, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2
)
# Remove noises
out = cv2.medianBlur(ada, 7)
# Invert colors (Not needed)
out = ~out
我测试了 Python 代码并且它有效;您可以找到 Java 或 C++ 的等价物。我试图解释 Java 代码,但我是临时写的,没有测试它。我写的 Java 代码可能有错误,但它确实抓住了要点。稍微改变一下可能会起作用。我还编写了应该将圆圈作为最后一个块的代码。使用它很棘手,需要调整参数。
Java:
...
Imgproc.cvtColor(im, gry, Imgproc.COLOR_RGBA2GRAY);
Imgproc.adaptiveThreshold(gry, ada, 255,
Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 11, 2);
Imgproc.medianBlur(ada, out, 7);
...
寻找圈子:
Java:
...
SimpleBlobDetector_Params params = new SimpleBlobDetector_Params();
params.set_filterByCircularity(true);
params.set_minCircularity(0.01f);
params.set_maxArea(50000);//important
SimpleBlobDetector detector = SimpleBlobDetector.create(params);
// List of detected points
MatOfKeyPoint keyPoints = new MatOfKeyPoint();
detector.detect(ada, keyPoints);
// Draw circles on final image
Scalar color = new Scalar(127, 0, 255);
for (KeyPoint key: keyPoints.toList()) {
Imgproc.circle(im, key.pt, (int) (key.size / 2.0f), color, 3/*Thickness*/);
}
...