OpenCv 画像編集 〜プログラマ的デザイン手法〜

イントロダクション

目標達成プロジェクトを作成し、目標ブレークを行った時の目標のカテゴリ分けをわかりやすくするため(わかりづらくなったらごめんなさい)。

カテゴリをイメージにしました。やったことのない「デザイン(イメージのデザイン)」を四苦八苦しながらやりました。

正確には「イメージの部品」を作成しました。作成したものはGitにアップしました。

OpenCVで画像を重ねる

元にしたコードは以前やったものを持ってきました。環境のセットアップも見直しました。

ちょいと注意しなくてはいけないのが以下の点になります。

  1. 「画像ファイル名は日本語ではエラーになる」
  2. EclipseNativeLibraryの設定

ここを見直しておくと「は?」とならないと思われます。

そして実行して困ったのが、表示したものが「黒くなっている」ということでした。どうやら「0」が「透過=黒」になっている様でMatのチャンネルを4つにしなくてはいけない様です。

実行した結果

はこんな感じです。サイズが「60 x 60」なので小さいです。

実行したコードは下の様な感じです。Gitで完全なコードが観れます。

long start = System.currentTimeMillis();
///// 画像読込 /////
// レベル0カテゴリ
Mat src = Imgcodecs.imread(OpenCVTest9_Substract.class.getResource("/categories/" + "1_create.png").getPath(), Imgcodecs.IMREAD_UNCHANGED);
// レベル1カテゴリ
Mat cart = Imgcodecs.imread(OpenCVTest9_Substract.class.getResource("/categories/" + "A_design.png").getPath(), Imgcodecs.IMREAD_UNCHANGED);
// レベル2カテゴリ
Mat cart1 = Imgcodecs.imread(OpenCVTest9_Substract.class.getResource("/categories/" + "a_artifacts.png").getPath(), Imgcodecs.IMREAD_UNCHANGED);
System.out.println("*** First ****");
// 出力用、画像(行列を表すクラス)
Mat dst = new Mat();
// 元の画像に重ねていく
Core.addWeighted(src, 0.5, cart, 0.5, 0, dst);
Core.addWeighted(dst, 0.5, cart1, 0.5, 0, dst);
System.out.println("*** Second ****");
Imgcodecs.imwrite("/dst/1Aa.png", dst);
ViewFrame frame = new ViewFrame(dst);
System.out.println("実行時間: " + (System.currentTimeMillis() - start) + "ミリ秒");

シンプルに画像を読み込んで、重ねていく処理です。OpenCvは、参考書などを読むと無茶苦茶難しいですが、部分的に使うなら問題なく使えました。

そして、こいつを理解すれば機械学習も怖くない(笑)

でわでわ。。。









OpenCV tutorial 〜フーリエ変換など〜

イントロダクション

今までのチュートリアルをやってきたのと、この先のチュートリアルを眺めてみたところ、ネックになっている「数式の理解」部分は難しいと判断しました。なので。。。

アプローチ方法をちょっと変えます。

とりあえず、写経(コピペしました(笑))してチュートリアルを起動する。

そして、そのアプリをカスタムして行く方向に切り替えます。

その御誂え向きなチュートリアルがこちらです。

「フーリエ変換」をやるチュートリアルになっていますが、こいつをカスタムして読み込んだイメージファイルをいろんな風に変換できるように修正しようと考えています。

とりあえずはアプリを起動してみました。※PNGではないイメージファイル

PNGファイルを選択した場合の動画

とりあえずは、準備ができた状態です。ここからどのようにカスタムして行くか?これが課題になりそうです。









OpenCV tutorial 解析2 〜ヒストグラム計算〜

イントロダクション

前回は、チュートリアルにあるコード(Git)を起動して、そのプログラムの内容について解析しました。

実際にはチュートリアルの「Calculate a Histogramのところにたどり着いた状態です。

ヒストグラムとは

ヒストグラムは、事前に定義されたビンのセットにまとめられたデータの収集数です。私たちの場合、データはピクセルの強度を表しているので、(0、256)のような範囲になります

チュートリアルには記載があるのですが、理解したのは色のデータ(0-256)を持っていることくらいです。

やっぱりコードから。。。

いつも通りコードから理解していきます。「なんやらわからんが、ヒストグラムを表示している(下のように)

