Java OpenCV Lv7 〜MatクラスでEllipseしてみる〜

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

イントロダクション

引き続き、OpenCVをいじり倒していきます。今度は「Ellipse」メソッドを使用して見ます。黒い背景のイメージを読み込んで単純にメソッドを使用して見ます。

<実行結果1>

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

/**
 * メインメソッド、書き方は決まっている。
 * イメージファイルを読み込んで線を引く
 * 
 * @param argsプログラム引数
 */
public static void main(String[] args) {
	// 100x100の白いPNGからのデータを作成する
	Mat src = Imgcodecs.imread(OpenCVTest7.class.getResource("/images/black.png").getPath());
	Imgproc.ellipse(src
			, new Point(src.width() /2, src.height() / 2)
			, new Size(src.width() / 4, src.width() / 16)
			, 0     // angle
			, 0.0   // ??
			, 360.0 // 0と360度の間の弧を延長する
			, new Scalar(255, 0, 0) // BGRの値
			, 2   // thickness
			, 8   // lineType
			, 0); // Shift
	System.out.println(src.dump());
	// 自作のJFrame拡張クラス
	new ViewFrame(src);
}

よくわからないけど真ん中に輪っかができました。

今度はImgproc#ellipse()のパラメータを変更して実行します。

「new Size(src.width() / 4, src.width() / 4)」に変更します。

<実行結果2>

普通の丸になりました。今度は逆にして見ます。

new Size(src.width() / 16, src.width() / 4)

<実行結果3>

縦長になりました。第三引数のサイズの第一引数がX軸方向の幅、第二引数がY軸方向の幅を定義しているので「丸」が開店しているようなイメージになるのであろうと推測します。なんか推測ばかりで確証までなかなかたどり着きませんが。。。次は連続してラベルを表示して見ます。その際にEllipseの値を変更して追加します。

	/**
	 * メインメソッド、書き方は決まっている。
	 * イメージファイルを読み込んで線を引く
	 * 
	 * @param argsプログラム引数
	 */
	public static void main(String[] args) {
		// 100x100の白いPNGからのデータを作成する
		Mat src = Imgcodecs.imread(OpenCVTest7.class.getResource("/images/black.png").getPath());
		src = ellipseLabel(src, 4, 16);
		System.out.println(src.dump());
		// 自作のJFrame拡張クラス
		ViewFrame frame = new ViewFrame(src);
		sleepFrame();
		frame.updateLabel(ellipseLabel(src, 16, 4));
		sleepFrame();
		frame.updateLabel(ellipseLabel(src, 2, 4));
	}

	private static Mat ellipseLabel(Mat src, int left, int right) {
		Imgproc.ellipse(src
				, new Point(src.width() /2, src.height() / 2)
				, new Size(src.width() / left, src.width() / right)
				, 0     // angle
				, 0.0   // ??
				, 360.0 // 0と360度の間の弧を延長する
				, new Scalar(255, 0, 0) // BGRの値
				, 2   // thickness
				, 8   // lineType
				, 0); // Shift
		return src;
	}

	private static void sleepFrame() {
		try {
			Thread.sleep(3000L);
		} catch(Exception e) {
			e.printStackTrace();
			System.exit(-1);
		}

	}

 

	/** 引っ越し2018/11/23 */
	private final JLabel label;
	
	public ViewFrame(Mat image) {
		// 受け取ったMatを表示する
		super("Show Image");
		// JFrameのメソッドを呼び出す(親クラス)
		Container con = super.getContentPane();
		
		// 入力ストリームを用意する
		BufferedImage buf = getIconImage(image);
		// ラベルをフィールドに持っていく 2018/11/23
		label = new JLabel(new ImageIcon(buf));
		con.add(label);
		// JFrameを閉じるときにアプリケーションも終わるようにする
		super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		// コンポーンエントの配置を整理する
		super.pack();
		// JFrameを表示する(これをやらないと何も表示されない)
		setVisible(true);
	}

	private BufferedImage getIconImage(Mat image) {
		// イメージのバイト配列を受ける変数
		MatOfByte bytes = new MatOfByte();
		// 上の変数にpngファイルを書き込む
		Imgcodecs.imencode(".png", image, bytes);
		// プリミティブ型に変換
		byte[] b = bytes.toArray();
		// 入力ストリームを用意する
		InputStream in = new ByteArrayInputStream(b);
		
		BufferedImage buf = null;
		try {
			// イメージとして読み込む
			buf = ImageIO.read(in);
		} catch(IOException e) {
			e.printStackTrace();
		}
		return buf;
	}
	/**
	 * 引数のMat(イメージ)でラベルを更新します。
	 * @param img Mat
	 */
	public void updateLabel(Mat img) {
		label.setIcon(new ImageIcon(getIconImage(img)));
	}

