ブログ

OpenCVで2つの直線の交点を検出

at_nakai
2014年6月13日 13時47分

OpenCVで2つの直線の交点を検出するソースコードを作ったのでシェアします。

このソースコードの動作確認は、ATDE5にUSBカメラを接続して行なっています。 アルゴリズムの検証用途だったため、Armadilloでは動作確認していませんのでご注意ください。

下図は動作確認時のキャプチャです。

Makefile

CROSS_COMPILE ?= arm-linux-gnueabihf-

CC = $(CROSS_COMPILE)cc
CXX = $(CROSS_COMPILE)g++

CFLAGS = -Wall -O2
CXXFLAGS = -Wall -O2

EXEC = vertex
OBJS = vertex.o
LDLIBS := -lopencv_core -lopencv_highgui -lopencv_imgproc -lm

all: $(EXEC)

$(EXEC): $(OBJS)
    $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)

romfs:
    $(ROMFSINST) /usr/bin/$(EXEC)

clean:
    rm -f $(OBJS) $(EXEC)

vertex.cpp

// The "Vertex Detector" program.

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <iostream>
#include <math.h>
#include <string.h>

using namespace cv;
using namespace std;

const char* wndname = "Vertex Detection Demo";

// helper function:
// finds a cosine of angle between vectors
// from pt0->pt1 and from pt0->pt2
double angle_cos( Point pt1, Point pt2, Point pt0 )
{
    double dx1 = pt1.x - pt0.x;
    double dy1 = pt1.y - pt0.y;
    double dx2 = pt2.x - pt0.x;
    double dy2 = pt2.y - pt0.y;

    if (pt0 == pt1 || pt0 == pt2)
        return 1.0;

    return fabs(dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}

int main(int argc, char *argv[])
{
    namedWindow( wndname, 1 );
    vector<vector<Point> > squares;
    const string source = "/dev/video0";
    VideoCapture inputVideo(CV_CAP_V4L2);

    if (!inputVideo.isOpened())
    {
        cout  << "Could not open the input video: " << source << endl;
        return -1;
    }

    Mat srcimg, dstimg, workimg;
    for(;;)
    {
        inputVideo >> srcimg;
        if (srcimg.empty()) break;

        dstimg = srcimg.clone();
        cvtColor(srcimg, workimg, CV_BGR2GRAY);
        Canny(workimg, workimg, 50, 200, 3, true);

        vector<Vec4i> lines;
        HoughLinesP( workimg, lines, 1, CV_PI/180, 80, 30, 10 );

        if (lines.size() >= 2)
            for( size_t i = 1; i < lines.size(); i++ )
            {
#define P1X lines[i - 1][0]
#define P1Y lines[i - 1][1]
#define P3X lines[i - 1][2]
#define P3Y lines[i - 1][3]
#define P2X lines[i - 0][0]
#define P2Y lines[i - 0][1]
#define P4X lines[i - 0][2]
#define P4Y lines[i - 0][3]

                double s1, s2;
                s1 = ((P4X - P2X) * (P1Y - P2Y) - (P4Y - P2Y) * (P1X - P2X))/2;
                s2 = ((P4X - P2X) * (P2Y - P3Y) - (P4Y - P2Y) * (P2X - P3X))/2;

                Point v;
                v.x = P1X + (P3X - P1X) * s1 / (s1 + s2);
                v.y = P1Y + (P3Y - P1Y) * s1 / (s1 + s2);

                if (v.x < 0 || v.y < 0)
                    continue;

                Point p1, p2;
                p1.x = P1X;
                p1.y = P1Y;
                p2.x = P2X;
                p2.y = P2Y;

                double cosine = angle_cos(p1, p2, v);
                if (cosine > 0.3)
                    continue;

                line( dstimg, Point(lines[i - 1][0], lines[i - 1][1]),
                      Point(lines[i - 1][2], lines[i - 1][3]), Scalar(255,0,0), 3, 8 );
                line( dstimg, Point(lines[i][0], lines[i][1]),
                      Point(lines[i][2], lines[i][3]), Scalar(0,0,255), 3, 8 );

                cout << "(" << v.x << ", " << v.y << "), " << cosine << endl;
                cv::circle(dstimg, v, 10, Scalar(0, 255, 0), 3, 8);
            }

        imshow(wndname, dstimg);
        cvWaitKey(10);
    }

    return 0;
}