この赤、緑、青のグラフ?が表示されているのはどうやらRGBの度合いが表示されているくさい(チュートリアルの文言から推測)

じゃ、コードで見て見ましょう。

ヒストグラムの表示領域

ImageView fx:id="histogram"

VideoControllerにある、ImageViewクラスの変数名が「histogram」を探す。。。

/** FXML ヒストグラム -> fx:id="histogram" */
@FXML
private ImageView histogram;

ありました、そしてこいつは、「showHistogram()」で処理しているようなのでこのメソッドを追いかけます。

// set the number of bins at 256
MatOfInt histSize = new MatOfInt(256);
// only one channel
MatOfInt channels = new MatOfInt(0);
// set the ranges
MatOfFloat histRange = new MatOfFloat(0, 256);

この部分で3つに分けているようです。

Imgproc.calcHist(images.subList(0, 1), channels, new Mat(), hist_b, histSize, histRange, false);

Core.calcHist()メソッドで細かい計算をしてくれるようです。

	// effectively draw the histogram(s)
	for (int i = 1; i < histSize.get(0, 0)[0]; i++)
	{
		// B component or gray image
		Imgproc.line(histImage, new Point(bin_w * (i - 1), hist_h - Math.round(hist_b.get(i - 1, 0)[0])),
				new Point(bin_w * (i), hist_h - Math.round(hist_b.get(i, 0)[0])), new Scalar(255, 0, 0), 2, 8, 0);
		// G and R components (if the image is not in gray scale)
		if (!gray)
		{
			Imgproc.line(histImage, new Point(bin_w * (i - 1), hist_h - Math.round(hist_g.get(i - 1, 0)[0])),
					new Point(bin_w * (i), hist_h - Math.round(hist_g.get(i, 0)[0])), new Scalar(0, 255, 0), 2, 8,
					0);
			Imgproc.line(histImage, new Point(bin_w * (i - 1), hist_h - Math.round(hist_r.get(i - 1, 0)[0])),
					new Point(bin_w * (i), hist_h - Math.round(hist_r.get(i, 0)[0])), new Scalar(0, 0, 255), 2, 8,
					0);
		}
	}
	
	// display the histogram...
	Image histImg = Utils.mat2Image(histImage);
	updateImageView(histogram, histImg);
	
}

こんな風にプログラムを起動しているようです。

わかったこと

  1. ROI(Rectクラス)でイメージの中に領域を作る
  2. Coreクラスの「calcHist()」「normalize()」「addWeighted()」などで色データの扱いができる

感想

単純にカメラからのデータをいじったり、成分解析したりできるのは魅力的だ!

ここで作成したアプリをラズパイなどに乗っけても面白そうだ。

続きは次回

でわでわ。。。









OpenCV tutorial 解析 〜ヒストグラム〜

イントロダクション

前回は、チュートリアルを読んでもよくわかならなかったので。。。

必殺の解析パターンをやろうという事になりました。(自分の中で)

  1. 写経する
  2. 動かす
  3. 中身を理解する

蒸気が解析パターンです。よくわからないものを触ったりして調べるのに似ていますね(笑)。そして、前回は上記工程の1と2を行いましたので、まぁ動いたかな?という感じです。ちょっと中途半端な表現ですがこれにはわけがあります。

上の動画が作成したものを動かしたときのものですが「Show logo」のチェックボックスをONにするとエラリます。

この部分の解決も含めてチュートリアルの記載とコードを解析して理解をしようというわけです。

参照するチュートリアルはこちらです。

解析開始

まずは、Mainメソッドからいきますので、「Tutorial2.java」からみていきます。

/**
 * Copyright (c) 2012-present Lightweight Java Game Library All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 * Neither the name Lightweight Java Game Library nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 */
package zenryokuservice.opencv.fx.tutorial;

import org.opencv.core.Core;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

/**
 * OpenCVのチュートリアルを写経します。
 * @author takunoji
 * 2019/02/02
 */
public class Tutorial2 extends Application {
	/** ネイティブライブラリを読み込む */
	static {
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
	}
	/**
	 * メインメソッド。
	 * @param args
	 */
	public static void main(String[] args) {
		// 親クラス(Superクラス)のメソッド起動
		launch();
	}

