从图像点构建树/图

时间:2013-12-22 13:55:29

标签: c++ opencv graph tree

我开始用这张图片描述我的问题: enter image description here

在图片中,我们可以看到一些点(黑色点)。我想要做的是首先存储所有点,然后找到节点点和提示点(红色点)。 更重要的是,我需要检查这些红点是否可以通过直线(沿着黑点)连接,以找到红线之间的角度。

我不知道我是否清楚地解释了它,但我想是我应该实现一个树/图,而不是使用一些路径查找来检查红点是否已连接?

基本上,我开始使用类似的东西:

class Point {
public:
int x;
int y;
vector<Point> neighbors;

Point(void);
Point(int x, int y);
}

vector<Point> allPoints;

我在allPoints向量中存储所有点的位置。比每个Point,我检查他的所有邻居([x + 1,y],[x-1,y],[x + 1,y + 1],[x-1,y + 1] ,...)并将它们存储在Point的邻居向量中。

然后,根据邻居向量的大小,我确定Point是节点(3个或更多邻居),提示(1个邻居),或者只是一些基本点(2个邻居)。

这里是部分,我不知道如何实现一些路径查找(检查是否有一种方法,例如从尖端点到最近的节点)。

更重要的是,我不知道我的“树”表示是否良好(可能不是)。所以如果有人帮我实现我想要的东西,那就太好了。


P.S。我正在用C ++(和OpenCV)和VS2010编写。

修改

这就是它在真实程序中的样子(红色线条被我淹没在油漆中,但这就是我想要实现的目标):

enter image description here

2 个答案:

答案 0 :(得分:1)

我不确定该帖子应该是答案还是编辑,因为我不知道是否有人会注意到我添加了某些内容,我决定将其作为答案发布。对不起,如果错了。

关于问题。我做了一些编码,我相信我知道怎么做我想要的,但另一个问题出来了; d。

让我们从图片开始:

enter image description here

要查看问题所在,您必须放大图片,大约400%,然后查看绿色矩形。图像“骨架”是我的基本线,而图像“temp”,是我的输出提示和节点。正如你所看到的,提示很好(紫罗兰色矩形)(带有1个邻居的点)但不幸的是有些像素有3个或更多邻居并且它们不是节点的行(“骨架”上的右绿色矩形是没有节点的行..和“temp”上的绿色矩形是我的假节点..由于特定的像素位置而被标记)。当你超级缩放它时,你会注意到我用颜色标记像素以使其更清晰。

所以问题在于,有时节点和“分支”都有两个以上的邻居,这导致我遇到“如何找到它们之间的差异”的问题。我需要的只是节点(“骨架”图像上的小绿色矩形 - 当你缩放时,你会发现有2个像素可能是一个节点,但只要它们彼此如此接近就不重要了。) / p>

任何帮助?

如果您需要代码,请告诉我,我会编辑&amp;粘贴它。

编辑:

我做了一些事情!

我找到了一种从线上过滤冗余像素的方法。但这使我的一些骨架线断开连接,这并不好,因为现在有些节点被视为“提示”。

看看图片: enter image description here

小点是“好”节点,但红色矩形内的点是断开连接的节点(放大以查看),现在被视为提示。

我是如何过滤像素的?这是代码:

void SKEL::clearPixels(cv::Mat& input)
{
    uchar* data = (uchar *)input.data;
    for (int i = 1 ; i < input.rows-1 ; i++)
    {
        for (int j = 1 ; j < input.cols-1 ; j++)
        {
            if (input.at<uchar>(i,j) == 255) //if its part of skeleton
            {
                if (input.at<uchar>(i-1,j+1) == 255)
                {
                    if (input.at<uchar>(i,j+1) == 255)  data[i*input.step+(j+1)*input.channels()] = 0;
                    if (input.at<uchar>(i-1,j) == 255)  data[(i-1)*input.step+(j)*input.channels()] = 0;
                }
                if (input.at<uchar>(i+1,j+1) == 255)
                {
                    if (input.at<uchar>(i,j+1) == 255)  data[i*input.step+(j+1)*input.channels()] = 0;
                    if (input.at<uchar>(i+1,j) == 255)  data[(i+1)*input.step+(j)*input.channels()] = 0;
                }
                if (input.at<uchar>(i-1,j-1) == 255)
                {
                    if (input.at<uchar>(i,j-1) == 255)  data[i*input.step+(j-1)*input.channels()] = 0;
                    if (input.at<uchar>(i-1,j) == 255)  data[(i-1)*input.step+(j)*input.channels()] = 0;
                }
                if (input.at<uchar>(i+1,j-1) == 255)
                {
                    if (input.at<uchar>(i,j-1) == 255)  data[i*input.step+(j-1)*input.channels()] = 0;
                    if (input.at<uchar>(i+1,j) == 255)  data[(i+1)*input.step+(j)*input.channels()] = 0;
                }
            }
        }
    }
}

