0
1

More than 1 year has passed since last update.

【Java初心者】OpenCVで輪郭抽出

Posted at

Javaアプリにも画像処理させたい

専門的な知識を学んだわけでもないので、ネット情報や書籍を参考にJavaアプリを作っているが、「AIだよ」って言えるようなものにも挑戦したくなった。

ネットなどで公開されている画像処理のサンプルの多くがPythonなので、せっかくだから自分が(比較的)得意とするJavaでやったらどうなるかと思って試した。

参考にしたサイト

大変参考になる記事を公開してくださり、ありがとうございました。

作ってみた

用意したサンプル画像

input.png

必要なライブラリーなど

  • openCV(Linuxならば普通にインストール。Windowsの場合はdll一枚をパスの通ったところに。自分は JAVA_HOME/bin の中に入れた)
  • OpenCVにアクセスするためのjar(OpenCVインストールすると入っている。今回はopencv-470.jarをプロジェクトに追加)

処理するためのコード

package opencvtest;

import java.util.ArrayList;
import java.util.List;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class Main {

    public static void main(String[] args) {
        // OpenCV ライブラリーをよむ
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        // 画像ファイルを読む(フルカラー)
        Mat img = Imgcodecs.imread("input.png");
        // グレースケールのMatにする
        Mat imgG = new Mat();
        Imgproc.cvtColor(img, imgG, Imgproc.COLOR_BGR2GRAY);
        // ガウジアンフィルターをかけて平滑化する
        // ぼかしがかかることで輪郭抽出しやすくなる
        Mat imgB = new Mat();
        Imgproc.GaussianBlur(imgG, imgB, new Size(5, 5), 5.0);
        // 輪郭抽出のための閾値処理
        Mat imgA = new Mat();
        Imgproc.adaptiveThreshold(imgB, imgA, 255, 1, 1, 11, 2);
        // 輪郭抽出
        Mat imgR = new Mat();
        List contour = new ArrayList();
        Imgproc.findContours(imgA,
                contour,
                imgR,
                Imgproc.RETR_LIST,
                Imgproc.CHAIN_APPROX_SIMPLE);

        // 輪郭の一つずつを処理
        // このforプロックは関数化できるが
        // わかりやすくするためこのままにした
        for (Object object : contour) {
            Rect boundingRect = Imgproc.boundingRect((Mat) object);
            int x = boundingRect.x;
            int y = boundingRect.y;
            int w = boundingRect.width;
            int h = boundingRect.height;
            // 上記変数の条件設定によって、
            // 画像の特定の場所だけ抽出することなどができる
            // 高さが40を超えるものだけ処理(適当)
            if (40 < h) {
                Point point1 = new Point(x, y);
                Point point2 = new Point(x + w, y + h);
                Scalar color = new Scalar(0, 0, 255); // 赤
                int thickness = 2; // 太さ
                // 最初のMat(フルカラー)に矩形を上書き
                Imgproc.rectangle(img, point1, point2, color, thickness);
            }
        }
        // できあがったMatを画像に書き出す
        Imgcodecs.imwrite("output.jpg", img);

    }
}


処理後の画像

output.jpg

確かに輪郭は抽出できました。ただ、これで「文字」を抽出したいとする場合、「う」のように一部が切り取られてしまうと、目的とする処理ができなくなるかもしれません。

これよりも大きなサイズの枠にするよう設定すると、アルファベットの小文字が抽出されなくなります。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1