如何在打开的简历中找到激光十字中心 [英] How to find laser cross center with open cv

查看:89
本文介绍了如何在打开的简历中找到激光十字中心的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

From camera with open cv I can get a red cross (see picture below) , I do not know best method to calculate cross center coordinates (x,y)? We can assume that laser is red.

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

Probably I will have to use some kind of object recognition. But I need to calculate it's center and perfomance is important.

任何人都可以帮忙吗?

Anyone can help ?

我已经找到了如何通过搜索图片中最多的红色像素来找到激光指示器(红点坐标)的方法,但是在这种情况下,中心并不总是最红色(整条线是红色的,有时cv计算出它比中心的红色更多) ).

I have founded how to find laser pointer (red dot coordinates) by searching most red pixel in the picture but at this case center is not always most red (whole line is red and sometimes cv calculates that it is more red than center).

推荐答案

这是我使用goodFeaturesToTrack函数的方法:

Here is how I did it using the goodFeaturesToTrack function:

#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;
}

这将导致以下输出:

This results in the following output:

您还可以查看使用

You could also look at using cornerSubPix to improve the answer accuracy.

我对实现vasile的答案感到很好奇,所以我坐下来尝试了一下.这看起来工作得很好!这是他所描述的我的实现.对于细分,我决定使用Otsu方法进行自动阈值选择.只要您在激光十字和背景之间保持较高的间隔,此方法就可以很好地工作,否则,您可能需要切换到像Canny这样的边缘检测器.我确实需要处理垂直线的一些角度模糊性(即0度和180度),但是代码似乎可以正常工作(可能有更好的方式处理角度模糊性).

EDIT : I was curious about implementing vasile's answer, so I sat down and tried it out. This looks to work quite well! Here is my implementation of what he described. For segmentation, I decided to use the Otsu method for automatic threshold selection. This will work well as long as you have high separation between the laser cross and the background, otherwise you might want to switch to an edge-detector like Canny. I did have to deal with some angle ambiguities for the vertical lines (i.e., 0 and 180 degrees), but the code seems to work (there may be a better way of dealing with the angle ambiguities).

无论如何,这是代码:

#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;
}

希望有帮助!

这篇关于如何在打开的简历中找到激光十字中心的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