对于每个像素,我检查它是否有(x + 1,y-1)(x + 1,y + 1)(x-1,y + 1)(x-1,y-1)邻居和if它确实,我检查了邻居旁边是否有邻居并将其删除。这是我唯一的想法,它很慢,但就目前来说,没有什么比这更好的了。

所以现在,我的主要问题是。如何重新连接损坏的节点? ..

答案 1 :(得分:0)

这已经很晚了,但是我得到了一些工作并把它放在github repo: pixeltree中(它太大了,不能在这里粘贴整个东西)。我在python而不是c ++工作,但我希望如果你或其他人需要它,这个想法会有所帮助。免责声明 - 可能有一些可接受的方法,但我找不到它。

方法

  1. 将图像分成任意数量的区域(例如黑/白)
  2. 对于每个地区,请选择任意像素
  3. 从该像素构建一个覆盖区域中每个像素的完整树
  4. 削减树的无意义分支,直到它是最小的树
  5. 详细

    困难的部分是砍伐树木的最后一步。这是我使用的方法:

    1. 再次为每个区域选择一个“远”像素的根(技术上,图中最长路径的一端)。
    2. 对于该树中的每个叶子,执行广度优先搜索,直到遇到另一个分支。如果此叶子的高度小于遇到的像素,则消除该叶子的分支。
    3. 实施例

      Pre-reduced hand Image with large areas Image with various test sections

      执行大部分工作的令人尴尬的大功能:

      def treeify(image, target_families=None):
          # family map is used everywhere to identify pixels, regions, etc.
          family_map = _make_family_map(image)
          target_families = target_families or np.unique(family_map)
          trees = list()
          rows, cols = family_map.shape
          remaining_points = set((r, c) for r in range(rows) for c in range(cols)
                                 if family_map[r, c] in target_families)
          # the "tree" here is actually just a non-cyclic undirected graph which could
          # be rooted anywhere. The basic graph is done with each pixel pointing to some neighbors (edges)
          edges = np.empty_like(family_map, dtype=object)
          edges.flat = [set() for _ in edges.flat]
          # continue until all regions within the graph are handled
          while remaining_points:
              # grow a tree from any remaining point until complete
              start_p = remaining_points.pop()
              family = family_map[start_p]
              tree = {'family': family,
                      'any_point': start_p}
              trees.append(tree)
              q = [(None, start_p)]
              while q:
                  # pushright + popleft --> breadth first expansion
                  # random within left part of q - roughly BFS with less pattern
                  source, p = q.pop(random.randrange(0, max(1, len(q)//2)))
                  try:
                      remaining_points.remove(p)
                  except KeyError:
                      pass # tree start point is always already gone
                  # send qualifying neighbors for expansion
                  q_points = tuple(qp for sp, qp in q)
                  expansion_points = [n for n in _neighbors(p, 'all', family_map)
                                      if all((n != source,
                                              n in remaining_points,
                                              n not in q_points,
                                              family_map[n] == family))]
                  expansion_pairs = [(p, n) for n in expansion_points]
                  q.extend(expansion_pairs)
                  # document all edges for this point
                  if source is None:
                      all_connections = list(expansion_points)
                  else:
                      all_connections = expansion_points + [source]
                  edges[p].update(all_connections)
      
          # prune all but "best" branches within each area
          for tree in trees:
              family = tree['family']
              # root graph at one end of the longest path in the graph
              distant_point = _most_distant_node(tree['any_point'], edges)
              # for choosing best paths: document the height of every pixel
              heights = _heights(distant_point, edges)
              remaining_leaves = set(_leaves(distant_point, edges))
              # repeatedly look for a leaf and decide to keep it or prune its branch
              # stop when no leaves are pruned
              while remaining_leaves:
                  leaf = remaining_leaves.pop()
                  # identify any degenerate path to next branching pixel
                  # this path is ignored when testing for nearby branches
                  ignore = set(_identify_degenerate_branch(leaf, edges))
                  # BFS expansion to find nearby other branches
                  expansion_q = deque()
                  expansion_q.append(leaf)
                  while expansion_q:
                      p = expansion_q.popleft() # pushright + popleft for BFS
                      ignore.add(p)
                      # decide what to do with each neighbor
                      for n in _neighbors(p, 'sides', family_map):
                          if n in ignore:
                              continue # already decided to ignore this point
                          elif n in expansion_q:
                              continue # already slated for expansion testing
                          elif family_map[n] != family:
                              ignore.add(n) # ignore other families
                              continue
                          elif len(edges[n]) == 0:
                              expansion_q.append(n) # expand into empty spaces
                          elif _disqualified(leaf, n, edges, heights):
                              _prune_branch_of_leaf(leaf, edges, heights)
                              expansion_q.clear() # this leaf is done. stop looking
                              break
                          else:
                              expansion_q.append(n)
          return trees, edges