<実行結果4>


今回はここまでにしておきます。

関連ページ一覧

  1. Java OpenCV 環境セットアップ(on Mac)
  2. Java Install Eclipse〜開発ツールのインストール〜
  3. Java OpenCv Hello in Java〜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 Lv6 〜Matクラスで背景から作成してみる〜

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

イントロダクション

前回はMatクラスを使用して描画処理を行って見ました。ただし、背景のイメージファイルを読み込んで起動、一からのイメージ作成はしていませんでした。

今回は、Matクラスでイチからイメージを作成してみようと思います。

<今までの記事>

  1. ava 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クラスで描画処理〜

Gitからのプロジェクト取得


やることはすごくシンプル

Matクラスをnewするときにちゃんとパラメータを渡してあげるだけです。

引数に画像のサイズ(int, int)「CvType.CV_8UC1」を渡してやるだけです。そして左のリンクページの記事より、扱えるチャネル(Channel)は1つということで。。。

色は黒と白のみなのであろう(予想)と思いました。

<実行結果1:CV_8UC1>

<ソース>

public static void main(String[] args) {
	// 100x100の白いPNGからのデータを作成する
//	Mat src = Imgcodecs.imread(OpenCVTest6.class.getResource("/images/black.png").getPath());
	Mat src = new Mat(50, 50, CvType.CV_8UC1);
	Point pt1 = new Point(0,0);
	Point pt2 = new Point(50,50);
	Imgproc.line(src, pt1, pt2, new Scalar(240, 255, 240), 1);
	System.out.println(src.dump());
	// 自作のJFrame拡張クラス
	new ViewFrame(src);
}

ちなみに白(255)で試してもゴミ(ノイズ?)が出ていました。

これは指定した色、他のプロパティ(Channelなど)が「CV_8UC1」に対応していないためと予想します。そんなわけで、CV_8UC2で起動しました。

エラーが出て以下の文言が見当たりました。

channels == 1 || channels == 3 || channels == 4 in function 'imencode'

どうやらチャネル数は1,3,4のどれかでなくてはならないようです。

改めて「CV_8UC3」で勝負!

<実行結果2:CV_8UC3>

動いたけど、ゴミはまだ残っています。そして、実行結果1と比べて少しカラフルになりました。ついでなのでCV_8UC4も実行して見ます。

<実行結果4>

おお!背景の「黒」が消えた!!ついでだから他のものも。。。

【補足】上記の「ソース」の赤い字の部分のみを変更して実行しています。

<実行結果5:CV_8SC1>

<実行結果6:CV_8SC3>

<実行結果7:CV_8SC4>

ここまでやったら、XX4は黒が透明になルようだと推定します。

<実行結果8:CV_16UC3>

おお!綺麗に線が引けた感じがする。。データは下のようになりました。

理由はよくわからないが、8XXだとゴミが入るけど16XXの時はゴミが入らなそうだ。

関連ページ一覧

  1. Java OpenCV 環境セットアップ(on Mac)
  2. Java Install Eclipse〜開発ツールのインストール〜
  3. Java OpenCv Hello in Java〜OpenCv事始め〜

Java OpenCV Lv5 〜Matクラスで描画処理〜

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

イントロダクション

