Java OpenCV 〜背景除去、輪郭を学習する準備3:画像を表示する〜

JavaFXを使用してOpenCVで行なった処理を表示する仕組み(アプリ)を作成します。

前回、SceneBuilderを使用して作成した画面の土台になる部分に、コントローラーを追加しました。
これにより「ボタンを押下した時にXXXの処理をする〜」というような処理を実装することができます。

画像を描画する

そして、やっとOpenCVの処理にたどり着きました。
イメージファイルを読み込み表示する。。。ハローワールド的な処理ですが、まずはハローワールドです。

出力した結果はい下のような感じで出力することができました。

実装(成果物)

「FXMLファイル」

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.canvas.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<BorderPane fx:controller="zenryokuservice.opencv.fx.controller.TestingCvController"
        maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
        prefHeight="400.0" prefWidth="600.0"
        xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <top>
      <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" BorderPane.alignment="CENTER">
         <children>
            <Label text="Input app no" />
            <TextField promptText="App No" />
            <Button mnemonicParsing="false" text="Execute" onAction="#clickExecute"/>
         </children>
      </HBox>
   </top>
   <center>
      <Canvas fx:id="testCanvas" height="200.0" width="200.0" BorderPane.alignment="CENTER" />
   </center>
   <bottom>
      <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" BorderPane.alignment="CENTER">
         <children>
            <Button mnemonicParsing="false" text="Clear"  onAction="#clear"/>
         </children>
      </HBox>
   </bottom>
</BorderPane>

コントローラー

public class TestingCvController {

    @FXML
    private Canvas testCanvas;

    /** コンストラクタ */
    public TestingCvController() {
        this.testCanvas = new Canvas();
    }

    @FXML
    protected void clickExecute() {
        System.out.println("Helllo");
        URL url = getClass().getResource("/pipo-charachip007.png");
        Mat charactor = Imgcodecs.imread(url.getPath(), CvType.CV_8UC4);
        MatOfByte charaByte = new MatOfByte();
        Imgcodecs.imencode(".png", charactor, charaByte);
        try {
//          Image img = new Image(url.getPath().toString());
            BufferedImage buf = ImageIO.read(new ByteArrayInputStream(charaByte.toArray()));
            GraphicsContext g = testCanvas.getGraphicsContext2D();
            g.drawImage(SwingFXUtils.toFXImage(buf, null), buf.getWidth(), buf.getHeight());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @FXML
    public void setClosed() {
        // 現状は空実装
    }

    @FXML
    public void clear() {
        System.out.println("Clear");
        this.testCanvas.getGraphicsContext2D().clearRect(0, 0, this.testCanvas.getWidth(), this.testCanvas.getHeight());
    }
}

処理内容

FXMLで、アクションを指定しています。

<Button mnemonicParsing="false" text="Execute" onAction="#clickExecute"/>

この行で指定している#clickExevuteの部分でコントローラークラスの「TestingCvController#clickExevute()
を呼び出す」という意味になります。
同様に、<Button mnemonicParsing="false" text="Clear" onAction="#clear"/>の部分は「TestingCvController#clear()」を呼び出す。という命令を指定しています。

画像を表示する

下の処理が起動するメソッドになります。

@FXML
protected void clickExecute() {
    System.out.println("Helllo");
    URL url = getClass().getResource("/pipo-charachip007.png");
    Mat charactor = Imgcodecs.imread(url.getPath(), CvType.CV_8UC4);
    MatOfByte charaByte = new MatOfByte();
    Imgcodecs.imencode(".png", charactor, charaByte);
    try {
        BufferedImage buf = ImageIO.read(new ByteArrayInputStream(charaByte.toArray()));
        GraphicsContext g = testCanvas.getGraphicsContext2D();
        g.drawImage(SwingFXUtils.toFXImage(buf, null), buf.getWidth(), buf.getHeight());
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

ビルドパス上にあるフォルダより「pipo-charachip007.png"」を読み込み、SceneBuilderで作成したCanvasに書き込み処理を行っています。
上に表示した画像は指定のpngファイルを表示したものです。

ここまで来たので

現状としては、固定のイメージファイルを表示しているだけですが、ここからアプリっぽくしていきます。
変更点としては下の部分です。

  1. テキストボックスに入力したファイル名を表示する
  2. Clearボタンを押下したら、現在表示している画像を消す

とりあえずはここまで実装します。

LearnOpenCvクラスを作る

設計としては以下のような実装にしようと考えております。

  1. テキストフィールドに処理の名前(コマンド)を入力
  2. コマンドに対応したクラスのexecute()を起動する→なのでコマンドはいくらでも増やすことができる

具体的にどのように実現するか?

すでに実装してあるclickExcecute()の処理を修正して下のように変更する

  1. 入力値を受け取り、プロパティファイルのキーの有無をチェック
  2. プロパティファイルにキーがあれば、キーに紐付くクラスを取得、execte()を起動する
  3. 実行結果をCanvasに描画する

なので、execute()には引数としてGraphicsContextを渡してあげる必要があります。(描画するためです)

実装は次回にいたします。

でわでわ。。。



投稿者:

takunoji

音響、イベント会場設営業界からIT業界へ転身。現在はJava屋としてサラリーマンをやっている。自称ガテン系プログラマー(笑) Javaプログラミングを布教したい、ラスパイとJavaの相性が良いことに気が付く。 Spring framework, Struts, Seaser, Hibernate, Playframework, JavaEE6, JavaEE7などの現場経験あり。 SQL, VBA, PL/SQL, コマンドプロント, Shellなどもやります。

コメントを残す