허프 라인 변환이란?
이미지 속 직선을 검출하고 싶다면 허프 라인 변환(Hough Line Transform)을 활용할 수 있습니다. OpenCV에서는 두 가지 종류의 허프 라인 변환을 제공합니다. 바로 표준 허프 라인 변환(Standard Hough Line Transform)과 확률적 허프 라인 변환(Probabilistic Hough Line Transform)입니다.
1. 표준 허프 라인 변환 — HoughLines()
표준 허프 라인 변환은 Imgproc 클래스의 HoughLines() 메서드를 통해 적용할 수 있습니다. 이 메서드는 다음과 같은 매개변수를 받습니다.
원본 이미지와, 검출된 선들의 파라미터(r, Φ)를 저장할 벡터를 나타내는 두 개의 Mat 객체
r(픽셀 단위)과 Φ(라디안 단위) 파라미터의 해상도를 나타내는 두 개의 double 변수
하나의 선으로 인정하기 위해 필요한 최소 교차점 수를 나타내는 정수값
2. 확률적 허프 라인 변환 — HoughLinesP()
확률적 허프 라인 변환은 Imgproc 클래스의 HoughLinesP() 메서드를 사용합니다(매개변수는 동일). 이 방식은 이미지의 모든 점이 아닌 일부 무작위 점만 분석하기 때문에 연산 속도가 빠르고, 검출된 선분의 시작점과 끝점 좌표를 직접 얻을 수 있다는 장점이 있습니다.
Canny 엣지 검출 — Canny()
허프 변환을 적용하기 전에는 대체로 엣지(윤곽선) 검출이 선행되어야 합니다. Imgproc 클래스의 Canny() 메서드를 사용하면 이미지의 엣지를 검출할 수 있으며, 이 메서드는 다음 매개변수를 받습니다.
원본 이미지와 결과 이미지를 나타내는 두 개의 Mat 객체
임계값(threshold) 두 개를 저장하는 double 변수
Canny 엣지 검출 수행 절차
Imgcodecs 클래스의 imread() 메서드로 원본 이미지를 불러옵니다.
Imgproc 클래스의 cvtColor() 메서드로 그레이스케일 이미지로 변환합니다.
Imgproc 클래스의 blur() 메서드에 커널 값 3을 지정하여 노이즈를 줄입니다.
블러 처리된 이미지에 Imgproc의 canny() 메서드로 엣지 검출 알고리즘을 적용합니다.
모든 값이 0인 빈 행렬을 생성합니다.
Mat 클래스의 copyTo() 메서드로 검출된 엣지를 해당 행렬에 복사합니다.
예제 코드
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
public class HoughLineTransform extends Application {
public void start(Stage stage) throws IOException {
//OpenCV 코어 라이브러리 로드
System.loadLibrary( Core.NATIVE_LIBRARY_NAME );
String file ="D:\\Images\\road4.jpg";
Mat src = Imgcodecs.imread(file);
//이미지를 그레이스케일로 변환
Mat gray = new Mat();
Imgproc.cvtColor(src, gray, Imgproc.COLOR_RGBA2GRAY);
//엣지 검출
Mat edges = new Mat();
Imgproc.Canny(gray, edges, 60, 60*3, 3, false);
//Canny 결과의 색상 변경
Mat cannyColor = new Mat();
Imgproc.cvtColor(edges, cannyColor, Imgproc.COLOR_GRAY2BGR);
//(canny 결과에서) 허프 라인 검출
Mat lines = new Mat();
Imgproc.HoughLines(edges, lines, 1, Math.PI/180, 150);
for (int i = 0; i < lines.rows(); i++) {
double[] data = lines.get(i, 0);
double rho = data[0];
double theta = data[1];
double a = Math.cos(theta);
double b = Math.sin(theta);
double x0 = a*rho;
double y0 = b*rho;
//이미지 위에 선 그리기
Point pt1 = new Point();
Point pt2 = new Point();
pt1.x = Math.round(x0 + 1000*(-b));
pt1.y = Math.round(y0 + 1000*(a));
pt2.x = Math.round(x0 - 1000*(-b));
pt2.y = Math.round(y0 - 1000 *(a));
Imgproc.line(cannyColor, pt1, pt2, new Scalar(0, 0, 255), 3);
}
//행렬을 JavaFX writable 이미지로 변환
Image img = HighGui.toBufferedImage(cannyColor);
WritableImage writableImage= SwingFXUtils.toFXImage((BufferedImage) img, null);
//이미지 뷰 설정
ImageView imageView = new ImageView(writableImage);
imageView.setX(10);
imageView.setY(10);
imageView.setFitWidth(575);
imageView.setPreserveRatio(true);
//Scene 객체 설정
Group root = new Group(imageView);
Scene scene = new Scene(root, 595, 400);
stage.setTitle("Hough Line Transform");
stage.setScene(scene);
stage.show();
}
public static void main(String args[]) {
launch(args);
}
}
입력 이미지

실행 결과
위 코드를 실행하면 다음과 같은 출력 결과를 확인할 수 있습니다.