今までの学習で、OpenCV(JavaCV)でフィルター処理(①)と描画処理(②)ができることがわかりました。

  1. Java OpenCV Lv2 〜画像を表示する〜 シンプルに画像を表示する
  2. Java OpenCV Lv3 〜画像の平滑化(smooth())〜 ①
  3. Java OpenCV Lv3 〜画像にガウシアンフィルタ(GaussianBlur())〜 ①
  4. Java OpenCV Lv3 〜画像に中央値フィルタ(medianBlur())〜 ①
  5. Java OpenCV Lv4 〜画像の中身をみてみる〜 ②

Gitからのプロジェクト取得


イメージファイル(PNG, JPGなど)の中身は数値型の配列になっていることがわかったので、次はそいつらをコントロールする方法を学びます。

<参考サイト>

MatクラスのJavaDoc

OpenCVのチュートリアル

RBGの値と色の表

学習ポイント

  1. 数値型の配列([0, 255, 255, 0, ...])の値はRGBが割り当てられていることを確認
  2. Matクラスでの描画方法(線を引く)

早速実装に入ります。

注意点として、白はデータ上「255」になります。なので白い背景を使用したら全部が「255」になります。

そして、実装するときには以下の手順でやります。

  1. OpenCVのライブラリを読み込む(staticで読み込みます)
  2. white100x100.png(背景)をロードする
  3. 線の開始点、終点を指定する(Point)
  4. Imgproc.line()で描画する

描画メソッドの参考

<実行結果>

