我开始用这张图片描述我的问题:
在图片中,我们可以看到一些点(黑色点)。我想要做的是首先存储所有点,然后找到节点点和提示点(红色点)。 更重要的是,我需要检查这些红点是否可以通过直线(沿着黑点)连接,以找到红线之间的角度。
我不知道我是否清楚地解释了它,但我想是我应该实现一个树/图,而不是使用一些路径查找来检查红点是否已连接?
基本上,我开始使用类似的东西:
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编写。
修改
这就是它在真实程序中的样子(红色线条被我淹没在油漆中,但这就是我想要实现的目标):
答案 0 :(得分:1)
我不确定该帖子应该是答案还是编辑,因为我不知道是否有人会注意到我添加了某些内容,我决定将其作为答案发布。对不起,如果错了。
关于问题。我做了一些编码,我相信我知道怎么做我想要的,但另一个问题出来了; d。
让我们从图片开始:
要查看问题所在,您必须放大图片,大约400%,然后查看绿色矩形。图像“骨架”是我的基本线,而图像“temp”,是我的输出提示和节点。正如你所看到的,提示很好(紫罗兰色矩形)(带有1个邻居的点)但不幸的是有些像素有3个或更多邻居并且它们不是节点的行(“骨架”上的右绿色矩形是没有节点的行..和“temp”上的绿色矩形是我的假节点..由于特定的像素位置而被标记)。当你超级缩放它时,你会注意到我用颜色标记像素以使其更清晰。
所以问题在于,有时节点和“分支”都有两个以上的邻居,这导致我遇到“如何找到它们之间的差异”的问题。我需要的只是节点(“骨架”图像上的小绿色矩形 - 当你缩放时,你会发现有2个像素可能是一个节点,但只要它们彼此如此接近就不重要了。) / p>
任何帮助?
如果您需要代码,请告诉我,我会编辑&amp;粘贴它。
编辑:
我做了一些事情!
我找到了一种从线上过滤冗余像素的方法。但这使我的一些骨架线断开连接,这并不好,因为现在有些节点被视为“提示”。
看看图片:
小点是“好”节点,但红色矩形内的点是断开连接的节点(放大以查看),现在被视为提示。
我是如何过滤像素的?这是代码:
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 ++工作,但我希望如果你或其他人需要它,这个想法会有所帮助。免责声明 - 可能有一些可接受的方法,但我找不到它。
困难的部分是砍伐树木的最后一步。这是我使用的方法:
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