图中的角点和边缘检测

Posted

技术标签:

【中文标题】图中的角点和边缘检测【英文标题】:Corner and edge detection in a graph 【发布时间】:2015-11-20 12:14:32 【问题描述】:

我目前正在尝试编写一个角和边缘检测方案,该方案应该能够检测图形中的角和边。

图形数据结构是从一个二维字符数组构建的,看起来像这样 这个例子的大小是 10 行和 9 列。 (空白填补了剩下的空白,我无法在边框处添加空白...?)

      ...
 ..Y.....
 ..Y   .
  ZYZ.Z.Z
  .Y ....
  .M
  ..

为节点中的每个字符创建一个节点,并将完整的图形存储为vector<Node> graph

每个节点都是这样定义的

struct Node

    char character;
    pair<int,int> position;
    bool lock;
    vector<Vertex> adjacent;
;

struct Vertex

   Node *current;
   Node *nextTo;

;

所以.. 我有很多节点,但其中一些在我的用例中是多余的,每个节点都有一个 bool lock => 告诉系统应该忽略这些节点。

我要忽略的节点是那些在地图中具有字符 . 并位于角落位置的节点(节点本身有 2 个邻居(大小向量邻居 == 2)),或者具有字符. 位于两个角之间。如果两个角之间出现其他字符,则仅将角设置为锁定。在遍历拐角的相邻节点时(寻找第二个拐角),并且一个节点有4个相邻节点,只会将看到的第一个拐角设置为锁定。

所以..我把它写成一些最终看起来像这样的代码。

 for(auto graph_it = begin(graph); graph_it != end(graph); graph_it++)
    
        if(graph_it->adjacent.size() == 2 && graph_it->character == '.')
        
            vector<Node*> trace;
            cout << "corner found " <<"("<< graph_it->position.first <<","<< graph_it->position.second << ")" << endl;
            graph_it->lock = true;

            for (Vertex edge : graph_it->adjacent)
            
                cout << "Check neighbour direction" << endl;
                int changeX = 0;
                int changeY = 0;

                changeX = graph_it->position.first - edge.nextTo->position.first;
                changeY = graph_it->position.second - edge.nextTo->position.second;

                cout << "neighbour direction is first: " << changeX << changeY << endl;
                auto start_position = edge.nextTo;
                vector<Node*> trace;
                bool endIsCorner = false;
                bool conditionMet = false;
                cout << endl;
                while((start_position->adjacent.size() != 2|| start_position->adjacent.size() != 4) /*&& start_position->character =='.'*/)
                
                    for(Vertex traversing_edge : start_position->adjacent)
                    
                        cout <<"position before: " << graph_it->position.first << graph_it->position.second << " now position: "<< start_position->position.first << start_position->position.second <<  " change is: " << (start_position->position.first - traversing_edge.nextTo->position.first) <<  " " << start_position->position.second - traversing_edge.nextTo->position.second  << " character is: " << traversing_edge.nextTo->character << endl;
                        if (traversing_edge.nextTo->adjacent.size() == 2)
                        
                            cout << "error found case 1" << endl;
                            cout << "position: " << traversing_edge.nextTo->character << traversing_edge.nextTo->position.first << traversing_edge.nextTo->position.second << endl;
                            start_position = traversing_edge.nextTo;
                            start_position->lock =true;
                            trace.push_back(start_position);
                            endIsCorner = true;
                            conditionMet = true;
                            break;
                        
                        else if(traversing_edge.nextTo->adjacent.size() == 4)
                        
                            cout << "error found case 2" << endl;
                            cout << "position: " << traversing_edge.nextTo->character << traversing_edge.nextTo->position.first << traversing_edge.nextTo->position.second << endl;
                            conditionMet = true;
                            break;
                        

                        if (start_position->position.first - traversing_edge.nextTo->position.first  == changeX && start_position->position.second - traversing_edge.nextTo->position.second == changeY)
                        
                            if (traversing_edge.nextTo->adjacent.size() == 3 )
                            
                                start_position = traversing_edge.nextTo;
                                cout << "traversed to position: " << start_position->position.first << start_position->position.second <<" character: "<<start_position->character<< endl;
                                trace.push_back(start_position);
                            

                            if (traversing_edge.nextTo->adjacent.size() == 2)
                            
                                edge.nextTo->lock = true;
                                start_position = traversing_edge.nextTo;
                                cout << "traversed to position being corner: " << start_position->position.first << start_position->position.second <<" character: "<<start_position->character<< endl;
                                trace.push_back(start_position);
                                endIsCorner = true;
                            

                            if (traversing_edge.nextTo->adjacent.size() == 4)
                            
                                cout << "traversed something else: " << start_position->position.first << start_position->position.second <<" character: "<<start_position->character<< endl;
                                start_position = traversing_edge.nextTo;
                            
                        
                        cout << endl;
                    
                    if (conditionMet)
                    
                        break;/* code */
                    

                
                if (endIsCorner == true)
                
                    for(auto traced: trace)
                    
                        cout << "Traced for locking position: " <<traced->position.first << traced->position.second << traced->character<< endl;
                        if (traced->character == '.')
                        
                            cout << "locking position: " <<traced->position.first << traced->position.second << traced->character<< endl;
                            traced->lock = true;
                        
                    
                
                else
                
                    trace.empty();
                    endIsCorner = false;
                
                cout<<endl;
            

        
        cout << endl;
    

  cout << "Locks detected" << endl;