<ソース(OpenCVTest5.java>

/**
 * メインメソッド、書き方は決まっている。
 * イメージファイルを読み込んで線を引く
 * 
 * @param argsプログラム引数
 */
public static void main(String[] args) {
	// 100x100の白いPNGからのデータを作成する
		Mat src = Imgcodecs.imread(OpenCVTest5.class.getResource("/images/white100x100.png").getPath());
	Point pt1 = new Point(0,0);
	Point pt2 = new Point(100,100);
	Imgproc.line(src, pt1, pt2, new Scalar(240, 255, 240), 4);

	System.out.println(src.dump());
	// 自作のJFrame拡張クラス
	new ViewFrame(src);
}

Imageデータを編集(描画)してから、表示に使用しているViewFrameクラスはjavax.swingパッケージ(Swing)を使用しています。

<自分で試す手順>

  1. Eclipseをセットアップする
  2. 関連ページ一覧のOpenCV(JavaCV)のセットアップを行う
  3. Gitから作成したソース、リソースをダウンロード
  4. Eclipseでプログラムを実行する

関連ページ一覧に補足になるような記事があります。

関連ページ一覧

Eclipse セットアップ

  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 Lv3 〜画像に中央値フィルタ(medianBlur())〜
  7. Java OpenCV Lv4 〜画像の中身をみてみる〜
  8. Java OpenCV Lv5 〜Matクラスで描画処理〜
  9. Java OpenCV Lv6 〜Matクラスで背景から作成してみる〜
  10. Java OpenCV Lv7 〜MatクラスでEllipseしてみる〜
  11. Java OpenCV Lv9 〜画像編集「足し算」(cvAdd)〜
  12. Java OpenCV Lv9 〜画像編集「引き算」(cvSubtract)〜
  13. Java OpenCV Lv9 〜画像の掛け算〜
  14. Java OpenCV Lv10 〜行列演算Mat#submat()〜
  15. Java OpenCv Lv10〜画像の平均値をだす〜

Java OpenCV Lv4 〜画像の中身をみてみる〜

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

イントロダクション

今回はPNGファイルの中身をのぞいて、プログラムで線を引く描画処理をしてみます。今までやってきたことは下のリンク参照で。。。

  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 Lv3 〜画像に中央値フィルタ(medianBlur())〜

しかし、画像がぼやけた感じになったのはわかったのですが、処理としては何をしているのかいまいちわかりませんでした。

なので、今回は画像の中身をみてみようと思います。

今回のポイント

  1. 画像データはどんなものなのか?
  2. 画像のデータを操作するということは、何をすることか?
  3. 色はどんなデータ?

今回使用するイメージ(アイコン)ファイルは下のようなものです。

一発目のイメージファイル

<likeEye.png>: 10 x 10

そして、下のようなコードをみてください

package jp.zenryoku.opencv;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import jp.zenryoku.opencv.view.ViewFrame;

/**
 * OpenCVで平滑化処理を行う。
 * 
 * @author takunoji
 * 2018/11/22
 */
public class OpenCVTest4 {

	static {
		// OpenCVのライブラリをロードする
		// static {~}はMainメソッドの開始前に起動する、起動するプログラムで1つ定義可能
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
	}
	/**
	 * メインメソッド、書き方は決まっている。
	 * イメージファイルを読み込んでぼかす Imgproc.blur()
	 * 
	 * @param argsプログラム引数
	 */
	public static void main(String[] args) {
		// ファイルの読み込み
		Mat src = Imgcodecs.imread(
				OpenCVTest4.class.getClass().getResource("/images/likeEye.png").getPath());
		System.out.println(src.dump());
// OpenCVTest3の一部をコメントアウト
//		// 出力用変数
//		Mat dst = new Mat();
//		// ブラーする、種知力用の変数に値をセットする→「参照渡し」
//		//Imgproc.blur(mat, source, new Size(2.0,2.0));
//		// 中央値フィルタ
//		Imgproc.medianBlur(src, dst, 7);
//		// 自作のJFrame拡張クラス
//		new ViewFrame(dst);
	}
}

前回のコードの一部をコメントアウトして、Matクラスのメソッドで読み込んだPNGファイルの中身をコンソール出力します。結果は下に

[  0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255;
 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255;
 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255;
 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255;
 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255;
 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255;
 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255;
 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255;
   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255;
 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]

上の結果を見てみると、「;」で区切られた配列が10個あります。そして1行の配列長が30になっています。

二発目のイメージファイル

一発目のイメージファイルに線を一本引いてそれを表示したものです。




キャプチャーしたものを加工したので少し変ですが。。。一発目と同じ<10 x 10>のイメージです。

そして、中身のデータは以下。

[ 30,  30,  40, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255;
 255, 255, 255,  30,  30,  40, 255, 255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255;
 255, 255, 255, 255, 255, 255,  30,  30,  40, 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255;
 255, 255, 255,   0,   0,   0, 255, 255, 255,  30,  30,  40, 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255;
 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255,  30,  30,  40, 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255;
 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255,  30,  30,  40, 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255;
 255, 255, 255, 255, 255, 255,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255,  30,  30,  40, 255, 255, 255, 255, 255, 255, 255, 255, 255;
 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0, 255, 255, 255,  30,  30,  40, 255, 255, 255, 255, 255, 255;
   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  30,  30,  40, 255, 255, 255;
 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  30,  30,  40]

初めの2個だけ赤い文字にしました。ちなにみ初めのソースと違う部分は以下の赤い字の部分。

今日の学習ポイント

// ファイルの読み込み
Mat src = Imgcodecs.imread(
	OpenCVTest4.class.getClass().getResource("/images/likeEye.png").getPath());
Point pt1 = new Point(0,0);
Point pt2 = new Point(10,10);
Imgproc.line(src, pt1, pt2, new Scalar(30, 30, 40));

System.out.println(src.dump());

出力した配列の中身は「1px目のR,G,B,2px....」と並んでいるようです。

[ 30, 30, 40, 255, 255, 255, 。。。

あと、線を引くときは「Imgproc.line()」を使用すれば良いことがわかりました。

ソースコードはGITからダウンロードできます。

余談

白い色は「255」で黒は「0」になっています。サンプルの画像とデータです。

関連ページ一覧

  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)

Java OpenCV Lv3 〜画像に中央値フィルタ(medianBlur())〜

イントロダクション

前回、OpenCVを使ってイメージファイルから、文字列を取得するのを目標にOpenCVを学んできます。文字列を読み込むまでに機械学習も学ぶ(倒す)必要があるのでまずは、目の前の敵を倒します。今日の敵は「中央値フィルタ」

参考サイトはこちらです。そしてJavaDocAPI

実装

前回作成したコードの1行を変えるだけで実装は完了します。

/**
 * メインメソッド、書き方は決まっている。
 * イメージファイルを読み込んでぼかす Imgproc.blur()
 * 
 * @param argsプログラム引数
 */
public static void main(String[] args) {
	// ファイルの読み込み
	Mat mat = Imgcodecs.imread(
		OpenCVTest2.class.getClass().getResource("/images/Experience.png").getPath());
	// 出力用変数
	Mat source = new Mat();
	// ブラーする、種知力用の変数に値をセットする→「参照渡し」
	//Imgproc.blur(mat, source, new Size(2.0,2.0));
	// 中央値フィルタ
	Imgproc.medianBlur(src, dst, 7);
	// 自作のJFrame拡張クラス
	new ViewFrame(source);
}

上のコード赤字の部分が追加した行です。

<実行結果>



ま塩ノイズのような特異なノイズに対して効果的です.カーネルサイズは奇数でなければいけません

1行変えただけですからね(笑)。

Eclipse セットアップ

  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)

