假设我有包含点的2D图像,我可以近似检测点的每个中心点,我如何检测它是方格(方格)还是菱格(旋转45度)?
幸运的是我的图像是规则的而且没有变形。菱形表壳实际上与方形相似,但它只旋转了45度。唯一的问题是:
我一直在想类似于OpenCV中的棋盘图案校准(但当然没有相机参数),
答案 0 :(得分:3)
一种方法可能是:
使用霍夫变换检测圆圈,但当然中心点是近似值;
选择要测试的任意数量的点。点数取决于您必须具备的准确度/处理图像所需的速度。需要多个点来实施投票以减少错误的影响。您可以使用任何方法来选择点 - 完全随机或半随机(随机在图像中的某些点分布);
要检测所选择的每个点的网格方向,请执行最近邻搜索并找到4个最近邻居。那些邻居将位于经过特定点的网格线的边缘。根据数据集大小,您可以自己找到两个for
循环的邻居,或者您可以使用FLANN库中的OpenCV knnSearch
方法(近似最近邻居的快速库);
如果每个点有4个最近邻居,则需要确定指定点的晶格方向。为此,您需要计算每个采样点与其邻居之间的垂直和水平距离。如果晶格是平方的,那么Min(deltaX,deltaY)应该接近0.如果它是菱形的,那么它将是每两个点之间距离的大约一半。处理所有邻居并确定此时是格子还是正方形或菱形。为每个测试点执行此操作并收集结果;
根据每个测试点的投票处理结果并对晶格取向做出最终决定。
答案 1 :(得分:1)
我的方法很简单,通过考虑前两行,如果两个点的质心位于同一垂直线上,则为正方形,否则为菱形。在这里,您需要执行以下步骤。
您也可以参考下面的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
答案 2 :(得分:1)
沿y方向对所有像素求和。你会得到一个一维信号,在一段时间内有一堆重复的峰值。取其中一个峰的x坐标,沿着x坐标沿y方向沿图像移动,直到找到检测到的点。记住当前的y坐标。现在看一下对应于1-D信号中相邻峰值的x坐标,以及刚刚记住的y坐标。你有一个检测点吗?如果是的话,这是一个正方形。如果没有,那就是一个菱形的拉丁文。