	/* (non-Javadoc)
	 * @see javafx.application.Application#start(javafx.stage.Stage)
	 */
	@Override
	public void start(Stage primaryStage) throws Exception {
		FXMLLoader loader = new FXMLLoader(getClass().getResource("Video.fxml"));
		BorderPane root = (BorderPane) loader.load();
		Scene scene = new Scene(root, 800, 600);
		scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());

		primaryStage.setTitle("Video Processing");
		primaryStage.setScene(scene);
		primaryStage.show();
		// 作成するクラス
		VideoController controller = loader.getController();
		primaryStage.setOnCloseRequest((new EventHandler() {
			public void handle(WindowEvent we) {
				controller.setClosed();
			}
		}));
	}
}

今までにJavaFXを作成したりしていたので、細かいところは省きます。

「start()」メソッドが走りFXMLLoaderにより、FXMLが読み込まれます。

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.text.*?>
<BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="zenryokuservice.opencv.fx.tutorial.VideoController">
<center>
   <ImageView fx:id="currentFrame" />
   </center>
   <right>
      <VBox alignment="CENTER_LEFT" spacing="10">
         <padding>
            <Insets left="10" right="20"/>
         </padding>
         <ImageView fx:id="histogram" />
         <Text text="Controls" />
         <CheckBox fx:id="grayscale" text="Show in gray scale" />
         <CheckBox fx:id="logoCheckBox" text="Show logo" onAction="#loadLogo" />
      </VBox
   </right>
   <bottom>
      <HBox alignment="CENTER" >
         <padding>
            <Insets top="25" right="25" bottom="25" left="25"/>
         </padding>
         <Button fx:id="button" alignment="center" text="Start camera" onAction="#startCamera" />
      </HBox>
   </bottom>
</BorderPane>

「fx:controller」に指定されている「VideoController」クラスにあるフィールド変数がこのタグの中に記載されている「fx:id」に対応しています。

名前を間違うとエラーが出ます。

ついでに、SceneBuilderで「FXML」を開いてみます。

表示されたのはチュートリアルにあるものと同じです、でも実際にアプリを起動したときには下のような感じです。

どうやら問題ないようですが、ちょっと納得がいきません。なのでコードを見ますと。。。

// フレームサイズ指定
this.currentFrame.setFitWidth(600);

これでFXMLにある「fx:id="currentFrame"」の部分(赤くなっています)に幅を600に設定しているようです。つまりSceneBuilderに表示されたときはサイズが0になっていたので下のような表示になっていた、という予測ができます。まぁ検証はしないのでここで終わりにします。時間があればFXMLにある「currentFrma」に横幅を与えて表示させてみると結果が見れると思います。

ちなみに「Show logo」のチェックボックスをクリックするとエラーが出る原因はファイルの指定が間違っていたからでした。チュートリアルは「resources」フォルダの直下にイメージファイルを置いていましたが、自分のところは違う場所に置いていたので。。。

チュートリアルを読み進める

実行してみると記載内容が驚くほど簡単にわかります。(実行した後だから当然といえば当然か(笑))

まとめると、JavaFXで画面を表示するのにFXMLとControllerクラスの関連付けを行なった後に。。。

ロゴを表示する

チェックされると、カメラストリーム上に画像の表示をトリガーします

この文言は翻訳したものです、「チェックされると」とあるのでその部分のコードを見ます。

fx:id="logoCheckBox" text="Show logo" onAction="#loadLogo"

とFXMLに記載があるので「VideoController#loadLogo」メソッドを見ます。※VideoControllerクラスのloadLogoメソッド

シンプルにロゴのイメージファイルを読んでフィールドに設定する処理でした。

this.logo = Imgcodecs.imread("resources/images/Poli.png");

これだけでなんで下にロゴが表示されるのでしょうか?

「startCamera」ボタンが謳歌された後に、キャプチャクラスの設定をしてRunnableインターフェースを実装しています(匿名クラス)というやつです。)

// フレームを30ミリ秒ごとに掴む (30 frames/sec)
Runnable frameGrabber = new Runnable() {
	@Override
	public void run() {
		Mat frame = grabFrame();
		Image imageToShow = Utils.mat2Image(frame);
		updateImageView(currentFrame, imageToShow);
	}
};

こいつをTimerクラスでスケジュールしてやるとそのように動いてくれるようです。※Timerクラスの中身はわからないけどそのように動いているので。。。