Java OpenCV Lv3 〜画像にガウシアンフィルタ(GaussianBlur())〜

イントロダクション

前回、OpenCVを使ってイメージファイルから、文字列を取得するのを目標にOpenCVを学んできます。文字列を読み込むまでに機械学習も学ぶ(倒す)必要があるのでまずは、目の前の敵を倒します。今日の敵は「ガウンシアンブラー?」

参考サイトはこちらです。そしてJavaDocAPI

実装

前回作成したコードの1行を変えるだけで実装は完了します。

/**
 * メインメソッド、書き方は決まっている。
 * イメージファイルを読み込んでぼかす Imgproc.blur()
 * 
 * @param argsプログラム引数
 */
public static void main(String[] args) {
	// ファイルの読み込み
	Mat mat = Imgcodecs.imread(
		OpenCVTest2.class.getClass().getResource("/images/Experience.png").getPath());
	// 出力用変数
	Mat source = new Mat();
	// ブラーする、種知力用の変数に値をセットする→「参照渡し」
	//Imgproc.blur(mat, source, new Size(2.0,2.0));
	// ガウシアンフィルタ
	Imgproc.GaussianBlur(mat, source, new Size(5, 5), 5.0);
	// 自作のJFrame拡張クラス
	new ViewFrame(source);
}

上のコード赤字の部分が追加した行です。

<実行結果>

見た目上、「何が違うの?」って感じですが、ボケ方が中心部と外側でボケ方が違います。

なんでも「注目画素との距離に応じて重みを変えるガウシアンカーネルを採用」するようで、白黒の雑音の除去に適しているようです。

簡単に終わってしまいました。

<余談>


DNSの設定が変わりWordPressにアクセスができなくなった経緯

昨日(2018/11/20)、このサイトにアクセスができなくなりました。

原因は、DNSの名前解決ができなくなっていたためです。

このブログをみてくれている人々にご迷惑をおかけしました。今後もブログを続けていくのでよろしくお願いいたします。

ちなみに、「DNSの名前解決ができなくなっていた」と記載しましたが経緯記載します。

  1. DNSにCNAMEレコードを追加
  2. 携帯で「zenryokuservice.com/wp」へのアクセスができなくなった
  3. 携帯で「takunoji.minim.ne.jp/wp」へのアクセスはできたが表示がいつもと違う
  4. 原因を探すが、わからないのでDNSプロバイダにログイン
  5. ネームサーバの名前が別のものに変わっていた

ここまでがブログにアクセスできなくなっていた原因でした。

Eclipse セットアップ

  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)

JavaDoc(クラスの使い方)

  1. JavaDoc 読解 〜 Filesクラス 〜
  2. Java Doc読解 BufferedReader
  3. Java Doc 読解〜BufferedWriter〜

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 Lv3 〜画像に中央値フィルタ(medianBlur())〜
  7. Java OpenCV Lv4 〜画像の中身をみてみる〜
  8. Java OpenCV Lv5 〜Matクラスで描画処理〜

Java OpenCV Lv3 〜画像の平滑化(smooth())〜

イントロダクション

前回は、Java Swingを使用してイメージファイルを表示しました。

