如何检测一组点是菱形或方形点阵

时间:2014-02-03 00:31:38

标签: algorithm opencv textures computer-vision

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

enter image description here

幸运的是我的图像是规则的而且没有变形。菱形表壳实际上与方形相似,但它只旋转了45度。唯一的问题是:

  1. 我可以使用霍夫变换检测圆圈,但当然中心点是近似值。
  2. 这些点不一定会填满整个图像(见下图) enter image description here
  3. 我一直在想类似于OpenCV中的棋盘图案校准(但当然没有相机参数),

3 个答案:

答案 0 :(得分:3)

一种方法可能是:

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

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

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

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

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

答案 1 :(得分:1)

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

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

您也可以参考下面的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

enter image description here enter image description here

  

图片2

enter image description here enter image description here

  

图3

enter image description here enter image description here

答案 2 :(得分:1)

沿y方向对所有像素求和。你会得到一个一维信号,在一段时间内有一堆重复的峰值。取其中一个峰的x坐标,沿着x坐标沿y方向沿图像移动,直到找到检测到的点。记住当前的y坐标。现在看一下对应于1-D信号中相邻峰值的x坐标,以及刚刚记住的y坐标。你有一个检测点吗?如果是的话,这是一个正方形。如果没有,那就是一个菱形的拉丁文。