找到轮廓在模拟图像上找到太多轮廓

时间:2019-09-23 13:24:06

标签: opencv image-processing opencv-contour

我想找到分段岩石的二值图像的轮廓。 opencv的findContours函数存在一些问题。

  1. 轮廓大小约为1000,而二进制图像的轮廓可能约为30-50。

  2. 当我绘制所有轮廓时,它们似乎很好地代表了二进制图像中的黑色边界。但是,当我只绘制一个随机索引的轮廓时,它显示的轮廓很小。

图像如下:

  • 二进制图像

enter image description here

  • 所有索引的轮廓

enter image description here

  • 随机轮廓索引的轮廓。绿色的小轮廓

enter image description here

我只希望具有与二进制图像相同的轮廓数量。

代码:

std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(input_image, contours,hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
  for( int i = 0; i < (int)contours.size(); i++)
  {

      cv::drawContours(input_rgb_image, contours, 512 , cv::Scalar(0,255,0), 1, 8, hierarchy,1);


  }


2 个答案:

答案 0 :(得分:1)

您的代码有两个问题。如果对图像进行倒置和模糊处理,将会得到更好的结果。这些是在找到轮廓之前应用了这两个操作之后的结果: contours

OpenCV findContours()函数可在浅色背景上找到深色轮廓。如果要查找白色空间(即岩石),则需要先反转二进制图像。您可以像这样invertedImage = 255 - binaryImage反转二进制图像。模糊也有帮助,因为它连接了应该连接的像素,但不是因为分辨率较低。使用代码blurredImage = cv2.blur(img, (2,2))进行模糊处理。这是倒置的模糊图像:

invert and blur

这是我使用的代码:

import cv2
import random
# Read image
gray = 255-cv2.imread('/home/stephen/Desktop/image.png', 0)
gray = cv2.blur(gray, (2,2))
# Find contours in image
contours, _ = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print(len(contours))
img = cv2.imread('/home/stephen/Desktop/image.png')
for cnt in contours:
    color = random.randint(0,255),random.randint(0,255),random.randint(0,255)
    img = cv2.drawContours(img, [cnt], 0, color, cv2.FILLED)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

答案 1 :(得分:1)

我会尝试几件事:

  • 双边过滤器而不是模糊的。它以类似的方式平滑事物 进行模糊处理,但也尝试保留边界,这对分割很有用。缺点-计算量大,但您可能会 找到免费玩的“您的​​”参数
  • 分水岭前的模糊+均值漂移分割。模糊只会起作用 如预期的和均值偏移将平均并加入等高线 相似的颜色,从而减少轮廓的数量。 根据参数,均值漂移也很昂贵。只是玩 它。

更高级的是事后轮廓分析。您可以根据以下条件团结一些邻居:

  • 某些hsv通道上直方图的相似性
  • 轮廓属性,例如圆度。如果两个圆度统一 邻居比任何一个国家的圆度都要好,这样他们才能团结起来。像这样的东西。

圆度计算:

float calcRoundness(std::vector<cv::Point> &contour, double area)
{
        float p = cv::arcLength(contour, true);
        if (p == 0)
                return 0;
        float k = (4 * M_PI * area) / pow(p, 2);

        /* 1 is circle, 0.75 - squared area, etc. */
        return k;
}