白旗製作所

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
  1. --/--/--(--) --:--:--|
  2. スポンサー広告

Java Executor Frameworkでマルチスレッド

以前,Javaでマルチスレッドという記事を書きました.
当時はGUIとバックグラウンドを別スレッド処理するという目的だったので,
Threadクラスで別処理の内容を1スレッドずつコツコツ書いていました.

今度は多数のスレッドを作成してマルチコアで並行して同様の処理を行なうコードを書きたかったので,
Executor Frameworkを使ってみました.

Javaでマルチスレッド処理を行うフレームワークには様々なものがある様なのですが,
今回は再帰処理をするわけでもなく,同期処理をする必要もないので,
シンプルなExecutor Frameworkを選択しました.

参考:
さあ、並列プログラミングをはじめよう
Executorフレームワークの使い方

使い方としては,参考記事にもありますが,Runnableクラスのインスタンス
もしくはRunnableクラスをimplementしたクラスを用意して,
ExecutorService.executeに突っ込む,という方法です.

ExecutorServiceの生成時にスレッド数を指定してやれば,
executeするたびに1つのスレッドに処理を割り当ててくれます.
はみ出た処理は待機され,処理が終わって空いたスレッドに
順次未実施の処理が割当たります.

下では,スレッド数を8としてExecutorで処理を行うサンプルです.
10の処理をexecuteする(hoge.length=10)場合,下に示すように順次実行される様子が見れます.




[実行結果]
pool-1-thread-1開始
pool-1-thread-3開始
pool-1-thread-2開始
pool-1-thread-4開始
pool-1-thread-8開始
pool-1-thread-7開始
pool-1-thread-5開始
pool-1-thread-6開始
pool-1-thread-8終了
pool-1-thread-8開始
pool-1-thread-3終了
pool-1-thread-3開始
pool-1-thread-5終了
pool-1-thread-1終了
pool-1-thread-2終了
pool-1-thread-6終了
pool-1-thread-4終了
pool-1-thread-3終了
pool-1-thread-7終了
pool-1-thread-8終了


上記のサンプルではRunnableをimplementするクラスを作成しましたが,
簡単に記述できる処理や値を渡す必要が無い場合,
Runnableクラスのインスタンスを生成するだけでもOKです.

Runnable command = new Runnable() {
  public void run() {
    String threadName = Thread.currentThread().getName();
    System.out.println(threadName+"開始");
    evaluate();
    System.out.println(threadName+"終了");
  }
};

スポンサーサイト
  1. 2018/01/02(火) 14:36:06|
  2. Java
  3. | トラックバック:0
  4. | コメント:0

java.nio.file.Filesを使ったフォルダコピー

これまでファイルコピーはjava.io.Fileを使っていたのですが,
どうやらファイル操作のライブラリは新しくなっていたらしく,色々楽そうなので使ってみることにしました.

ファイルコピーやフォルダの再帰探索は容易に行うメソッドが容易されているので,
これを使ってフォルダ内のサブフォルダを含めたコピーメソッドを作成してみました.

walkFileTreeをつかってフォルダの中身を辿り,
FileVisitorでフォルダを事前にコピー,その後ファイルをコピーします.
コピー先のファイル/フォルダパスは,FileVisitor内のパスには含まれないので,
コピー先のディレクトリ名を使って指定してやります.
そのためにrelativizeメソッドとresolveメソッドを用います.

参考:
これからの「Java I/O」の話をしようwww (1) : Path インターフェース, Paths クラス
Java SE 7のjava.nio.file.Filesがとても便利な件


  1. 2018/01/02(火) 01:40:34|
  2. Java
  3. | トラックバック:0
  4. | コメント:0

スキャン画像のモアレ除去のための、ぼかしとアンシャープマスク処理

CDのジャケット等の印刷物をスキャナでスキャンすると、
以下の画像の様にモアレが発生します。
(本画像はCQ出版「定本 トランジスタ回路の設計」表紙画像のスキャン画像の一部です。
ダウンロードして拡大するとモアレがよりよく見えます。)
moire50.png


これは、印刷する際に、あるdpiで印刷していて、
それを異なるdpiで読み取るために、ズレが周期的に発生して
干渉縞ができるためです。

ふつう、スキャナにはこれを除去するモアレ除去という
機能が付いているのですが、安物の機種にはついていなかったり、
ついていてもONOFFのみなど、調整ができなかったりします。
これを調整できるようにしようかと思い、javaでプログラムを作成しました。


