ブログ

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