当我意识到代码没有按照我想要的那样做时,我开始调试它..

所以我看到的第一件奇怪的事情就是这个。它检测为角的第一个节点是位于第 2 行和第 1 列的节点,这是正确的。

然后它尝试沿第一个 nextTo 节点方向的方向遍历,该方向是它下面的一个(第 3 行,第 2 列),它也是一个角,但不知何故它进入了 while 循环?我不明白。它的相邻向量大小为 2,调试器也这么说,但不知何故在 while 循环中它检测到大小为 2,并正确退出 while 循环并将其设置为要锁定的节点....(可能的问题)

当我完成这一切时,我检查了完整的图表,看看应该锁定的东西是否也被锁定了……事实并非如此。

for(auto node :  graph)
    
    cout << "node position: " <<"(" << node.position.first << "," << node.position.second << ")" << " " << node.character << endl;   
    if (node.locked)
    
      cout << node.position.first << node.position.second << endl;
    

为此我得到了这个输出

node position: (2,1) .
21
node position: (3,1) .
31
node position: (2,2) .
node position: (3,2) .
node position: (4,2) Z
node position: (5,2) .
52
node position: (6,2) .
node position: (7,2) .
72
node position: (2,3) Y
node position: (3,3) Y
node position: (4,3) Y
node position: (5,3) Y
node position: (6,3) M
node position: (7,3) .
73
node position: (2,4) .
24
node position: (4,4) Z
node position: (2,5) .
25
node position: (4,5) .
node position: (5,5) .
55
node position: (1,6) .
16
node position: (2,6) .
node position: (4,6) Z
node position: (5,6) .
node position: (1,7) .
node position: (2,7) .
node position: (3,7) .
37
node position: (4,7) .
node position: (5,7) .
57
node position: (1,8) .
18
node position: (2,8) .
28
node position: (4,8) Z
48
node position: (5,8) .
58

意味着它不仅锁定我想要锁定的那些(作为我放置在指定位置的字符.),而且锁定我不想锁定的那些(. 以外的字符)。

(5,2) should not be locked
(2,4) should not be locked
(2,5) should not be locked
(1,7) should be locked
(4,7) should be locked

这里出了什么问题.. 我很确定这一定与我在调试器中发现的问题有关,但我不明白为什么会发生这种情况?

---更新--

我似乎发现了另一个问题,如此处所示。

