OpenCVとQualkusを用いたJava画像処理


あなたがコンピュータビジョンにいるならば、あなたは多分よく知っていますOpenCV . そのほとんどすべて1つの2 Dおよび3 D処理を行う必要があります驚くほどのライブラリとはるかに.ジェスチャー認識、顔の検出、モーショントラッキング、何かのイメージ処理とOpenCVのに関連するあなたのgotoを考えることができます.そのBSDライセンスに基づいて、あなたはそれをダウンロードすることができますので、それを使用して起動します.
OpenCVはCで書かれていて、それにも素敵なJavaバインディングがあります.あなたが私のようなJava開発者であるならば、そして、dontはすべてのローディングと自然なバインディングなどを構築したいです.この記事では、ライブラリをインストールしたり、アプリケーション全体を再読み込みすることなく心配することなく、人気の新しいフレームワークQualkusでOpenCVを使用する方法を示します.
Quarkus 最初のコンテナは、KubernetesネイティブフレームワークはDeveloper Joy . 楽しい部分imhoは、我々は我々のアプリで表示されるライブコーディング機能です.私は本当にそれがJNIを使用しているにもかかわらず、私は私のアプリを再構築し、私のアプリを再読み込みし続ける必要はありません、と私は単に一緒にchugging保つことができると簡単にコーディング.私はこれが大好き!それは、生命をより単純にします.

設定


Java環境があるとします.これはJavaランタイム、ビルド用のMavenまたはGradleシステムを意味します.JNI用のOpenCVライブラリをダウンロードする必要があると考えているかもしれません.まあ何をする必要はありません推測!Qualkus OpenCv拡張はそれを気にするでしょう.Qualkus拡張はコアクォークフレームワークにより多くの機能を有効にする方法です.Quarkiverseはすべての拡張を保持するハブです.ですから、例えば、DocsやHibernate検索やAmazonのサービスの統合などのファジー検索を生成するための素晴らしいフレームワークを探している場合.よく自分自身を探すhere
それで、我々はQualkus OpenCvを使うつもりですextension .
これを行うには、まずコードから簡単なJava CLIプロジェクトを作成します.クォークラスio
始めるには2、3の方法がある.つは、ちょうどコードに向かうことができました.クォークラスIOとプロジェクトを作成したり、ローカルMavenコマンドを実行したり、クォークカスCLIを使用したりします.私は、私が最もよく知られているアプローチをとるつもりです.Mavenから始めましょう.
<1> mvn io.quarkus.platform:quarkus-maven-plugin:2.7.5.Final:create \
                    -DprojectGroupId=org.acme \
                    -DprojectArtifactId=getting-started \
                    -Dextensions="resteasy"

<2> cd getting-started                    

