Java
 Computer >> コンピューター >  >> プログラミング >> Java

JavaでOpenCVのハフ線変換を実装する方法を徹底解説


画像から直線を検出したい場合に活躍するのが、OpenCVが提供するハフ線変換(Hough Line Transform)です。ハフ線変換には主に2種類あり、それぞれ用途に応じて使い分けられます。

  • 標準ハフ線変換(Standard Hough Line Transform)
  • 確率的ハフ線変換(Probabilistic Hough Line Transform)

標準ハフ線変換(HoughLinesメソッド)

標準ハフ線変換は、ImgprocクラスのHoughLines()メソッドを使用して適用できます。このメソッドは以下の引数を受け取ります。

  • 元画像と、検出された直線のパラメータ(r、Φ)を格納するベクトルを表す2つのMatオブジェクト
  • パラメータr(ピクセル単位)およびΦ(ラジアン単位)の解像度を表す2つのdouble型変数
  • 1本の直線として「検出」するために必要な最小交差数を表す整数値

確率的ハフ線変換(HoughLinesPメソッド)

確率的ハフ線変換は、同じくImgprocクラスのHoughLinesP()メソッドを使用します。引数は標準ハフ線変換と共通です。こちらは計算量を抑えつつ、線分(始点と終点を持つ直線)として結果を取得できるのが特徴です。

Cannyエッジ検出による前処理

ハフ線変換を適用する前に、画像のエッジを抽出しておく必要があります。エッジ検出には、ImgprocクラスのCanny()メソッドを使用します。このメソッドは以下の引数を受け取ります。

  • 元画像と出力画像を表す2つのMatオブジェクト
  • しきい値を保持する2つのdouble型変数

実装の流れ

Cannyエッジ検出器を使って画像のエッジを検出し、ハフ線変換で直線を描画するまでの基本的な手順は以下の通りです。

  1. Imgcodecsクラスのimread()メソッドで元画像を読み込む
  2. ImgprocクラスのcvtColor()メソッドでグレースケール画像に変換する
  3. Imgprocクラスのblur()メソッドでカーネルサイズ3を指定して、グレースケール画像にぼかし処理を施す
  4. ぼかした画像に対し、Imgprocクラスのcanny()メソッドでCannyエッジ検出を適用する
  5. すべての値が0の空のマトリックスを作成する
  6. MatクラスのcopyTo()メソッドで、検出されたエッジをそのマトリックスにコピーする

サンプルコード

以下は、道路画像からハフ線変換によって直線(車線など)を検出し、JavaFX上に表示する完全なサンプルコードです。

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のWritableImageに変換
        Image img = HighGui.toBufferedImage(cannyColor);
        WritableImage writableImage= SwingFXUtils.toFXImage((BufferedImage) img, null);
        // ImageViewを設定
        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);
    }
}

入力画像

JavaでOpenCVのハフ線変換を実装する方法を徹底解説

出力結果

上記のコードを実行すると、検出された直線が赤色で描画された以下のような結果が得られます。

JavaでOpenCVのハフ線変換を実装する方法を徹底解説

  1. JavaとOpenCVで線を描画する方法をわかりやすく解説

    Java版OpenCVライブラリのorg.opencv.imgprocパッケージには、Imgprocというクラスが含まれています。画像に直線を描画するには、このクラスが提供するline()メソッドを呼び出します。 line()メソッドのパラメータ line()メソッドは、以下のパラメータを受け取ります。 Matオブジェクト ― 直線を描画する対象となる画像を表します。 Pointオブジェクト2つ ― 直線の始点と終点の座標を表します。 Scalarオブジェクト ― 直線の色をBGR形式で指定します。 整数値 ― 直線の太さを指定します(デフォルト値:1)。 サンプルコード 以下は、白紙の画

  2. JavaとOpenCVライブラリを使って画像内の顔を検出する方法

    JavaでOpenCVを使用して画像から顔を検出するには、CascadeClassifierクラスを利用します。このクラスは、分類器ファイル(カスケードファイル)を読み込み、画像内から目的のオブジェクト(ここでは顔)を検出する役割を担います。 CascadeClassifierクラスとは CascadeClassifierは、OpenCVが提供する物体検出用のクラスです。事前に学習済みのカスケード分類器(XMLファイル)を読み込むことで、顔や人など特定のパターンを画像から認識できます。 detectMultiScale()メソッドについて このクラスが持つdetectMultiScale(