この実装はいろんなところで使えそうです。自分で無限ループの処理を書かなくてもこのクラスに登録(2行目の処理)をしてやれば、そのように動いてくれるようです。

this.timer = Executors.newSingleThreadScheduledExecutor();
this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);

OpenCVの操作に入る

ストリームの特定の領域にロゴを表示するために、コードにいくつかのバリアントを追加します。つまり、フレームキャプチャごとに、画像を1つまたは3つのチャンネルに変換する前に、ロゴを配置するROI(関心領域)を設定する必要があります。通常、画像のROIはその一部です。ROIをRectオブジェクトとして定義できます。Rectは、次のパラメータで記述された2D矩形のテンプレートクラスです。

loadLogoメソッドの処理での説明文です。画面上では確かに右下部分にロゴが表示されています。

そして、this.logo(フィールド変数)はVideoController#grabFrame()メソッドで使用されていて、なにやら処理を行っていました。ちなみに「grabFrame()」は上記の「Runnable」インターフェースを実装した匿名クラスで呼ばれていて、カメラが起動したら無限ループがスタートします(33(30)ミリ秒ごと)。

下の処理部分でROI(イメージファイルの表示領域)を指定しているのですが、

Rect roi = new Rect(frame.cols() - logo.cols()
     , frame.rows() - logo.rows(), logo.cols(),logo.rows());

「frame」 のcolsとrowsはキャプチャを読み込んでそのサイズが入っているので以下のようになります。

デバックして見た結果、キャプチャ全体のサイズからロゴのサイズを引き算した領域(Rectクラス)をキャプチャの領域に載せたように見せるための計算処理を行います。

今の所、ロゴのサイズがやたら小さいのがおかしいので「なんで?」と疑問に思っているのですが、このドキュメントを見て「addWeighted」の処理内容を調べましたが、よくわからなかった。。。

とりあえずは、画像の上に指定領域(Rect)部分を乗せることができるようだ。

そして、今回はここまでにします。(頭から煙が出てきたようで。。。)

でわでわ。。。








OpenCV tutorial〜ヒストグラム〜

イントロダクション

ようやく、OpenCVのチュートリアルを続ける準備ができました。

前回は、ビデオキャプチャを作成してJavaFXで起動しました。

問題というか気に入らない事

せっかく作成したビデオキャプチャと次に作成するヒストグラムのプログラムを別々に作成、もしくは変更するという方向でチュートリアルが記載されているので「画面切り替え」という形で今まで作成したものを残していく方法でやっていこうと思います。

画面切り替え作成はこんな感じでやりました。

そして、プロジェクトの構成を変えました。(リソースフォルダを使用するように修正)

スクリーンショット 2019-02-02 14.26.11.png

いざ、チュートリアル

参考にするサイトはこちらです。

今回のチュートリアルは「ビデオキャプチャ」作成後の状態(ソース)から始まっているようです。※自分にはふた通りの解釈ができました。

さぁ読み込んで理解してやるぞ!

結局。。。

よくわからなかった(記載している文言とキャプチャがずれているように見えた)のでソースから入ります。コードから入るのは理解力不足なのかもしれない。。。が、わからないなら結論から入るのもアリだと思うのです。

というわけで、チュートリアルページの一番下、以下キャプチャ参照(日本語に翻訳してます。。。)スクリーンショット 2019-02-02 14.58.55.png

Gitにあるソースを参照して写経します。元々の画面への追加は後日。。。

写経、そして起動

写経したら、早速動かしてみたいと思うのが人情(だと思う。。。)と言うわけで動かしてみました。

早速Exception

こんなのでました。

ちょっとわかりづらいけど、選択している部分に

at zenryokuservice.opencv.fx.tutorial.Tutorial2.start(Tutorial2.java:35)

実行したクラス名があります、そのクラス「start」メソッドTutorial2.javaの35行目でエラってます。。。という内容です。下の部分がそうです。

「Video.xml」とコーディングしてます。。。ファイルがないから落ちるな(笑)

「Video.fxml」に修正、サイド実行する

どーん!

またException、いつものことなので「なんだまだかよ?」みたいな感じです。

ポイントは下の方に記載がある、赤い字の部分です。