AdobeのHPを見ると、『画像に「ぼかし(ガウス)」を加えてから
「アンシャープマスク」で引き締める 2 つのフィルタを適用する
方法が効果的です。』とあります。
スキャン画像のモアレの解消方法
https://helpx.adobe.com/jp/x-productkb/multi/216043.html


おそらく普通のスキャナにも、こういった処理がついていて、
パラメータが固定値になっているのではないでしょうか。

というわけで、Javaで「ぼかし」と「アンシャープマスク」の
2つを実装してみます。


こういった処理にはJava 2D APIを使用するのが良いようです。
コンボリューションを用いた画像の平滑化、鮮鋭化とエッジ検出
http://codezine.jp/article/detail/129


ここでいう「平滑化」が「ぼかし」で「鮮鋭化」が
「アンシャープマスク」ですね。オペレータを作って
Java 2D APIで畳み込みをすればこれらの処理が実現できます。

この例では3×3のオペレータの例しか載っていませんが、
実際は記述されている通り7×7や15×15くらいのサイズが必要ですので、
オペレータを作成する処理が別途必要です。

ここでは、この記事に書いてあるように、ガウス分布(正規分布)を
使って、範囲を分散σ^2で調整できるようなオペレータを作成します。
また、オペレータのサイズも自由に変更できるようにします。

サイズとσ値は調整が必要です。とりあえず、サイズ15、σ2で
ぼかしとアンシャープマスクをかけると、記事冒頭の画像が以下のようになります。
moireremoved50.png

ややボケた感じが残っていますが、最初に目立っていた周期的な
モアレノイズはかなり低減できていると思います。
あとはパラメータ調整と、別のシャープ化処理とかを実装すれば、
そこそこ実用的になるのではと思います。


以下、今回作成したサンプルコードです。
一部に、私のオリジナルのライブラリ関数が使われてるので注意してください。


/**
* 正規分布をつかってオペレータを作る
*/
public static Matrix gausianOperator( int size, double sigma )
{
//サイズが奇数でなければエラー
if( size%2 == 0 ) return null;

//オペレータをつくる
Matrix operator = new Matrix(size, size);

double distance;
int center = size/2;
//各マスに正規分布の値を入れる
for(int r=0; r<size; r++){
for(int c=0; c<size; c++){
distance = Math.hypot(r-center, c-center);//中央からの距離を計算
operator.set(r, c, Numeric.normalDistribution(distance, 0, sigma)); //正規分布の値をセット
}
}

//全部の値の合計が1になるように調整
operator = operator.multiply(1/operator.sum());

return operator;
}
/**
* BufferedImageの画像を畳み込みする
*/
public static BufferedImage convolution( BufferedImage image, Matrix operator,int type)
{
//オペレータをfloat[]に変換する準備をする
Vector temp = new Vector(0);
int size = operator.length();
for(int i=0; i<size; i++) temp = temp.add(operator.getRow(i));

//畳み込む
Kernel kernel=new Kernel(size,size,Cast.doubleToFloat(temp.get()));
ConvolveOp convolveOp;
if(type==1)
convolveOp=new ConvolveOp(kernel,ConvolveOp.EDGE_ZERO_FILL,null);
else
convolveOp=new ConvolveOp(kernel,ConvolveOp.EDGE_NO_OP,null);
BufferedImage output=convolveOp.filter(image,null);
return output;
}

/**
* 画像を平滑化する<br>
*/
public static BufferedImage smooth( BufferedImage image, int size, double sigma )
{
//オペレータを作成する
Matrix operator = gausianOperator( size, sigma );

//オペレータを使って畳み込みする
return convolution(image, operator, 0);
}

/**
* 画像を鮮鋭化する<br>
*/
public static BufferedImage sharpen( BufferedImage image, int size, double sigma )
{
//オペレータを作成する
Matrix operator = gausianOperator( size, sigma );

//オペレータをアンシャープマスクにする
operator = operator.multiply(-1);
operator.set(size/2, size/2, (2-operator.get(size/2, size/2)*(-1)) );

//オペレータを使って畳み込みする
return convolution(image, operator, 0);
}

public static void main(String[] args)
{
BufferedImage target = ImageUtility.read("test.csv");
BufferedImage smoothed = ImageProcessing.smooth(target, 15, 2);
BufferedImage shaped = ImageProcessing.sharpen(smoothed,15, 2);

ImageUtility.save(shaped , "test2.csv");
}


  1. 2015/08/23(日) 23:07:03|
  2. Java
  3. | トラックバック:0
  4. | コメント:0

Javaでマルチスレッド

