2D形状识别算法 - 寻找指导

时间:2014-08-05 20:55:13

标签: image-processing image-recognition shape-recognition marvin-framework

我需要能够验证用户是否正确绘制了形状,从简单的形状开始,如圆形,三角形和更高级的形状,如字母A.

我需要能够实时计算正确性,例如,如果用户应绘制一个圆形但是绘制一个矩形,我希望能够在绘图时检测到它。

有几种不同的形状识别方法,遗憾的是我没有经验或时间来尝试它们,看看哪些方法有效。

您会为此特定任务推荐哪种方法?

感谢您的帮助。

3 个答案:

答案 0 :(得分:8)

我们可以定义"识别"作为检测元素中的特征/特征并将其与我们的经验中看到的已知元素的特征进行比较的能力。具有相似特征的对象可能是类似的对象。特征的数量和复杂程度越高,我们区分类似对象的能力就越大。

在形状的情况下,我们可以使用它们的几何属性,例如角度数,角度值,边数,边尺寸等。因此,为了完成您的任务,您应该使用图像处理算法从图纸中提取这些特征。

下面我将介绍一种在实践中表明这一概念的非常简单的方法。我们将使用角数来识别不同的形状。正如我所说:"功能的数量和复杂程度越高,我们辨别类似对象的能力就越大。由于我们只使用一个特征,角落的数量,我们可以区分几种不同的形状。具有相同角数的形状将不会被区分。因此,为了改进方法,您可以添加新功能。

<小时/> 的更新:

为了实时完成此任务,您可以实时提取这些功能。如果要绘制的对象是三角形并且用户正在绘制任何其他图形的第四面,则您知道他或她没有绘制三角形。关于正确性级别,您可以计算所需对象的特征向量与绘制对象的特征向量之间的距离。


<强>输入:

enter image description here

算法

  1. 缩小输入图像,因为可以在较低分辨率下检测到所需的特征。
  2. 将每个要独立处理的对象分段。
  3. 对于每个对象,提取其功能,在这种情况下,只提取角数。
  4. 使用这些功能,对对象形状进行分类。
  5. 软件:

    下面介绍的软件是用Java开发的,并使用Marvin Image Processing Framework。但是,您可以使用任何编程语言和工具。

    import static marvin.MarvinPluginCollection.floodfillSegmentation;
    import static marvin.MarvinPluginCollection.moravec;
    import static marvin.MarvinPluginCollection.scale;
    
    public class ShapesExample {
    
        public ShapesExample(){
            // Scale down the image since the desired features can be extracted
            // in a lower resolution.
            MarvinImage image = MarvinImageIO.loadImage("./res/shapes.png");
            scale(image.clone(), image, 269);
    
            // segment each object
            MarvinSegment[] objs = floodfillSegmentation(image);
            MarvinSegment seg;
    
            // For each object...
            // Skip position 0 which is just the background
            for(int i=1; i<objs.length; i++){
                seg = objs[i];
                MarvinImage imgSeg = image.subimage(seg.x1-5, seg.y1-5, seg.width+10, seg.height+10);
                MarvinAttributes output = new MarvinAttributes();
                output = moravec(imgSeg, null, 18, 1000000);
                System.out.println("figure "+(i-1)+":" + getShapeName(getNumberOfCorners(output)));
            }
        }
    
        public String getShapeName(int corners){
            switch(corners){
                case 3: return "Triangle";
                case 4: return "Rectangle";
                case 5: return "Pentagon";
            }
            return null;
        }
    
        private static int getNumberOfCorners(MarvinAttributes attr){
            int[][] cornernessMap = (int[][]) attr.get("cornernessMap");
            int corners=0;
            List<Point> points = new ArrayList<Point>();
            for(int x=0; x<cornernessMap.length; x++){
                for(int y=0; y<cornernessMap[0].length; y++){
                    // Is it a corner?
                    if(cornernessMap[x][y] > 0){
                        // This part of the algorithm avoid inexistent corners
                        // detected almost in the same position due to noise.
                        Point newPoint = new Point(x,y);
                        if(points.size() == 0){
                            points.add(newPoint); corners++;
                        }else {
                            boolean valid=true;
                            for(Point p:points){
                                if(newPoint.distance(p) < 10){
                                    valid=false;
                                }
                            }
                            if(valid){
                                points.add(newPoint); corners++;
                            }
                        }
                    }
                }
            }
            return corners;
        }
    
        public static void main(String[] args) {
            new ShapesExample();
        }
    }
    

    软件输出:

    figure 0:Rectangle
    figure 1:Triangle
    figure 2:Pentagon
    

答案 1 :(得分:0)

你有两个输入 - 初始图像和用户输入 - 你正在寻找一个布尔结果。

理想情况下,您可以将所有输入数据转换为可比较的格式。相反,您也可以参数化两种类型的输入并使用supervised machine learning算法(关闭形状会想到最近邻)。

诀窍是寻找合适的参数。如果您的输入是平面图像文件,则可以是二进制转换。如果用户输入是滑动动作或笔划,我确信有一些方法可以捕获并将其映射为二进制,但如果使用最接近原始输入的数据,算法可能会更加稳健。

答案 2 :(得分:0)

另一种方法是你可以使用数学来解决这个问题,使用每个点的平均值,与你比较它的距离最小, 首先,您必须使用形状库中的形状调整形状,然后:

      function shortestDistanceSum( subject, test_subject ) {

         var sum = 0;

         operate( subject, function( shape ){

            var smallest_distance = 9999;

            operate( test_subject, function( test_shape ){
                var distance = dist( shape.x, shape.y, test_shape.x, test_shape.y );

                smallest_distance = Math.min( smallest_distance, distance );
            });

            sum += smallest_distance;

        });

            var average = sum/subject.length;

            return average;
       }

       function operate( array, callback ) {
          $.each(array, function(){
              callback( this );
          });
       }

       function dist( x, y, x1, y1 ) {
            return Math.sqrt( Math.pow( x1 - x, 2) + Math.pow( y1 - y, 2) );
        }

        var square_shape = Array; // collection of vertices in a square shape
        var triangle_shape = Array; // collection of vertices in a triangle
        var unknown_shape = Array; // collection of vertices in the shape your'e comparing from

        square_sum = shortestDistanceSum( square_shape, unknown_shape );
        triangle_sum = shortestDistanceSum( triangle_shape, unknown_shape );

最低总和是最接近的形状。