次は、画像を加工して表示します。

参考サイトはこちらです。そしてJavaDocAPI

平滑化処理

<実行結果>

左のほうがSwingで表示したものです。ぼやけています。

Imgproc.blur(mat, source, new Size(10.0,10.0));

上の部分でぼやかしているのですが、いまいち理解できません。

Imgproc.blur(mat, source, new Size(2.0,2.0));

でやってみます。

Sizeの値が違うと、ボケ方も変わります。。。要するにSizeの値でボケ具合を調節できるということか。。。



次は、「ガウス〜」の処理をやります。

Eclipse セットアップ

  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 Lv3 〜画像に中央値フィルタ(medianBlur())〜
  7. Java OpenCV Lv4 〜画像の中身をみてみる〜
  8. Java OpenCV Lv5 〜Matクラスで描画処理〜

Java OpenCV Lv2 〜画像を表示する〜

インントロダクション

今までJavaFXだとか、根深いビデオキャプチャの問題があるとかやってきましたが。。。

OpenCVを学ぶのにそんなのはほっといても良いことに気がつきました。

単純に画像を表示できればOK!

参考サイト

https://www.tutorialspoint.com/opencv/opencv_gui.htm

<今までこんなことをやってきました。(OpenCV編)>

Eclipse セットアップ

  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())〜

<実行結果>

<実装したコードにコメント>


<作成したコード>

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.imgcodecs.Imgcodecs;

/**
 * @author takunoji
 *
 * 2018/11/18
 */
public class TrainOpenCV {
	static {
		// OpenCVライグラリ
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
	}
	public static void main(String[] args) {
		Mat image = Imgcodecs.imread(TrainOpenCV.class.getClass().getResource("/images/Experience.png").getPath());
		MatOfByte bytes = new MatOfByte();
		Imgcodecs.imencode(".png", image, bytes);
		byte[] b = bytes.toArray();
		InputStream in = new ByteArrayInputStream(b);
		BufferedImage buf = null;
		try {
			buf = ImageIO.read(in);
		} catch(IOException e) {
			e.printStackTrace();
		}
		// Create Swing Compoenent
		JFrame frame = new JFrame("Show Image");
		frame.getContentPane().add(new JLabel(new ImageIcon(buf)));
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.pack();
		frame.setVisible(true);
	}
}

明日から、こっちのコードでOpenCVの仕組みを学んでいこうと思います。

お疲れ様でした。

Java OpenCV Lv2 〜JavaFXでの画像表示〜

イントロダクション

前回は、写真などを表示しようと試みましたがImShowメソッドが使用できないということで、JavaFXを使用してやる方向にしました。

参考サイト;Java版OpenCVチュートリアル(英語です)

<工程>

  1. Eclipseのインストール
  2. OpenCVインストール
  3. JavaでOpenCVのライブラリを起動する(工程2の記事でやりました)
  4. JavaFXで写真を表示してみる(今回実行します)

画像(イメージ)表示の準備

こちらのサイトを参考にしてやります。

大雑把に上記の<工程>にあるようなことが書いてありました。今までに<工程>の1、2をやったので3からいきます。

<前提>

JavaFXでの画面作成のためにSceneBuiderをセットアップします。

  1. Eclipse SceneBuilderを追加する
  2. JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~


JavaFXの実装

ソースコードはGITにあるものを参照(参考サイトより)

<今回の作成するアプリ構成>

ソースはGitにアップロードしてあります。

<Main.java>

import org.opencv.core.Core;

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

/**
 * OpenCVnogaの学習用のGUIを作成する。
 * JavaFXで画面を作成している
 * 1.SceneBuilderでFXMLを出力
 * 2.FXMLで取得したコンポーネントを表示する
 * 
 * @author takunoji
 * 2018/11/18
 */