JavaでGUIを触っていて、重めの処理をしたときにGUIが固まってしまい、
処理がおわるまで反応しなくなったことがありました。

これを避けるには、処理を別スレッドにすれば良いということで、
マルチスレッド化をしましたので、それについて少しメモしておきます。

現在のスレッドと別のスレッドを用意して処理させるには、基本的に以下を書けばよいです。

【GUIのクラス内の処理】
  Test test = new Test();
  Thread thread = new Thread(test);
  thread.start();

【重い処理を記述するクラス】
public Test implements Runnable{
  ...
  public void run(){
  hogehoge(); //何か重い処理
  }
  
  private void hogehoge(){
    ...
  }
}

何をやっているのかというと、GUIクラスでは
Thread thread = new Thread(test)
の箇所で、Testクラスのインスタンスtestを使って、threadという新たなスレッドを作り、
thread.start();
で、test.run()をスレッドthread内で動かしています。

Testクラスでは、run()の中に、別スレッドで行わせたい処理hogehoge()を書いておき、
Runnableというインターフェースをimplements しておきます。


こうすることで、重い処理であるhogehoge()を別スレッドで呼び出すことができるため、
GUIが固まることを回避できます。


上記ではGUIクラスから別スレッドを呼び出しましたが、
当然ながら、GUIクラスを別スレッドとして生成してもよいでしょう。


また、わざわざ別クラスを用意するほどでもなかったりする場合、
以下のようにRunnable()クラスのインスタンスを作って、直接処理を記述することも可能です。

Thread thread = new Thread(new Runnable(){
  public void run(){ hogehoge(); }
});
thread.start();



  1. 2015/03/08(日) 22:18:48|
  2. Java
  3. | トラックバック:0
  4. | コメント:0

JavaでJPEGのEXIF情報を読み取り

JPEG写真のEXIF情報をまとめて持ってくるため、
Javaで取得をしてみました。

EXIF情報取得には、METADATA EXTRACTORという
便利なライブラリがあるのでこれを使わせてもらいます。

EXIF情報は、情報によって格納されているディレクトリが異なるらしいので、
まずJPEGのメタデータを読み込んだあと、必要なディレクトリを読み込んで、情報を取り出します。
EXIF情報には何があるか、情報のタグ名、タグIDがどのようになっているかは、このサンプルが参考になります。

METADATA EXTRACTORを使ってJavaでEXIF情報読み込む例はこことかここにあるのですが、
情報が古く、最新のライブラリの仕様は変わっていてコードがそのままでは使えないため、
ライブラリの仕様に合わせてプログラムを変更します。
またいつ仕様も変更になるかわからないので、githubのGettingStartedを参考にするとよいでしょう。

試しに、以下のデータを読みだした例を置いておきます。
・カメラメーカー
・カメラモデル
・絞り値
・露出時間
・ISO感度
・露出
・焦点距離
・撮影日時

------------------------------------------
import java.io.File;
import java.util.Date;

import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifIFD0Directory;
import com.drew.metadata.exif.ExifSubIFDDirectory;

public class Main {
public static void main(String[] args) {

// メタデータを読み込み
File jpegFile = new File(fileName);
Metadata metadata = ImageMetadataReader.readMetadata(jpegFile);

// EXIFのディレクトリ(情報種類)を読み込み
ExifIFD0Directory ifdDirectory = metadata.getDirectory(ExifIFD0Directory.class);
ExifSubIFDDirectory subIfdDirectory = metadata.getDirectory(ExifSubIFDDirectory.class);

// タグの値を読み込み
String maker = ifdDirectory.getString(ExifIFD0Directory.TAG_MAKE);
String cameraModel = ifdDirectory.getString(ExifIFD0Directory.TAG_MODEL);
String fNumber = subIfdDirectory.getString(ExifSubIFDDirectory.TAG_FNUMBER);
String exposureTime = subIfdDirectory.getString(ExifSubIFDDirectory.TAG_EXPOSURE_TIME);
String ISO = subIfdDirectory.getString(ExifSubIFDDirectory.TAG_ISO_EQUIVALENT);
String exposureBias = subIfdDirectory.getString(ExifSubIFDDirectory.TAG_EXPOSURE_BIAS);
String foculLength = subIfdDirectory.getString(ExifSubIFDDirectory.TAG_FOCAL_LENGTH);
Date date = subIfdDirectory.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);

System.out.println(maker);

}
}
  1. 2014/11/30(日) 09:16:26|
  2. Java
  3. | トラックバック:0
  4. | コメント:0
次のページ
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。