Caused by: java.lang.ClassNotFoundException: it.polito.teaching.cv.VideoController
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:920)

「java.lang.ClassNotFoundException」は「クラスが見つかりませんよ!」というExceptionです。

作成したパッケージが「zenryokuservice.〜」で始まっているのに「it.polito〜」で始まっているのは明らかにおかしい→コピペが犯人です。自分が悪いわけじゃありません(ちゃんとやらないのがいけません。。。)というわけで、Video.fxmlのパッケージ名を修正します。

it.polito.teaching.cv.VideoController」
   →「zenryokuservice.opencv.fx.tutorial.VideoController」

そして再度実行!はい!いらっしゃい!

今度は、FXMLローダあたりのエラーのようです。

Caused by: java.lang.UnsatisfiedLinkError: org.opencv.videoio.VideoCapture.VideoCapture_3()J
at org.opencv.videoio.VideoCapture.VideoCapture_3(Native Method)
at org.opencv.videoio.VideoCapture.<init>(VideoCapture.java:72)
at zenryokuservice.opencv.fx.tutorial.VideoController.initialize(VideoController.java:72)
... 24 more

この「UnsatisfiedLinkError」は自分にもよくわかりませんでした。。。が赤い字で示す通り、VideoController.javaの72行目

this.capture = new VideoCapture();

「んー!なんでだ?わからんぞ?。。。」と5分くらい考えましたがわからなかったです。駄菓子菓子、OpenCVのライブラリの設定をしていなかった事に気がつきました(笑)

そう!OpenCVでプロジェクトにライブラリを設定する、実行時にライブラリを読み込む事が必要なのです。

/** ネイティブライブラリを読み込む */
static {
    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}

「static { 〜 }」の部分はメインメソッドの前に起動される部分です。

【補足】

Javaを起動するときに走る順番

  1. 「JVM(javaコマンドだと思ってください)
  2. 「staic」のついているフィールド、メソッド、スコープ(「{」と「}」で囲まれている部分)がJVMに読み込まれます。
  3. メインメソッド

大雑把にこんな感じです。そして修正して再実行!

Caused by: java.lang.ClassCastException: javafx.scene.layout.BorderPane cannot be cast to javafx.fxml.FXMLLoader
	at zenryokuservice.opencv.fx.tutorial.Tutorial2.start(Tutorial2.java:45)
	at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
	at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
	at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
	at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
Exception running application zenryokuservice.opencv.fx.tutorial.Tutorial2

BorderPaneはFXMLLoaderにキャストできません。というわけで下のように修正をします。

<変更前>

FXMLLoader loader = FXMLLoader.load(getClass().getResource("Video.fxml"));

<変更後>

FXMLLoader loader = new FXMLLoader(getClass().getResource("Video.fxml"));

凡ミスのようです。。。これで最後であって欲しい。。。

どーだぁ!

キターーーー!

ちなみに「Show Logo」のチェックボックスを押下するとエラリます。。。

これでなんとか動いたので、この処理の内容をみていきます。

ただし、次回にします。

でわでわ。。。









Java OpenCv ビデオキャプチャ〜カメラからの入力を表示〜

イントロダクション

TensorFlowでの機械学習のチュートリアルを多少やりました。下にリンクにあるような感じでやりました。

 

細かいところはわからなかった

チュートリアルでやったことはあくまでフレームワークとしてのTensorFlowの使い方なので、キモになる部分は、機械学習の中身はわからなかったと言うことです。

じゃあどーするか?

OpenCvの機械学習から理解していこうと思います。

どこからやるのか?

JavaFxで途中までやっていたのですが、ちょっとバグっぽいのがあったので放置していたもの(GIT)を持ってきて再開しようと思います。

参考にしているサイトはこちらです。

前回までのOpenCv関連のやったこと

  1. EclipseにSceneBuilderを追加する
  2. JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~
  3. Java OpenCv Lv1 〜入門: 写真の表示〜
  4. Java OpenCV Lv2 〜JavaFXでの画像表示〜

その前にバグ退治をやります。

どこから改修しようかととりあえずは参照元ソースを見た所。。。

実装していない部分を発見、Mainメソッドのクラスにありました。。。どーりで気づかないわけだ。。。Conrollerクラスしか見てなかったもんなぁ。。。

そんなわけでコードを追加してやったらご覧の通り動きした。

