【问题标题】:How I can detect a set of dots is either rhombic or square lattice我如何检测一组点是菱形或方格
【发布时间】:2014-02-03 00:31:37
【问题描述】:

假设我有包含点的 2D 图像,并且我可以大致检测点的每个中心点,我如何检测它是方格(方格)还是菱形(旋转 45 度)?

幸运的是,我的图像是规则的,没有变形。菱形的情况实际上类似于正方形,但它只旋转了 45 度。唯一的问题是:

  1. 我可以使用霍夫变换检测圆,但中心点当然是近似的。
  2. 这些点不一定会填满整个图像(见下图)

我一直在考虑类似于 OpenCV 中的棋盘图案校准(但当然没有相机参数),

【问题讨论】:

    标签: algorithm opencv textures computer-vision


    【解决方案1】:

    一种方法可能如下:

    1. 使用霍夫变换检测圆,但中心点当然是近似的;

    2. 选择任意数量的点进行测试。点数取决于您必须有多准确/处理图像需要多快。需要多点来实施投票以减少错误的影响。您可以使用任何方法来选择点 - 完全随机或半随机(在图像上具有特定点分布的随机);

    3. 要检测所选每个点的网格方向,请执行最近邻搜索并找到 4 个最近邻。这些邻居将位于通过特定点的网格线的边缘。根据数据集的大小,您可以使用两个 for 循环自己找到邻居,或者您可以使用 FLANN 库(用于近似最近邻居的快速库)中的 OpenCV knnSearch 方法;

    4. 当每个点有 4 个最近邻时,您需要确定指定点的晶格方向。为此,您需要计算每个采样点与其相邻点之间的垂直和水平距离。如果格子是平方的,那么 Min(deltaX, deltaY) 应该接近 0。如果它是菱形的,那么它将是每两点之间距离的一半左右。处理所有的邻居并在这一点上决定它是正方形还是菱形。对每个测试点执行此操作并收集结果;

    5. 根据每个测试点的投票处理结果并最终决定晶格方向。

    【讨论】:

    • 整洁,一定会尝试你的方法
    • 我也会推荐最近邻的方法!
    • 将此标记为答案,@Harris 的方法很好,但可以扩展以检测任何方向,0、15、30、45,...度
    【解决方案2】:

    我的方法有点简单,通过考虑前两行,如果两个点的质心位于同一垂直线上,则为正方形,否则为菱形。在这里您需要执行以下步骤。

    • 在图片中找到contours
    • 使用moments 查找每个轮廓的质心。
    • 现在您需要按照从左上到右下的顺序对质心进行排序。
    • 仅取前两行并检查第一行到第二行中的每个质心,因为它的 x 坐标相等,即检查这些行中的任何两个点是否位于同一垂直线上,如果是,则为正方形,否则为菱形.

    您也可以参考下面的 C++ 代码。

    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <algorithm>
    
    using namespace cv;
    using namespace std;
    int tolerance=3; /// You can varies this to change the result as the centroid may varies in little even if it's lies in same vertical line
    
    ///For sorting x,y co-ordinates from top left corner to bottom rgiht corner
    struct sort_xy {
        bool operator() (cv::Point pt1, cv::Point pt2) {
             if((pt2.y-tolerance<=pt1.y)&&(pt1.y<=pt2.y+tolerance))  return (pt1.x < pt2.x); ///if y values are equal sort x
            else return (pt1.y < pt2.y); /// else sort y
            }
    } compare_xy;
    
    
    
    int main(){
    
    Mat tmp,thr;
    Mat src=imread("1.png",1);
    
    cvtColor(src,tmp,CV_BGR2GRAY);
    threshold(tmp,thr,10,255,THRESH_BINARY_INV);
    imshow("thr,",thr);
    
        ///Find  contours
        vector< vector <Point> > contours; // Vector for storing contour
        vector< Vec4i > hierarchy;
        int largest_contour_index=0;
        int largest_area=0;
        Mat dst(src.rows,src.cols,CV_8UC3,Scalar::all(0)); //create destination image
        findContours( thr, contours, hierarchy,CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE ); // Find the contours in the image
    
        /// Get the moments and mass centers:
        vector<Moments> _moment(contours.size() );
        vector<Point> centroid( contours.size() );
        for( int i = 0; i < contours.size(); i++ ) {
        _moment[i] = moments( contours[i], false );
        centroid[i] = Point( _moment[i].m10/_moment[i].m00 ,_moment[i].m01/_moment[i].m00 );
        }
    
        /// Sort centroid of each contour from top left to bottom right
        sort(centroid.begin(), centroid.end(), compare_xy);
    
        ///Draw  all sorted centroid to dst image
        for( int i = 0; i <centroid.size(); i++ ) {
          circle(dst, centroid[i], 3,Scalar(0,255,0),1,CV_AA, 0);
          imshow("dst",dst);
        }
    
        /// Store first two rows of centroid to a vector
        vector< vector <Point> > rows(2);
        int j=0;
        for( int i = 0; i < centroid.size(); i++ ) {
        if((centroid[i+1].y-tolerance<=centroid[i].y)&&(centroid[i].y<=centroid[i+1].y+tolerance))
         rows[j].push_back(centroid[i]);
        else j++;
        if(j>1) i = centroid.size();
        }
    
    
        /// This block will decide whether the image is Squre or Rhombic.
        /// The loop checks whether any x-coordinates centroid in first row is equal to
        /// x-coordinates centroid in second row, if so it is squre otherwise Rhombic.
        /// That is it simply checks whether two centroid lies in same vertical line.
    
        int cnt=0;
        if(rows[0].size()>rows[1].size()) cnt=rows[1].size();
        else cnt=rows[0].size();
        int squre=0;
        for( int i = 0; i <cnt; i++ ){
         for( int j = 0; j <cnt; j++ ){
         if((rows[1][j].x-tolerance<=rows[0][i].x)&&(rows[0][i].x<=rows[1][j].x+tolerance))
          squre++;
         }
        }
    
        /// Show the result
        if(squre > 0)  putText(dst,"Squre", Point(50,50), FONT_HERSHEY_SIMPLEX,1, Scalar (0,0,255), 3, 8,false );
        else  putText(dst,"Rhombic ", Point(50,50), FONT_HERSHEY_SIMPLEX,1, Scalar (0,0,255), 3, 8,false );
        imshow("src,",src);
        imshow("dst",dst);
        waitKey();
        return 0;
    }
    

    这里我为你的图片找到了一些结果

    图片 1

    图片 2

    图 3

    【讨论】:

      【解决方案3】:

      对沿 y 方向的所有像素求和。你会得到一个一维信号,其中有一堆在某个时期重复出现的峰值。取其中一个峰的 x 坐标,在该 x 坐标处沿 y 方向沿图像行进,直到找到检测到的点。记住当前的 y 坐标。现在查看与一维信号中相邻峰值相对应的 x 坐标,以及您刚刚记住的 y 坐标。您在这里有检测到的点吗?如果是,它是一个方形格子。如果不是,那就是菱形格子。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-03-22
        • 2016-12-06
        • 1970-01-01
        • 2019-08-19
        • 2015-11-08
        • 1970-01-01
        • 2017-07-01
        相关资源
        最近更新 更多