<3> ./mvnw quarkus:add-extension -Dextensions="io.quarkiverse.opencv:quarkus-opencv"

  • <1 -ここでコードからスタータープロジェクトをダウンロードします.クォークラス入出力プロジェクト名はgetting-started .
  • <2 -- iディレクトリを新しく作成したプロジェクトに変更します.
  • <3 --そして最後に私はまた、我々のプロジェクトにQuarkiverseからOpenCVの拡張機能を追加しています.
  • 今完了すると、仕事を始めるためのプロジェクトが必要です.IDEで開くことができます.Then
    pomをチェックしましょう.XMLが正しい依存関係を持っていること.あなたがこれに続いているならば、以下がPOMの依存関係のリストであることを確認してください.XML
      <dependencies>
        <dependency>
          <groupId>io.quarkus</groupId>
          <artifactId>quarkus-arc</artifactId>
        </dependency>
        <dependency>
          <groupId>io.quarkiverse.opencv</groupId>
          <artifactId>quarkus-opencv</artifactId>
          <version>LATEST</version>
        </dependency>
        <dependency>
          <groupId>io.quarkus</groupId>
          <artifactId>quarkus-junit5</artifactId>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>io.rest-assured</groupId>
          <artifactId>rest-assured</artifactId>
          <scope>test</scope>
        </dependency>
      </dependencies>
    
    
    次に、残りの簡単な依存関係を削除したので、残りの終了点も削除します.インorg.acme.GreetingResource.java とそのテスト.
    完璧なので、我々は始めるためにきれいなプロジェクトを持っています.ヒア

    CLIメインを作成する


    Qualkusコマンドラインのアプリを作成するオプションを提供し、これはので、ネイティブにこれらをコンパイルすることができますので、クールです.我々はちょうどこのブログのデモ目的のための簡単なアプリを作るつもりです.しかし、もしあなたがCLIアプリのいくつかの深刻な涅槃を作成しようとしているthis guide アットクォート.ピコクリクまたはJBang
    私のアプリでは、それをシンプルにしてください.Bearbone Qmainクラスを作成します.
    package org.acme;
    
    import io.quarkus.runtime.QuarkusApplication;
    import io.quarkus.runtime.annotations.QuarkusMain;
    
    @QuarkusMain
    public class QMain implements QuarkusApplication {
    
        @Override
        public int run(String... args) throws Exception {
            // TODO Auto-generated method stub
            return 0;
        }
    }
    
    私は今、端末でこのアプリを実行する予定です.そして、アプリケーションが開始されるとき、コマンドはlivecodingセッションを開始しなければなりません.

    ライブコーディングを開始する


    ~/demos/getting-started mvn quarkus:dev
    

    ライブコーディングは何ですか?まあ、ちょうどあなたのアプリケーションを再起動するか、新しい依存関係と設定やリビュードを追加する心配しないでコーディングを続ける..などあなただけのアプリを毎回再起動する必要はありません!(ほとんど)
    私はターミナルを走らせて、Qmainでコーディングに戻るつもりです.
    私は2つのクラスレベルのプロパティを追加するつもりです、1つからイメージを読んで、2番目のイメージを保存します.マイクロプロフィールを通してのクォーク@ConfigProperty . これは私のアプリケーションに設定プロパティを注入することができます.これが私のやり方です.
        // Set these in your application.properties
        @ConfigProperty(name = "cli.sourceImagePath")
        String testImage;
    
        // Set these in your application.properties
        @ConfigProperty(name = "cli.targetImagePath")
        String targetImage;
    
    
    そして、私のアプリケーションで.プロパティこれらのファイルへのパスを追加する
    cli.sourceImagePath=images/testImage.jpg
    cli.targetImagePath=images/testImageDetected-output.jpg
    
    一つはcli.sourceImagePath , これは処理するために存在しなければなりません.とcli.targetImagePath 私がそこにイメージを保存するので、存在する必要はありません.私の場合、私はイメージを私のプロジェクトのルートに加えましたimages/

    画像の読み込みと保存


    今すぐQmainに戻る.これらのパスに対するsaveメソッドとloadメソッドを追加します.
        /**
         * Loading the image
         */
        public Mat loadImage(String imagePath) {
            Imgcodecs imageCodecs = new Imgcodecs();
            return imageCodecs.imread(imagePath);
        }
    
    
    
        /**
         * Save the image to the targetPath
         */
        public void saveImage(Mat imageMatrix, String targetPath) {
            Imgcodecs imgcodecs = new Imgcodecs();
            imgcodecs.imwrite(targetPath, imageMatrix);
        }
    
    マットにはイメージヘッダーとデータマトリックスの2つの部分があります.ヘッダーは定数です、しかし、マトリックスのサイズはイメージに依存します.マットはパスからイメージをロードするために使われます、そして、マットはイメージの操作を実行するために我々の基本的な構成を形成します.

    フィルタインタフェースの定義


    そして、画像を処理するために複数のフィルタを作るために、私はマットをソースとして、それを処理して、それからマットを返すインターフェースを定義するつもりです.保存する前に複数のフィルタを画像に適用することができます.
    package org.acme;
    
    import org.opencv.core.Mat;
    
    public interface Filter {
    
        public Mat process(Mat src);
    
    }
    

    ドットの接続


    そして最後に、qmainのrunメソッドへのメソッド呼び出しを追加することで構造体を接続しようとします.いくつかの喜びをスパーク!
        @Override
        public int run(String... args) throws Exception {
            Mat m = loadImage(testImage);
    
            saveImage(m, targetImage);
            return 0;
        }
    
    シンプルで、上記のすべては画像を読み込み、画像を保存することです.まだ処理していません.どうやってテストするの?我々が走ったターミナルを思い出してくださいmvn quarkus:devその上にスペースを押してください.そして、プログラムはちょうど実行を続けます.どのようにクールです!再構築する必要はありません、すべての設定は、新しいクラスだけで働いた.Thats何が火花Developer Joy! , Qualkusで!

    ログをチェックアウトします.国File change detected 申し込み.プロパティの詳細については、変更されたクラスも一覧表示します.
    それで、ちょうど起こったこと?
    Qualkusランタイムは、CLIアプリケーションを実行しました.つまり、私が後藤ならばcli.targetImagePath 私はそこに作成されたイメージを見るべきです.この時点で、ソースイメージと同じように見えます.推測何?thats正確にwhati計画今する.
    移動して、私が今日使用しているイメージはShuttergames on Unsplash

    ガウシアン


    私が作成した最初のフィルタはGaussianBlur フィルタ.ITSlow-pass filter それが高周波信号を減衰させるという意味.全体的な視覚効果は滑らかなぼかしになります.
    package org.acme;
    
    
    
    import org.opencv.core.Mat;
    import org.opencv.core.Size;
    import org.opencv.imgproc.Imgproc;
    
    public class GaussianBlur implements Filter {
    
        @Override
        public Mat process(Mat src) {
    
            if(src != null) {
                int MAX_KERNEL_LENGTH = 45;
                Mat dst = new Mat();
                for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) {
                    Imgproc.GaussianBlur(src, dst, new Size(i, i), 0, 0);
                }
                return dst;
            }
    
            else throw new IllegalArgumentException("Looking for Mat nothing found!, try passing org.opencv.core.Mat to process");
        }
    }
    
    上記ではカーネルサイズを定義します.カーネルは、アンカーされたピクセルとその周囲のピクセルが提供される関数に基づいて変更される方法を定義する行列です.

    カーネルは、コンボリューション、重み、および中央に配置されたアンカーポイントのサイズを定義します.プロセスメソッドは、Gausianblurフィルタをカーネルサイズで適用し、最後にマットオブジェクトを返します.

    RGB 2グレー


    qmainの実行mehtodに以下を追加するので、私のフィルタを呼び出すことができます.
        @Override
        public int run(String... args) throws Exception {
            Mat m = loadImage(testImage);
    
            m = new GaussianBlur().process(m);
    
            saveImage(m, targetImage);
            return 0;
        }
    
    完璧な、私は再びターミナルにスペースバーを押すと、そのすべての変更を実行する必要があります.以下に示すようにぼかしを生じる.そのぼかしは滑らかで、ほとんどの場合、レンズでオーバーレイされています.

    次に、別のフィルタを作成します.今回はどうやってイメージをグレーにしますか?そのためにopencvは簡単な機能を提供します.また、私はこのため、マットを渡すと1つの背中をレシーバーインターフェイスを使用しています.
    package org.acme;
    
    import org.opencv.core.Mat;
    import org.opencv.imgproc.Imgproc;
    
    
    
    public class RGB2Grey implements Filter{
    
        @Override
        public Mat process(Mat src) {
            if(src != null) {
                Mat dst = src;
                Imgproc.cvtColor(src, dst, Imgproc.COLOR_RGB2GRAY);
                return dst;
            }
            else throw new IllegalArgumentException("Looking for Mat nothing found!, try passing org.opencv.core.Mat to process");
        }
    }
    
    
    上記コード使用ImgProc これはRGBからRGBへすべてのピクセルを動かすためにこの操作を提供します.
     m = new RGB2Grey().process(m);
    
    私のrunメソッドに上記を加えて、ターミナルで再びスペースバーを押すことは、再び私のすべてのcahngesを実行するべきです.Vola!私はグレーのトーンのイメージがあります.

    あなたが一緒にQualkusとOpenCVを使用する方法でこのランを楽しんでほしい.より多くの例のためにgithub repo with code examples .