2022年度情報メディア基礎ユニット1
項⽬B︓ヒューマンメディア1
3週目

課題1

Japan_Flag.java
import ij.*;
import ij.process.*;
import ij.gui.*;
import java.awt.*;
import ij.plugin.*;
import ij.plugin.frame.*;
  
public class Japan_Flag implements PlugIn {
	boolean dialogCanceled = false;
	int width = 0;
  
	private void doDialog() {
		GenericDialog gd = new GenericDialog("幅の指定");
		gd.addNumericField("国旗の幅:", width, 0);
		gd.showDialog();
  
		if (gd.wasCanceled()) {
			dialogCanceled = true;
		} else {
			width = (int)gd.getNextNumber();
		}
	}
  
	public void run(String arg) {
		doDialog();
		if (dialogCanceled) return;
  
		int height = width * 2 / 3;
		ImageProcessor ip = new ColorProcessor(width, height);
		ip.setColor(Color.white);
		ip.fill();
		
		int diameter = height * 3 / 5;
		int cx = width / 2, cy = height / 2;
		ip.setColor(Color.red);
		ip.fillOval(cx - diameter / 2, cy - diameter / 2, diameter, diameter);
  
		ImagePlus imp = new ImagePlus("Japan Flag", ip);
		imp.show();
	}
}
    

課題2のヒント

Test_4.javaを参考に、Adaptive_Bin.javaの関数runを完成させてください。

Test_4.java
import ij.*;
import ij.process.*;
import ij.gui.*;
import java.awt.*;
import ij.plugin.filter.*;
  
public class Test_4 implements PlugInFilter {
    boolean dialogCanceled = false;
    ImagePlus imp;
    int th = 0;
  
    private void doDialog() {
        GenericDialog gd = new GenericDialog("⼆値化の閾値の指定");
        gd.addNumericField("閾値:", th, 0);
        gd.showDialog();
  
        if (gd.wasCanceled()) {
            dialogCanceled = true;
        } else {
            th = (int)gd.getNextNumber();
        }
    }
  
    @Override
    public int setup(String arg, ImagePlus imp) {
        this.imp = imp;
        return DOES_8G;
    }
  
    @Override
    public void run(ImageProcessor ip) {
        doDialog();
        if (dialogCanceled) return;
  
        int height = ip.getHeight();
        int width = ip.getWidth();
        ImageProcessor ip2 = new ByteProcessor(width, height);
        ip2.setColor(Color.black);
        ip2.fill();
  
        for(int x = 0; x < width; x++) {
            for(int y = 0; y < height; y++) {
                int val = ip.getPixel(x, y);
                if (val > th) {
                    ip2.putPixel(x, y, 255);
                }
            }
        }
  
        ImagePlus imp2 = new ImagePlus("⼆値化(" + th + ")", ip2);
        imp2.show();
    }
}
    
Adaptive_Bin.java
import ij.*;
import ij.process.*;
import ij.gui.*;
import java.awt.*;
import ij.plugin.filter.*;
    
public class Adaptive_Bin implements PlugInFilter {
    boolean dialogCanceled = false;
    int n = 3;
    int c = 0;
  
    private float calcLocalMean(int x, int y, int n, ImageProcessor ip) {
        int height = ip.getHeight();
        int width = ip.getWidth();

        if (x >= 0 && x < width && y >= 0 && y < height) {
            float sum = (float)0;
            int total = (2 * n + 1) * (2 * n + 1);
            
            for (int yy = -n; yy <= n; yy++) {
                for (int xx = -n; xx <= n; xx++) {
                    if ((y + yy) >= 0 && (y + yy) < height && (x + xx) >= 0 && (x + xx) < width) {
                        sum = sum + ip.getPixel(x + xx, y + yy);
                    }
                }
            }

            return sum / total;
        }

        return (float)0.0;
    }
  
    private void doDialog() {
        GenericDialog gd = new GenericDialog("適応的二値化のパラメータ設定");
        gd.addNumericField("局所(片側) n:", n, 3);
        gd.addNumericField("局所的平均値から差し引く定数 c:", c, 0);
        gd.showDialog();

        if (gd.wasCanceled()) {
            dialogCanceled = true;
        } else {
            n = (int)gd.getNextNumber();
            c = (int)gd.getNextNumber();
        }
    }
  
    @Override
    public void run(ImageProcessor ip) {
        doDialog();
        if (dialogCanceled) return;
  
        int height = ip.getHeight();
        int width = ip.getWidth();
        ImageProcessor ip2 = new ByteProcessor(width, height); // 適応的二値化の結果を格納する変数

        // ip2 を黒色で塗りつぶす
        ip2.setColor(Color.black);
        ip2.fill();
  
        for(int x = 0; x < width; x++) {
          for(int y = 0; y < height; y++) {
              int val = ip.getPixel(x, y);
              // calcLocalMean関数を呼び出す時のパラメータを考えてください。
              float th = calcLocalMean( ? ) - c;
              if (val > th) {
                  ip2.putPixel(x, y, 255);
              }
          }
      }
  
      ImagePlus imp2 = new ImagePlus("適応的二値化(n=" + n + ",c=" + c + ")", ip2);
      imp2.show();
    }
  
