如何找到开放式电视激光十字中心

Aud*_*ius 3 c++ opencv

从打开cv的相机我可以得到一个红十字(见下图),我不知道计算交叉中心坐标(x,y)的最佳方法?我们可以假设激光是红色的.

在此输入图像描述

可能我将不得不使用某种物体识别.但我需要计算它的中心,性能很重要.

有人可以帮忙吗?

我已成立了如何找到的图片,但在这种情况下,中心搜索最红的像素激光指示器(红点坐标)并不总是最红(整条生产线是红色,有时简历计算,它比中心更红).

mev*_*ron 5

以下是我使用该goodFeaturesToTrack函数的方法:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <vector>

using namespace cv;
using namespace std;


int main(int argc, char* argv[])
{
    Mat laserCross = imread("laser_cross.png");

    vector<Mat> laserChannels;
    split(laserCross, laserChannels);

    vector<Point2f> corners;
    // only using the red channel since it contains the interesting bits...
    goodFeaturesToTrack(laserChannels[2], corners, 1, 0.01, 10, Mat(), 3, false, 0.04);

    circle(laserCross, corners[0], 3, Scalar(0, 255, 0), -1, 8, 0);

    imshow("laser red", laserChannels[2]);
    imshow("corner", laserCross);
    waitKey();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这导致以下输出:
在此输入图像描述

您还可以使用cornerSubPix来提高答案的准确性.

编辑:我很好奇实施vasile的答案,所以我坐下来试了一下.这看起来效果很好!这是我对他描述的内容的实现.对于分段,我决定使用Otsu方法进行自动阈值选择.只要激光十字和背景之间有很高的间距,这就可以正常工作,否则你可能想要切换到边缘检测器Canny.我确实必须处理垂直线(即0度和180度)的一些角度模糊度,但代码似乎有效(可能有更好的方法来处理角度模糊).

无论如何,这是代码:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <vector>

using namespace cv;
using namespace std;

Point2f computeIntersect(Vec2f line1, Vec2f line2);
vector<Point2f> lineToPointPair(Vec2f line);
bool acceptLinePair(Vec2f line1, Vec2f line2, float minTheta);

int main(int argc, char* argv[])
{
    Mat laserCross = imread("laser_cross.png");

    vector<Mat> laserChannels;
    split(laserCross, laserChannels);

    namedWindow("otsu", CV_WINDOW_NORMAL);
    namedWindow("intersect", CV_WINDOW_NORMAL);

    Mat otsu;
    threshold(laserChannels[2], otsu, 0.0, 255.0, THRESH_OTSU);
    imshow("otsu", otsu);

    vector<Vec2f> lines;
    HoughLines( otsu, lines, 1, CV_PI/180, 70, 0, 0 );

    // compute the intersection from the lines detected...
    int lineCount = 0;
    Point2f intersect(0, 0);
    for( size_t i = 0; i < lines.size(); i++ )
    {
        for(size_t j = 0; j < lines.size(); j++)
        {
            Vec2f line1 = lines[i];
            Vec2f line2 = lines[j];
            if(acceptLinePair(line1, line2, CV_PI / 4))
            {
                intersect += computeIntersect(line1, line2);
                lineCount++;
            }
        }

    }

    if(lineCount > 0)
    {
        intersect.x /= (float)lineCount; intersect.y /= (float)lineCount;
        Mat laserIntersect = laserCross.clone();
        circle(laserIntersect, intersect, 1, Scalar(0, 255, 0), 3);
        imshow("intersect", laserIntersect);
    }

    waitKey();

    return 0;
}

bool acceptLinePair(Vec2f line1, Vec2f line2, float minTheta)
{
    float theta1 = line1[1], theta2 = line2[1];

    if(theta1 < minTheta)
    {
        theta1 += CV_PI; // dealing with 0 and 180 ambiguities...
    }

    if(theta2 < minTheta)
    {
        theta2 += CV_PI; // dealing with 0 and 180 ambiguities...
    }

    return abs(theta1 - theta2) > minTheta;
}

// the long nasty wikipedia line-intersection equation...bleh...
Point2f computeIntersect(Vec2f line1, Vec2f line2)
{
    vector<Point2f> p1 = lineToPointPair(line1);
    vector<Point2f> p2 = lineToPointPair(line2);

    float denom = (p1[0].x - p1[1].x)*(p2[0].y - p2[1].y) - (p1[0].y - p1[1].y)*(p2[0].x - p2[1].x);
    Point2f intersect(((p1[0].x*p1[1].y - p1[0].y*p1[1].x)*(p2[0].x - p2[1].x) -
                       (p1[0].x - p1[1].x)*(p2[0].x*p2[1].y - p2[0].y*p2[1].x)) / denom,
                      ((p1[0].x*p1[1].y - p1[0].y*p1[1].x)*(p2[0].y - p2[1].y) -
                       (p1[0].y - p1[1].y)*(p2[0].x*p2[1].y - p2[0].y*p2[1].x)) / denom);

    return intersect;
}

vector<Point2f> lineToPointPair(Vec2f line)
{
    vector<Point2f> points;

    float r = line[0], t = line[1];
    double cos_t = cos(t), sin_t = sin(t);
    double x0 = r*cos_t, y0 = r*sin_t;
    double alpha = 1000;

    points.push_back(Point2f(x0 + alpha*(-sin_t), y0 + alpha*cos_t));
    points.push_back(Point2f(x0 - alpha*(-sin_t), y0 - alpha*cos_t));

    return points;
}
Run Code Online (Sandbox Code Playgroud)

希望有所帮助!