次回からは、このチュートリアルの続きをやっていこうと思います。

そして次回は

カラーチャンネルについてやるようです。


関連ページ一覧

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. Java Git clone in Eclipse 〜サンプルの取得〜
  3. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  4. IntelliJ IDEA GitGitリポジトリからクローン〜
  5. Java Basic Level 1 Hello Java
  6. Java OpenCV 環境セットアップ(on Mac)

 

Java OpenCv Lv10〜画像の平均輝度をだす〜

イントロダクション

前回に引き続きメソッドの処理を実行して処理を確認します。

「C++」cvAvg() => 「Java」Core.mean()

参考サイト:OpenCV Code Example(サンプル)

すごくわかりづらいけど、少し濃いめの灰色になったようです。

ソース

public static void main(String[] args) {
	long start = System.currentTimeMillis();
	// 画像を2枚読み込む
	Mat src = Imgcodecs.imread(OpenCVTest12.class.getResource("/images/4color.png").getPath());
	Scalar scalar = Core.mean(src);
	// 論理演算処理を行う
	Mat dst = new Mat(new Size(50, 50), CvType.CV_8UC1, scalar);
	ViewFrame frame = new ViewFrame(dst);
	System.out.println("実行時間: " + (System.currentTimeMillis() - start) + "ミリ秒");
}

これもやっぱり、よくわかりませんでした。根本的に「どんなことを計算しているか?」の部分を理解する必要があるようです。

関連ページ一覧

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. Java OpenCV 環境セットアップ(on Mac)
  3. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
    1. JavaFXでのハローワールド〜OpenCVのチュートリアル迄続きます。

今までにやったこと(OpenCV編)

  1. Java OpenCV 環境セットアップ(on Mac)
  2. Java OpenCv Lv1 〜入門: 写真の表示〜
  3. Java OpenCV Lv2 〜画像を表示する〜
  4. Java OpenCV Lv3 〜画像の平滑化(smooth())〜
  5. Java OpenCV Lv3 〜画像にガウシアンフィルタ(GaussianBlur())〜
  6. Java OpenCV Lv4 〜画像の中身をみてみる〜
  7. Java OpenCV Lv5 〜Matクラスで描画処理〜
  8. Java OpenCV Lv6 〜Matクラスで背景から作成してみる〜
  9. Java OpenCV Lv7 〜MatクラスでEllipseしてみる〜
  10. Java OpenCV Lv9 〜画像編集「足し算」(cvAdd)〜
  11. Java OpenCV Lv9 〜画像編集「引き算」(cvSubtract)〜
  12. Java OpenCV Lv9 〜画像の掛け算〜
  13. Java OpenCV Lv10 〜行列演算Mat#submat()〜
  14. Java OpenCv Lv10〜画像の平均値をだす〜

Java OpenCV Lv10 〜画像の論理演算〜

Javaでクロス!モンハンじゃないよ?

イントロダクション

前回は、Mat#submat()を実行してみました。元の画像データを切り抜きその部分に変更を加えるものでした。

今回は、Core#bitwise_and()を実行してみます。

Java OpenCV Lv9 〜画像の掛け算〜

画像の論理演算「AND演算処理」

本を読むと、描く配列ごとの論理積の結果を出力するようです。つまり「掛け算」ということです。前々回やったような?些細なことは放っておき。。。

シンプルに実行した結果を記載いたします。

<実行結果>

 +  = 

<上の絵が見えないとき用>



2つの画像が合体したような感じです。どっかでみたような結果だな・・・

 

上でやったのと同じ結果だな(元にした画像は違います)

使用したメソッドは下のものです。パラメータも多く細かい調整が可能です。

Core.addWeighted(src, 0.5, cart, 0.5, 0, dst);

今回使用したのは下のソースコード赤い字の部分です。

<ソース> ※Gitからダウンロードできます

/**
 * メインメソッド、書き方は決まっている。
 * イメージファイルを読み込んで線を引く
 * 
 * @param argsプログラム引数
 */