public class Main extends Application {
	/**
	 * このアプリケーション(Mainメソッド)が起動する前に
	 * 起動(OpenCVのロード)する
	 */
	static {
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
	}
	/**
	 * スーパクラスApplication)のstartメソッドを起動する
	 * オーバーライドしているので、本当は親クラスのメソッドが起動するが
	 * 子クラスで上書きするので、このクラスを起動した時にはこちらのメソッドが起動する。
	 */
	@Override
	public void start(Stage primaryStage) {
		try {
			// FXMLをロード
			BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("OpenCvTest.fxml"));
			// 表示領域を作成する
			Scene scene = new Scene(root,400,400);
			// JavaFX用のCSSを適用する
			scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
			// Sceneをステージに設定する
			primaryStage.setScene(scene);
			// 表示処理
			primaryStage.show();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * メインメソッド。
	 * JavaFXの規定部品
	 * Application{@link #start(Stage)}を起動する
	 * 
	 * @param args プログラム引数
	 */
	public static void main(String[] args) {
		// スーパークラス(親)のメソッドを起動する
		launch(args);
	}
}

<OpenCvController.java>

/**
 * FXMLで定義したコントローラクラス。
 * 参考サイトを写経しようとしたが、ソースを少しいじる
 * 基本的には写経している。
 * @see 
 * @author takunoji
 * 2018/11/17
 */
public class OpenCvController {
	 /** FXML定義のボタン */
	@FXML
	private Button button;
	/** FXML定義のImageViewer */
	@FXML
	private ImageView currentFrame;
	
	/** ビデオキャプチャ */
	private VideoCapture capture = new VideoCapture();
	
	private ScheduledExecutorService timer;
	// a flag to change the button behavior
	private boolean cameraActive = false;
	// the id of the camera to be used
	private static int cameraId = 0;
	
	/**
	 * ボタン押下時のアクション処理。
	 * "@FXML"アノテーションでFXMLとの同期を取っている
	 * @param event ボタン押下のイベント
	 */
	@FXML
	protected void startCamera(ActionEvent event) {
		// カメラがアクティブ状態の時は停止する
		if (this.cameraActive) {
			this.cameraActive = false;
			this.button.setText("Start Camera");
			this.stopAcquisition();
			// 処理終了
			return;
		}
		// カメラ
		this.capture.open(this.cameraId);
		// カメラが開いていない時
		if (this.capture.isOpened() == false) {
			// エラーログを出力して処理を終了する
			System.err.println("Impossible to open the camera connection...");
			return;
		}
		// カメラが正常に開いている時
		this.cameraActive = true;
		// 匿名クラス
		Runnable frameGrabber = new Runnable() {
			@Override
			public void run() {
				Mat frame = grabFrame();
				Image imageToShow = Utils.mat2Image(frame);
				updateImageView(currentFrame, imageToShow);
			}
		};
		this.timer = Executors.newSingleThreadScheduledExecutor();
		this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);
		this.button.setText("Stop Camera");
	}

	/**
	 * 開いているビデオストリームからフレームを取得する
	 * @return {@link Mat}
	 */
	private Mat grabFrame() {
		Mat frame = new Mat();
		if (this.capture.isOpened()) {
			try {
				this.capture.read(frame);
				if (frame.empty() == false) {
					Imgproc.cvtColor(frame, frame, Imgproc.COLOR_BGR2GRAY);
				}
				
			} catch(Exception e) {
				System.err.println("Exception during the image elaboration: " + e);
			}
		}
		return frame;
	}

	private void stopAcquisition() {
		if (this.timer != null && this.timer.isShutdown() == false) {
			try {
				this.timer.shutdown();
				this.timer.awaitTermination(33, TimeUnit.MICROSECONDS);
			} catch(Exception e) {
				// log any exception
				System.err.println("Exception in stopping the frame capture, trying to release the camera now... " + e);
			}
		}
		// @FIXME-[カメラを解放するだけで良い?]
		if (this.capture.isOpened()) {
			this.capture.release();
		}
	}
		/**
		 * Update the {@link ImageView} in the JavaFX main thread
		 * 
		 * @param view
		 *            the {@link ImageView} to update
		 * @param image
		 *            the {@link Image} to show
		 */
		private void updateImageView(ImageView view, Image image) {
			Utils.onFXThread(view.imageProperty(), image);
		}
		
		/**
		 * On application close, stop the acquisition from the camera
		 */
		protected void setClosed() {
			this.stopAcquisition();
		}
}

ボタンを押下したらエラーが出た!

下のキャプチャのようにbottunの変数名とIDが違っていると次のようなエラーが出ます。

 

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException

<BorderPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="zenryokuservice.opencv.fx.OpenCvController">
   <center>
      <BorderPane prefHeight="522.0" prefWidth="410.0" BorderPane.alignment="CENTER">
         <bottom>
            <Button fx:id="start_btn" mnemonicParsing="false" onAction="#startCamera" text="StartCamera" BorderPane.alignment="CENTER" />
         </bottom>
         <center>
            <ImageView fx:id="currentFrame" fitHeight="248.0" fitWidth="234.0" pickOnBounds="true" preserveRatio="true" BorderPane.alignment="CENTER" />
         </center>
      </BorderPane>
   </center>
</BorderPane>

上のコード赤字の部分を変数名に合わせます。「button」に修正。

<問題>

このVideoCaptureを起動し、閉じるときにメモリの使用量の部分(そのほかにもあるかも?)で問題があります。

ソースの方では、カメラを停止したときに「System.gc()」でメモリを解放するようにしたのですが、操作を早くするとクラッシュします。

この部分は、根深い問題なのでとりあえずは、飛ばしてOpenCVを学んでいくようにします。。。

エラーログ

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fffcfe13017, pid=1748, tid=0x000000000001560f
#
# JRE version: Java(TM) SE Runtime Environment (8.0_144-b01) (build 1.8.0_144-b01)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# C  [libobjc.A.dylib+0x7017]  objc_msgSend+0x17
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /XXX/git/OpenCvFX/OpeCvFX/hs_err_pid1748.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

 

関連ページ一覧

<JavaFXの準備>

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

Java OpenCv Lv1 〜入門: 写真の表示〜

イントロダクション

前々回に、家計簿アプリのグラフ部分を作成が一区切りついたので今度は入力部分を作成しようとOpenCvに着手しました。

今までにやってきたこと

そして、入力部分は手入力を行いたくないのでアプリケーションに入力させようと思うのです。つまり、アプリのユーザーはレシートの写真をとるだけ(カテゴリの追加などは別です)という仕様にしようと思い現在に至る次第です。

まずは、OpenCv in Javaと、JUnitのセットアップを行いました。

OpenCvを学ぶ

画像から文字を取得することが最優先なのですが、なんだかんだと初めから学ぶことになりそうなので初っ端から学び始めてしまおうと思います。※OpenGLをやった時に途中から学んだけど初めからやり直しました。。。

画像を表示する

上のツイート画像にある様にその本に書いてあることを実行します。よくわからなかったら、とりあえず進んで見れば良いのです。

※危険な事は神経質になった方が良い、痛い目にあいます。。。

そんなわけで、上記の18ぺーじにC/C++で書かれたソースがあります。そいつをJavaに書き換えて実行します。

駄菓子菓子、OpenCV3.XからはImShowメソッドが、HightGUIが使用できない(しない)仕様になったということで。。。

JavaFXで実装します。続きは以下参照でお願いします。

Eclipse SceneBuilderを追加する – PGボックス

www.youtube.com


JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~ – PGボックス

www.youtube.com

関連ページ一覧

  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 Lv3 〜画像に中央値フィルタ(medianBlur())〜
  7. Java OpenCV Lv4 〜画像の中身をみてみる〜
  8. Java OpenCV Lv5 〜Matクラスで描画処理〜
  9. Java OpenCV Lv6 〜Matクラスで背景から作成してみる〜
  10. Java OpenCV Lv7 〜MatクラスでEllipseしてみる〜
  11. Java OpenCV Lv9 〜画像編集「足し算」(cvAdd)〜
  12. Java OpenCV Lv9 〜画像編集「引き算」(cvSubtract)〜
  13. Java OpenCV Lv9 〜画像の掛け算〜
  14. Java OpenCV Lv10 〜行列演算Mat#submat()〜
  15. Java OpenCv Lv10〜画像の平均値をだす〜