检测着陆平台的位置/角度以驾驶无人机

时间:2014-01-06 13:58:16

标签: opencv image-processing computer-vision

Bacisally的任务是: 实现四轴飞行器的自动着陆/起飞,可以携带一个FlyCam / GoPro摄像头。定向应该相对于在2D平面上的着陆平台的高度和位置(包括旋转)发生。这意味着无人机有一个“头”和“尾巴”,应该落在一个特定的位置。

登陆平台看起来像这样

enter image description here

角落形状用于远距离定向,中心圆圈中的小重复形状用于精确着陆。

你会采取什么方法来解决这个问题?

1 个答案:

答案 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));

输入图片 input image

检测到最大方Mat t

detected biggest-square

检测到最大 - 不接近中心圆 - 内部最大正方形conts[0]detected biggest-not close to center-circle-inside that biggest square

分别围绕中心和电路板中心进行定位 circle center and board center respectively, for orientation purposes

编辑:董事会中心(center)是根据image的位置,而圆心(c)是根据董事会(t)的位置。唯一剩下的就是找到穿过板中心和圆心的线的斜率。