public static void main(String[] args) {
	long start = System.currentTimeMillis();
	// 画像を2枚読み込む
	Mat src = Imgcodecs.imread(OpenCVTest11.class.getResource("/images/4color.png").getPath());
	Mat cart = Imgcodecs.imread(OpenCVTest11.class.getResource("/images/racgaki2.png").getPath());
	// 論理演算処理を行う
	Mat dst = new Mat();
	Core.bitwise_and(src, cart, dst);
	ViewFrame frame = new ViewFrame(dst);
	System.out.println("実行時間: " + (System.currentTimeMillis() - start) + "ミリ秒");
}

まとめ

アルファブレンド(addWeighted)の調整値(param)を上のコードと同じように実行すると論理積と同じ結果でる。

画像処理を行うときは、それぞれ適当な方法を洗濯して使用する。。。というところでしょうか。

でわでわ。。。

関連ページ一覧

  1. ava Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseにCDTをインストール〜
  3. Setup OpenGL with Java〜JOGLを使う準備 for Eclipse〜
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)

今までにやったこと(OpenCV編)

  1. Java OpenCv Lv1 〜入門: 写真の表示〜
  2. Java OpenCV Lv2 〜画像を表示する〜
  3. Java OpenCV Lv3 〜画像の平滑化(smooth())〜
  4. Java OpenCV Lv3 〜画像にガウシアンフィルタ(GaussianBlur())〜
  5. Java OpenCV Lv4 〜画像の中身をみてみる〜
  6. Java OpenCV Lv5 〜Matクラスで描画処理〜
  7. Java OpenCV Lv6 〜Matクラスで背景から作成してみる〜
  8. Java OpenCV Lv7 〜MatクラスでEllipseしてみる〜
  9. Java OpenCV Lv9 〜画像編集「足し算」(cvAdd)〜
  10. Java OpenCV Lv9 〜画像編集「引き算」(cvSubtract)〜
  11. Java OpenCV Lv9 〜画像の掛け算〜
  12. Java OpenCV Lv10 〜行列演算Mat#submat()〜
  13. Java OpenCv Lv10〜画像の平均値をだす〜

Java OpenCV Lv10 〜行列演算Mat#submat()〜

Javaでクロス!モンハンじゃないよ?

イントロダクション

Lv9では、画像(行列=Mat)の足し算と引き算、アルファブレンド(掛け算?)をやりました。

ここからは、ドラクエⅢ的にいうならば地下世界に突入します。

Lv9でやった「足し算」と「引き算」はバラモスのようなものでまぁ本番前の前哨戦と言ったところです。

今回の目玉

Lv9の処理でやったものは条件があり、演算するときにサイズを同じにする必要があります。(50x50, 100x100など)これはあまり実践的ではありませんので「策」が必要です。

「策」とは?

シンプルに、画像のサイズが違うなら一部を抜き出してしまえば良いのです。 ※調べているうちに気がつきました(笑)

つまりMat#subMat()を使用するということです。

ちょっと手こずりましたが、基本ですね。。。何が言いたいかというと

今回使用したMat#submat()は抜き出したMat(ROI)の参照を持っているのでいちいち変換処理の後に元の画像データに戻してやる必要がない(※参照渡しになっている)ということでした。参考サイトはstackoverflow

<実行結果>



<ソース> ※Gitからダウンロードできます

public static void main(String[] args) {
	long start = System.currentTimeMillis();
	// mountain.png(798x503)
	Mat src = Imgcodecs.imread(OpenCVTest9_Substract.class.getResource("/images/mountain.png").getPath());
        // rakugaki.png(50x50)
	Mat cart = Imgcodecs.imread(OpenCVTest9_Substract.class.getResource("/images/racgaki2.png").getPath());
	Rect rect = new Rect(600, 400, 50, 50);
        // 変更したい部分を切り抜く
	Mat roi = src.submat(rect);
	// 抜き出した部分に掛け算を行う(アルファブレンドを行う)
	Core.addWeighted(roi, 0.5, cart, 0.5, 0, roi);
               // 掛け算を行なったとき、元の画像データの抜き出した部分を変更しているので「src」をそのまま表示
	ViewFrame frame = new ViewFrame(src);
	System.out.println("実行時間: " + (System.currentTimeMillis() - start) + "ミリ秒");
}

関連ページ一覧

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseにCDTをインストール〜
  3. Setup OpenGL with Java〜JOGLを使う準備 for Eclipse〜
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)

