본문 바로가기
Open CV

opencv c++ Hough 라인 변환

by 빈이쥬 2023. 1. 17.

Hought 라인 변환은 이미지에서 직선을 감지하는 데 사용되는 이미지 처리 기술이다

 

이미지를 Hough 공간 표현으로 변환한다.

이미지의 각 지점은 Hough 공간에서 정현 곡선으로 표시된다.

정현곡선
3각 함수의 정현 (sine)과 각도와의 관계를 나타내는 파형(波形)의 곡선을 가리킨다.

Hough 공간에서 이러한 곡선의 교차점은 이미지의 직선 위치에 해당한다

허프 라인 변환은 기존의 에지 감지 방법이 실패할 수 있는 노이즈가 있거나 복잡한 이미지에서 라인을 감지하는 데 특히 유용하다

Hough 라인 변환은 두 단계로 작동한다.

  1. 에지 감지: 이미지는 먼저 Canny 에지 감지와 같은 에지 감지 기술을 사용하여 이진 이미지로 변환된다. 이렇게 하면 원본 이미지의 가장자리에 해당하는 픽셀이 1로 설정되고 나머지는 0으로 설정된 이진 이미지가 생성된다
  2. Hough 변환:  이진 이미지에서 가장자리의 (x,y) 좌표를 Hough 공간의 (rho, theta) 좌표로 변환합니다. Rho는 원점에서 선까지의 거리를 나타내고 세타는 선과 x축의 각도를 나타냅니다.

적용하는 함수는 다음과 같다,

1. 에지 감지

 

Canny(src, edges, threshold1, threshold2, apertureSize, L2gradient)

 

  • src – 8비트 입력이미지
  • edges – src와 동일한 크기 및 유형의 출력 이미지.
  • threshold1 - 첫번째 임계값
  • threshold2 – 두번째 임계값
  • apertureSize - 조리개의 크기
  • L2gradient - True이면 그레디언트 크기를 계산할 때 sqrt{(dI/dx)^2 + (dI/dy)^2}를 사용한다. False라면 근사값인 |dI/dx|+|dI/dy|를 사용함.  디폴트값은 False.

2.Hough 변환

 

HoughLines(src, lines, rho, theta, threshold, srn, stn, min_theta, max_theta)

 

  • src – 8비트, 단일 채널 이진 입력이미지
  • lines – 라인 출력 벡터
  • rho - 거리 해상도(픽셀 단위 0~1 실수)
  • theta –  각도 분해능 𝜃 (라디안 단위 0~180)
  • threshold - 임계값 만나는 점의 기준 숫자가 작으면 많은 선이 검출되지만 정확성이 떨어짐 
  • srn - 다중 스케일 허프 변환의  거리해상도. 선 검출에서는 사용하지 않으며 디폴트는 0이다.
  • stn - 다중 스케일 허프 변환의 각도 분해능. 선 검출에서는 사용하지 않으며 디폴트는 0이다.
  • min_theta - 표준 및 다중 스케일 Hough 변환의 최소 각도이다. (0과 max_theta 사이)
  • max_theta -  표준 및 다중 스케일 Hough 변환의 최대 각도이다. (min_theta와 CV_PI 사이) 

 

3. line() - 이미지에 선을 그림

 

line(src, pt1, pt2, color, thick, It, shift)

 

 

소스코드

1. cvtColor() 함수를 사용하여 회색조로 변환한다.

2. Canny() 함수를 사용하여 Canny 에지 감지를 수행한다.

3. HoughLines( ) 함수를 사용하여 HoughLines( ) Hough 변환을 수행한다.

 

#include <opencv2/opencv.hpp>
#include <iostream>
#include <opencv2/imgproc.hpp>

using namespace cv;
using namespace std;

int main(int argc, char* argv[])
{
    
    string url = "http://192.168.0.123";
    
    // Open the default camera
    VideoCapture cap(url);

    // Check if the camera is opened
    if(!cap.isOpened())
    {
        cout << "Error opening camera" << endl;
        return -1;
    }
 
    // Capture frames from the camera in a loop
    while(true)
    {
        // Capture a frame
        Mat frame;
        cap >> frame;
        
        // Check if the frame is empty
        if(frame.empty())
        {
            cout << "Empty frame" << endl;
           break;
        }
//      Convert the image to grayscale
        Mat gray;
        cvtColor(frame,gray,COLOR_RGB2GRAY);
        imshow("gray", gray);

//        Canny edge detection
        Mat edges;
        Canny(gray, edges, 100, 100);
        imshow("edges", edges);
        
//        Hough line transformation
        vector<Vec2f> lines;
        HoughLines(edges, lines, 1, CV_PI/180, 80);
        
        Mat result = frame.clone();
            for(size_t i = 0; i < lines.size(); i++) {
                float rho = lines[i][0], theta = lines[i][1];
                Point pt1, pt2;
                double a = cos(theta), b = sin(theta);
                double x0 = a*rho, y0 = b*rho;
                pt1.x = cvRound(x0 + 1000*(-b));
                pt1.y = cvRound(y0 + 1000*(a));
                pt2.x = cvRound(x0 - 1000*(-b));
                pt2.y = cvRound(y0 - 1000*(a));
                line(result, pt1, pt2, Scalar(255,255,255), 2);
            }
        imshow("Hough Lines", result);
        // Press 'q' to exit the loop
        if(waitKey(1) == 'q')
        {
            break;
        }
    }

    // Release the camera
    cap.release();

    return 0;
}

 

소스코드 리뷰

Canny(): 이 함수는 이미지에서 Canny 에지 감지를 수행한다.

첫 번째 인수는 입력 이미지,

두 번째 인수는 출력 이미지,

세 번째 및 네 번째 인수는 각각 가장자리의 하한 및 상한 임계값이다.

Mat edges;
Canny(gray, edges, 100, 100);

 

HoughLines(): Hough 라인 변환을 수행한다.

첫 번째 인수는 입력 이미지,

두 번째 인수는 라인의 출력 벡터,

세 번째 인수는 거리 해상도(픽셀),

네 번째 인수는 각도 해상도(라디안),

다섯 번째 인수는 라인의 임계값이며, 숫자가 작을수록 선을 만많이 검출됨

vector<Vec2f> :  부동 좌표가 있는 2D 벡터 모음을 저장하는 변수이다.

vector<Vec2f> lines;
HoughLines(edges, lines, 1, CV_PI/180, 80);

 

 

line(): 이미지에 선을 그린다.

첫 번째 인수는 입력 이미지,

두 번째 및 세 번째 인수는 각각 선의 시작점과 끝점,

네 번째 인수는 선의 색상,

다섯 번째 인수는 선의 두께이다. 색상 - 255, 255, 255(흰색) 선의 두께 - 2

Mat result = frame.clone(); //frame data copy
	for(size_t i = 0; i < lines.size(); i++) {
    	float rho = lines[i][0], theta = lines[i][1];
        Point pt1, pt2;
        double a = cos(theta), b = sin(theta);
        double x0 = a*rho, y0 = b*rho;
        pt1.x = cvRound(x0 + 1000*(-b));
        pt1.y = cvRound(y0 + 1000*(a));
        pt2.x = cvRound(x0 - 1000*(-b));
        pt2.y = cvRound(y0 - 1000*(a));
        line(result, pt1, pt2, Scalar(255,255,255), 2);
    }

 

 

출력