Bacisally的任务是: 实现四轴飞行器的自动着陆/起飞,可以携带一个FlyCam / GoPro摄像头。定向应该相对于在2D平面上的着陆平台的高度和位置(包括旋转)发生。这意味着无人机有一个“头”和“尾巴”,应该落在一个特定的位置。
登陆平台看起来像这样
角落形状用于远距离定向,中心圆圈中的小重复形状用于精确着陆。
你会采取什么方法来解决这个问题?
答案 0 :(得分:2)
这是一个伪代码,假设您已经拥有对电机控制API的完全访问权限;即你已经成功地定义了改变高度,左转等所需的东西。
loop
{
if(landing board detected)
{
if(circle including the center point detected)
{
find orientation from corner circles' center
change device's orientation accordingly
}
else
{
lose altitude & move towards the center point
}
}
else
{
move around
}
}
登陆板&它的中心:
假设:这是最大的&近乎完美的广场。
1-门槛
2-提取轮廓
3-将形状(方形)滤镜应用于轮廓
4-找到最大轮廓
5-找到它的中心
6-使用此轮廓的边界矩形裁剪图像
Mat image = imread("~\\image.jpg");
// scale down for faster processing
pyrDown(image, image);
pyrDown(image, image);
// safe copy
Mat temp = image.clone();
// noise reduction & thresholding
GaussianBlur(image, image, Size(5,5), 3);
cvtColor(image, image, CV_BGR2GRAY);
threshold(image, image, 127, 255, CV_THRESH_OTSU);
// extract all contours
vector<vector<Point> > contours;
findContours(image, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
// define a perfect square
vector<Point> square;
square.push_back(Point(0,0));
square.push_back(Point(0,10));
square.push_back(Point(10,10));
square.push_back(Point(10,0));
// filter out contours that are not square
bool erased;
for(unsigned int i = 0; i<contours.size(); i++)
{
erased = false;
double x = matchShapes(contours[i], square, CV_CONTOURS_MATCH_I2, 0);
if(x > 0.005)
{
contours.erase(contours.begin() + i);
erased = true;
}
if(erased) i--;
}
// area filtering to find the biggest square contour
vector<double> contourAreas(contours.size());
for(unsigned int i = 0; i<contours.size(); i++)
{
contourAreas[i] = contourArea(contours[i]);
}
int ID = max_element(contourAreas.begin(), contourAreas.end()) - contourAreas.begin();
for(unsigned int i = 0; i<contours.size(); i++)
{
erased = false;
if(i != ID)
{
contours.erase(contours.begin() + i);
erased = true;
ID--;
}
if(erased) i--;
}
// find the bounding rect of this contour and crop the image within that rect
vector<Point> total;
for(unsigned int j = 0; j<contours[0].size(); j++)
{
total.push_back(contours[0][j]);
}
Rect rect = boundingRect(total);
Mat t = Mat(temp, rect);
// find the center of the landing board - to move towards it when necessary
Moments m = moments(contours[0], false);
Point center = Point(cvRound(m.m10/m.m00), cvRound(m.m01/m.m00));
现在我们检测到了电路板,我们需要检测转角以进行定位。
1-门槛
2-提取轮廓
3-将形状(圆形)滤镜应用于轮廓
4-过滤掉靠近电路板中心的圆圈
5-生成的圆圈是圆角,找到它们最大的中心
// threshold
Mat gray;
cvtColor(t, gray, CV_BGR2GRAY);
threshold(gray, gray, 2187451321, 12186471, CV_THRESH_OTSU);
// extract contours
vector<vector<Point> > conts;
findContours(gray, conts, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
// circularity check
for(unsigned int i = 0; i<conts.size(); i++)
{
erased = false;
if(4*3.14*contourArea(conts[i]) / ((arcLength(conts[i],true) * arcLength(conts[i],true))) < 0.85)
{
conts.erase(conts.begin() + i);
erased = true;
}
if(erased) i--;
}
// position check - filtering out center circle
vector<Moments> mu(conts.size());
vector<Point2f> mc(conts.size());
for(unsigned int i = 0; i<conts.size(); i++ )
{
mu[i] = moments(conts[i], false);
}
for(unsigned int i = 0; i <conts.size(); i++ )
{
mc[i] = Point2f(mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00);
}
for(unsigned int i=0; i<conts.size(); i++)
{
erased = false;
if((((int)mc[i].x > t.cols/3) && ((int)mc[i].x < 2*t.cols/3) && ((int)mc[i].y < 2*t.rows/3) && ((int)mc[i].y > t.rows/3)))
{
mc.erase(mc.begin() + i);
conts.erase(conts.begin() + i);
erased = true;
}
if(erased) i--;
}
// selecting the biggest circle
vector<double> contAreas(conts.size());
for(unsigned int i = 0; i<conts.size(); i++)
{
contAreas[i] = contourArea(conts[i]);
}
ID = max_element(contAreas.begin(), contAreas.end()) - contAreas.begin();
for(unsigned int i = 0; i<conts.size(); i++)
{
erased = false;
if(i != ID)
{
conts.erase(conts.begin() + i);
erased = true;
ID--;
}
if(erased) i--;
}
drawContours(t, conts, -1, Scalar(0,255,255));
// finding its center - this is nothing but current orientation
Moments m2 = moments(conts[0], false);
Point c = Point(cvRound(m2.m10/m2.m00), cvRound(m2.m01/m2.m00));
输入图片
检测到最大方(Mat t
)
检测到最大 - 不接近中心圆 - 内部最大正方形(conts[0]
)
分别围绕中心和电路板中心进行定位
编辑:董事会中心(center
)是根据image
的位置,而圆心(c
)是根据董事会(t
)的位置。唯一剩下的就是找到穿过板中心和圆心的线的斜率。