今までにやったこと(OpenCV編)

  1. Java OpenCV 環境セットアップ(on Mac)
  2. Java OpenCv Lv1 〜入門: 写真の表示〜
  3. Java OpenCV Lv2 〜画像を表示する〜
  4. Java OpenCV Lv3 〜画像の平滑化(smooth())〜
  5. Java OpenCV Lv3 〜画像にガウシアンフィルタ(GaussianBlur())〜
  6. Java OpenCV Lv4 〜画像の中身をみてみる〜
  7. Java OpenCV Lv5 〜Matクラスで描画処理〜
  8. Java OpenCV Lv6 〜Matクラスで背景から作成してみる〜
  9. Java OpenCV Lv7 〜MatクラスでEllipseしてみる〜
  10. Java OpenCV Lv9 〜画像編集「足し算」(cvAdd)〜
  11. Java OpenCV Lv9 〜画像編集「引き算」(cvSubtract)〜
  12. Java OpenCV Lv9 〜画像の掛け算〜
  13. Java OpenCV Lv10 〜行列演算Mat#submat()〜
  14. Java OpenCv Lv10〜画像の平均値をだす〜

重宝するページ:JavaDoc(opencv-343.jar API)

Java OpenCV Lv9 〜画像の掛け算〜

Javaでクロス!モンハンじゃないよ?

イントロダクション

このところ、画像の計算を行なっております。

  1. Java OpenCV Lv9 〜画像編集「足し算」(cvAdd)〜
  2. Java OpenCV Lv9 〜画像編集「引き算」(cvSubtract)〜

足し算、引き算。。。とくれば「掛け算」でしょう。というわけで掛け算やります。

画像のアルファブレンド(掛け算?)

とりあえず「アルファブレンド」の意味がわからないので調べます。

ついでに「アルファチャンネル」も理解する必要アリのようです。

まずは実行して見ます。

 +  = 

これが、始めイメージしていた「足し算」でしたが、どうやら「掛け算」にあたるようです。


ソース>※GItからダウンロードできます。

public static void main(String[] args) {
	long start = System.currentTimeMillis();
	// 真っ白な画像から引き算してみる
	Mat src = Imgcodecs.imread(OpenCVTest9_Substract.class.getResource("/images/rakugaki.png").getPath());
	Mat cart = Imgcodecs.imread(OpenCVTest9_Substract.class.getResource("/images/racgaki2.png").getPath());
	System.out.println("*** First ****");
	System.out.println(src.dump());
	Mat dst = new Mat();
	Core.addWeighted(src, 0.5, cart, 0.5, 0, dst);
	System.out.println("*** Second ****");
	System.out.println(dst.dump());
	ViewFrame frame = new ViewFrame(dst);
	System.out.println("実行時間: " + (System.currentTimeMillis() - start) + "ミリ秒");
}

結果を見てみて

今までやってきた画像の計算に関しては、計算するときに画像のサイズを合わせる必要がある、が100x100の画像と20x20の画像を掛け算(アルファブレンド)したいときは、ROIで画像の切り抜きを行えば問題なしです。

関連ページ一覧

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseにCDTをインストール〜
  3. Setup OpenGL with Java〜JOGLを使う準備 for Eclipse〜
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)

今までにやったこと(OpenCV編)

  1. Java OpenCV 環境セットアップ(on Mac)
  2. Java OpenCv Lv1 〜入門: 写真の表示〜
  3. Java OpenCV Lv2 〜画像を表示する〜
  4. Java OpenCV Lv3 〜画像の平滑化(smooth())〜
  5. Java OpenCV Lv3 〜画像にガウシアンフィルタ(GaussianBlur())〜
  6. Java OpenCV Lv4 〜画像の中身をみてみる〜
  7. Java OpenCV Lv5 〜Matクラスで描画処理〜
  8. Java OpenCV Lv6 〜Matクラスで背景から作成してみる〜
  9. Java OpenCV Lv7 〜MatクラスでEllipseしてみる〜
  10. Java OpenCV Lv9 〜画像編集「足し算」(cvAdd)〜
  11. Java OpenCV Lv9 〜画像編集「引き算」(cvSubtract)〜
  12. Java OpenCV Lv9 〜画像の掛け算〜
  13. Java OpenCV Lv10 〜行列演算Mat#submat()〜
  14. Java OpenCv Lv10〜画像の平均値をだす〜

重宝するページ:JavaDoc(opencv-343.jar API)