corner found (7,2)
Check neighbour direction
neighbour direction is first: 10

position before:  72 now position: 62 change is: 1 0 Element is: .
traversed in right direction . 
traversed to position: 52 Element: .

position before:  72   now position: 52 change is: -2 0 Element is: .
error found case 1
position: .72

这是从while循环中输出的。

while((start_position->adjacent.size() != 2|| start_position->adjacent.size() != 4) /*&& start_position->character =='.'*/)
                    
                        for(Vertex traversing_edge : start_position->adjacent)
                         .. 

我在for 循环中更改了start_position 的值,循环对此有何反应?.. 在我看来,它应该从头开始,从头开始,而不是继续迭代第一个start_position 向量。

应该是while 而不是for

Start_position 首先是放置在 (7,2) 的节点,然后它遍历到右侧的节点 (6,2),这成为新的 start_position。然后它再次向右移动 (5,2),start_position 成为该节点。但是变量traversing_edge 成为放置在 (7,2) 处的节点,从而错误地结束.. traversing_edge 成为一个不可能的值,因为与放置在 (5,2) 处的节点相邻的节点只有邻居 (4 ,2),(6,2) ,(5,3)... 所以这里肯定有问题..

--更新--

      DDD
 D.Y....D
 D.Y   .
  ZYZ.Z.Z
  .Y DDDD
  .M
  DD

没有节点具有大小为 1 的相邻向量,还会创建具有空白字符的节点。 D 显示应该锁定哪些节点。

--- Lamda 更新 ---

这是一个推箱子地图,M是人,Y是菱形,Z是目标。这个想法是 M 将 Y 推向某个方向,但为了防止将钻石移动到无法再次检索到的位置,该方案是否会对图形进行预处理,以便忽略这些位置。

【问题讨论】:

struct Vertex 应该是struct Edge 吗?不是解决方案——我只是看到这里的Vertex 和那里的Edge 感到困惑。 是的。我解决了这个问题。我试图通过只插入相关部分而不是整个代码来使帖子更容易理解。但似乎我有点搞砸了。但是Struct Vertex = Struct Edge。现在应该删除它。 抱歉——还没有用。您能否在处理输入后发布所需类型的 ASCII 艺术输出?我想确保我正确理解角和边的构成。 已添加.. 至少您正在尝试.. 这超出了我的预期:) 那么调试器可以完美地跟踪大量变量的大量更改。问题在于您(和其他所有人)的大脑,它不会跟踪超过 4-7 个并发问题。 【参考方案1】:

所以..我终于设法通过重写来解决我的问题..

新版本以不同的方式工作,在人眼看来似乎更有条理,但与上面发布的版本相比要慢一些。

我确定我在上面的代码中也发现了错误。 我过度使用基于范围的 for 循环,导致无法在对象的成员值上插入值,调试器显示给我..

解决这个问题和其他一些事情会让它工作。

我要感谢大家尝试帮助解决我的问题,非常感谢您的帮助。我不认为人们会对这么长的帖子做出反应,但同时我觉得我必须提供所有给定的信息,所以如果有人敢于研究它,他们会有合理的机会理解它..

谢谢:)

【讨论】:

恭喜您解决了问题。关于“长”问题:始终最好将您的问题限制为显示您实际问题的最短完整示例。另请参阅***.com/help/mcve,但“完整”部分与“最小”部分同样重要。在你的情况下,我想没有人真正详细阅读过你的代码,但它仍然帮助我看到了你的底层设计问题。

以上是关于图中的角点和边缘检测的主要内容,如果未能解决你的问题,请参考以下文章

图像角点检测

特征提取算法——Harris角点提取

特征匹配-Harris角点检测

Harris角点检测学习

学习日记_Harris特征点检测器-兴趣点检测

模式识别与图像处理课程实验一:图像处理实验(颜色算子实验SusanHarris角点检测实验 sobel边缘算子检测实验)