    @Override
    public int setup(String arg0, ImagePlus imp) {
        return DOES_8G;
    }
  }
    

課題2(適応的二値化)の処理結果のサンプル

n=3, c=0 n=3, c=10 n=3, c=20
n=10, c=0 n=10, c=10 n=10, c=20
n=40, c=0 n=40, c=10 n=40, c=20

補足事項

VSCodeによるプラグイン開発

お世辞にもImageJのエディタは使いやすいとは言えません。 そこで、VSCodeによるプラグイン開発の方法をここで紹介したいと思います。

OpenJDKのインストール

  1. http://jdk.java.net/18/から、 以下の図の赤丸をクリックしてダウンロードします。

  2. ダウンロードされた「openjdk-18.0.1_windows-x64_bin.zip」ファイルを右クリックして、 表示されるメニューの中から「すべて展開(T)...」を選択して解凍します。

  3. 解凍して作成された「openjdk-18.0.1_windows-x64_bin」フォルダごと、 「C:\Program Files」に移動します。

VSCode(Visual Studio Code)のインストール

  1. https://azure.microsoft.com/ja-jp/products/visual-studio-code/から、 VSCode(Windows, 64-bit, User Installer)の最新版をダウンロードします。


  2. ダウンロードされた「VSCodeUserSetup-x64-1.66.2.exe」ファイルをダブルクリックして、 インストールします。






  3. VSCodeが起動しますが、終了します。

VSCodeの日本語化

  1. デスクトップのアイコンをダブルクリックして、VSCodeを起動します。
  2. 日本語化する前に、画面の名称が以下のようになっていることをお伝えしておきます。

  3. アクティビティバーの上から5番目のアイコンを選択します。

  4. サイドバー上部のテキストボックスに、「japan」と入力します。 すると、下図のようにサイドバーの表示内容が変わるので、 一番先頭の拡張機能の「Install」ボタンをクリックします。

  5. しばらくすると、エディタグループに表示されている日本語化の拡張機能のそばに「Uninstall」ボタンが表示されます。 これで、インストールは完了したことになります。 実際に日本語化するためには、 右下に表示されているダイアログの「Restart」ボタンをクリックします。


  6. 再起動後のVSCodeは、下図のように日本語化されています。

VSCodeのJavaプログラミング環境構築

  1. アクティビティバーの上から5番目のアイコンを選択します。

  2. サイドバー上部のテキストボックスに、「java」と入力します。 すると、下図のようにサイドバーの表示内容が変わるので、 一番先頭の拡張機能の「インストール」ボタンをクリックします。

  3. しばらくすると、エディタグループの表示が下図のようになります。 これで、インストールは完了したことになります。 今回は、再起動は必要ありません。

  4. エクスプローラで「C:\Program Files\openjdk-18.0.1_windows-x64_bin\jdk-18.0.1」を開き、 直下にあるファイルもしくはフォルダを選択し、右クリックします。 すると、メニューが表示されるので、「プロパティ(R)」を選択します。

  5. 表示されるダイアログの「場所:」を選択し、選択行の上で右クリックします。 すると、メニューが表示されるので、「コピー(C)」を選択します。 このダイアログはもう必要ないので、「OK」ボタンをクリックして閉じます。

  6. VSCodeのメニュー「ファイル」-「ユーザー設定」-「設定」を選択します。 エディタグループ上部のテキストボックスに「java:home」と入力します。 すると、「Java>Jdt>Ls>Java:Home」という項目が見つかります(青枠)。 その下にある「settings.jsonで編集」というリンクをクリックします(赤丸)。

  7. 下図のような設定ファイルの内容が、エディタグループに表示されます。 右側の「"」で囲まれたところにカーソルを移動し、コントロールキーを押しながら「v」を押します。 すると、先ほどコピーした文字列が貼り付けられます。 この文字列中のバックスラッシュ(スラッシュを左右反転した記号)の箇所にバックスラッシュをもう一文字追加してください。 バックスラッシュは\キーで入力できます。 最後に、メニュー「ファイル」-「保存」を選択して、編集した内容を保存します。



VSCodeによるプラグイン・プログラミング

