6

输入图像: 在此处输入图像描述

预期输出: 在此处输入图像描述

我打算拟合三个(或一定数量的)多边形(在本例中为矩形)来表示此图像中的“大”白色斑点。输出图像中绘制的矩形是根据我对白色区域的感知。我不希望算法提出这些相同的边界区域。我希望在白色像素簇周围放置一些紧密的多边形。

我最初的解决方案包括找到这个图像的轮廓,并在每个轮廓周围拟合一个封闭的凸多边形,方法是找到每个轮廓中点的凸包。

然而,由于白色区域高度碎片化,黑色区域在内部并在边缘周围呈脊状,因此 cv2.findContours 返回的轮廓数非常高(大约 500 个左右)。因此,拟合凸包不会改善白色区域的形状。白色区域大多保留其原始的抽象形状。我的目标是将白色区域的许多小轮廓合并为一个包含轮廓的整体,然后我可以在该轮廓上拟合凸包。

我该如何解决这个问题?我应该最初在轮廓点上使用聚类算法来找到彼此靠近的轮廓吗?

4

4 回答 4

6

您首先需要在此图像上执行形态闭合(膨胀后腐蚀)。这会关闭图像中的所有小“洞”,同时保留各个组件的形状和大小。与之相反,当腐蚀之后是膨胀时,它会去除图像中的噪声点。我正在处理类似的图像,我必须执行多达 10 次膨胀+腐蚀才能使我的组件均匀。完成后,使用连接组件或查找轮廓。这肯定会使等高线计数从 400 减少到 20-30。

其次,您提到您需要 3 个集群。虽然这两个小集群(由红线覆盖)可以合并为一个。我从中得出的结论是,您希望您的每个集群都尽可能紧密地适合其边界矩形。所以,我建议你设置一个阈值效率(比如 80%)并使用层次聚类将每个连接的组件合并到一个集群中。当您的白色像素使用少于其边界矩形(集群)的 80% 空间时,您将停止集群并获取集群。

于 2014-05-29T11:21:43.340 回答
2

您可以先放大图像,然后再找到轮廓。膨胀导致明亮区域增长。您可以将其视为在图像中每个现有的白色像素周围添加白色像素。这样相邻的明亮形状就会合并。见http://docs.opencv.org/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.html

您也可以再次模糊和阈值,但根据模糊量的不同,模糊可能比膨胀更昂贵。

于 2013-06-18T01:09:31.607 回答
1

您可以使用 kmeans 聚类,使用 xy 坐标作为每个白点和三个聚类的特征。然后取所得三个簇的凸包。您可能必须尝试不同的起点并选择最佳结果。看http://docs.opencv.org/modules/core/doc/clustering.html#kmeans

于 2013-06-18T00:32:06.687 回答
1

您可以在形状周围绘制近似轮廓,直到连接所有需要的区域。有了这个,我有效地侵蚀了形象。如果你在这些连接区域周围画一个外壳,你会得到你的红色矩形。

重复直到你最大的三个船体有一些必要的属性(例如,如果它们覆盖了所有白点的 99%)

#include <vector>
using std::vector;
#include <algorithm>
using std::sort;
#include <string>
using std::string;
using std::to_string;
#include <iostream>
using std::clog;
using std::endl;
#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
  typedef vector<Point> Polygon;
  typedef vector<Polygon> Polygons;
  Mat mFrame;
  Mat mOrig;
  mFrame = imread("R2TsZ.png");
  mFrame.copyTo(mOrig);
  Mat mOrigHull;
  Mat mOut;
  int fileCounter = 0;
  while(true){
    clog<< "image read"<< endl;
    cvtColor(mFrame, mOut, CV_BGR2GRAY);
    clog<< "image grayscaled"<< endl;
    Polygons contours;
    Polygons aContours;
    Polygons hulls;
    OutputArray hierarchy = {};

    findContours(mOut, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    clog<< contours.size()<< " contours found"<< endl;
    sort(contours.begin(), contours.end(), [](auto p1, auto p2){
      return contourArea(p1) > contourArea(p2);
    });
    clog<< "contours sorted"<< endl;
    aContours.resize(contours.size());
    hulls.resize(contours.size());
    for(size_t i = 0; i < aContours.size() - 1; ++ i){
      approxPolyDP(contours[i], aContours[i], 20, true);
      drawContours(mFrame, aContours, i, Scalar(255, 255, 255), 10);
      convexHull(aContours[i], hulls[i], true);
    }
    mOrig.copyTo(mOrigHull);
    for(size_t i = 0; i < 3; ++ i){
      drawContours(mOrigHull, hulls, i, Scalar(0, 0, 255), 10);
    }
    imshow("out", mOrigHull);
    int key = waitKey() & 0xff;
    if(key == 27){
      return EXIT_SUCCESS;
    }
    if(key == 'p'){
      string file = "test_" + to_string(++ fileCounter) + ".png";
      imwrite(file, mOrigHull);
      clog<< file<< " saved."<< endl;
    }
  }
}

在opencv的本教程中查看更多信息。

在此处输入图像描述

于 2016-08-14T13:12:35.623 回答