準備として、ドキュメントの下に「java」フォルダを作ります。 このフォルダの下に、プロジェクトごとにフォルダを作成してプログラムを格納していくことになります。 今回は、「kisounit1」というプロジェクトを1つ作成します。 「kisounit1」プロジェクトに、3週目で作成するプラグインのプログラムすべてを格納することができます。 また、ここではテキストの最初に出てくるサンプルのプラグインTest_1.javaを題材として用いることにします。

  1. VSCodeのメニュー「表示」-「コマンドパレット...」を選択し、 上部テキストボックスに「create java」と入力します。 すると、「Java:Create Java Project...」という項目が表示されるので、選択します。

  2. すると、下図のような選択肢が表示されます。 ここでは、「No build tools」を選択します。

  3. フォルダを選択するダイアログが表示されるので、 ドキュメントの下の「java」フォルダを選択します。 そして、「Select the project location」ボタンをクリックします。

  4. プロジェクト名を入力するテキストボックスが表示されるので、 「kisounit1」と入力してエンターキーを押します。

  5. 次のようなダイアログが表示されたら、 青丸の箇所にチェックを入れ、 赤丸のボタンをクリックします。

  6. サイドバーに、作成された階層的なフォルダ構造が表示されます。 「lib」フォルダは、外部ライブラリを格納する場所です。 今回は、ImageJのライブラリ「ij.jar」を「lib」フォルダにコピーする必要があります。 「ij.jar」は、ImageJ.exeと同じフォルダにあります。

  7. 次に、サイドバーの「src」フォルダをクリックし、 下図の赤丸のアイコンをクリックします。 すると、新しいファイルが作成され、 ファイル名が空になっているので「Test_1.java」と入力してエンターキーを押します。 すると、「Test_1.java」という名前が確定し、 エディタグループに当該ファイルの編集ウィンドウが表示されます。


  8. テキストから冒頭のimport命令群をコピぺします。

  9. import命令群の下に、「public class Test_1 implements P」と入力すると、 選択リストが表示されます。 ここでは、「PlugIn」をマウスでクリックします。

  10. 「PlugIn」というインターフェースが挿入されます。 次いで、「{}」を入力し、「{」の後にエンターキーを押します。


  11. クラス名「Test_1」を右クリックすると、メニューが表示されます。 「クイックフィックス...(Ctrl+.)」をクリックします。

  12. 下図のように、「Add unimplemented methods」ボタンが表示されるので、クリックします。

  13. すると、下図のように「PlugIn」インターフェースで定義されているメソッドが挿入されます。

  14. 「public void run()」メソッドの中のコメントを削除し、 テキストから当該メソッドの中身をコピペし、タブキーにより適宜インデントを挿入します。 そして、メニュー「ファイル」-「保存」を選択して保存します。

  15. 下図のように、import文の数か所に黄色のアンダーラインが引かれているが、 これは警告なので気にする必要はありません(機能していないimport文であることを示している)。 この時点で、サイドバーの「bin」フォルダをクリックすると、 「Test_1.class」ができていることがわかります。 VSCodeでは、逐次コンパイルが行われているのです。


  16. 「src」フォルダ直下に「RunTest_1.java」ファイルを作成し、下記プログラム・リストからコピペします。

    import ij.*;
      
    public class RunTest_1 {
        public static void main(String[] args) {
            ImagePlus imp = IJ.openImage("C:/Users/yama/Desktop/dave.png");
            IJ.runPlugIn(imp, "Test_1", "");
        }
    }
            
  17. 下図の青丸の下向きの矢印をクリックすると、メニューが表示されます。 「Run Java」をクリックします。 すると、ネットワークへの接続を許可するか確認するダイアログが表示されるので、 許可します。 そして、プラグインの実行画面が表示されます。


  18. ここから、ImageJに組み込む話をします。 まず、VSCodeの編集ファイルの漢字コードは、UTF-8(ユニコード)です。 一方、ImageJのコンパイラは、シフトJISの漢字コードに対応しています。 Test_1.javaには、日本語は使われていませんが、今後のことを考えて、 シフトJISへの変換方法を説明しておきます。 変換対象のファイル(ここでは、Test_1.java)を開いた状態で、 「UTF-8」と表示されている箇所をクリックします。

  19. 下図のような選択肢が表示されるので、「エンコード付きで保存」をクリックします。 すると、また別の選択肢が表示されるので、「Japanese (Shift JIS)」をクリックします。 これで、Sift JISへの変換が完了しました。


  20. ImageJシステムの直下の「plugins」フォルダの下に、「kisounit1」フォルダを作成します。 そこに、「Test_1.java」をコピーします。

  21. ImageJのメニュー「Plugins」-「Compile and Run...」を選択し、 表示されるダイアログで「kisounit1」フォルダの下にある「Test_1.java」を選択します。

  22. コンパイルされた後、実行されます。

  23. ImageJのメニュー「Help」-「Refresh Menus」を選択すると、 下図のようにメニューに当該プラグインの項目が配置されます。