20190126のJavaに関する記事は4件です。

化合物の記述子:CDKを計算してみた

この記事、何?

いろいろやりたいのですが、まずは元のデータがないとね。
ひとまず、RDKit使うつもりだけど別ネタということでCDKを。

■CDK (ver 1.4.6)
http://www.rguha.net/code/java/CDKDescUI-1.4.6.jar

いや、Javaとかjarとか正直知らなかったので結構苦労したので。
っていうか、CDKの引数もよくわからんかったし。。

どういう人向け?

いや、やっぱり自分あてなんですけどね。
ただ、コマンド一つで行けるところまで行ってるのでそのまま使えるならどうぞ。

試した環境は?

Windows 8 Pro (x64)
jdk-11.0.2

やりたいこと

だからCDKの計算。

やったこと

時系列に示すと、こんな。

1.ファイル入手

これは上記URLから
CDKをGUIで計算できるという話を聞き、まずは「CDK GUI」で検索。
ほんとは出てきた1.4.8にしてもよかったんだけど、とある理由で1.4.6で。
でもツールで使いたかったのでCUI版動作で。

2.Javaからの呼び出し

java.exe -jar xxxxxx.jar
でjarファイルの実行を指示できるそうな。そうなんだぁ・・・へぇ・・・ありがとう。
そしたらあっさりGUI版が起動。
とりあえずいくつか計算できることを試せたけど、欲しいのはCUI動作。
java.exe -jar CDKDescUI-1.4.6.jar -h
であれこれヘルプが出たのでそれを参考に・・・

・・・

で、できたのがこれ。
ほんとは可読性優先で経過ログとかの行を間引くべきでしょうけど、コピペで使えるようにしておきたいと思ったので。

echo "just start"
echo %time%

echo " --- descriptors ---"
echo %time%
java -jar CDKDescUI-1.4.6.jar -t all          -o descriptors.csv    Compound_000000001_000025000.sdf -b

echo " --- f_estate ---"
echo %time%
java -jar CDKDescUI-1.4.6.jar -f estate       -o f_estate.csv       Compound_000000001_000025000.sdf -b

echo " --- f_extended ---"
echo %time%
java -jar CDKDescUI-1.4.6.jar -f extended     -o f_extended.csv     Compound_000000001_000025000.sdf -b

echo " --- f_graph ---"
echo %time%
java -jar CDKDescUI-1.4.6.jar -f graph        -o f_graph.csv        Compound_000000001_000025000.sdf -b

echo " --- f_standard ---"
echo %time%
java -jar CDKDescUI-1.4.6.jar -f standard     -o f_standard.csv     Compound_000000001_000025000.sdf -b

echo " --- f_pubchem ---"
echo %time%
java -jar CDKDescUI-1.4.6.jar -f pubchem      -o f_pubchem.csv      Compound_000000001_000025000.sdf -b

echo " --- f_substructure ---"
echo %time%
java -jar CDKDescUI-1.4.6.jar -f substructure -o f_substructure.csv Compound_000000001_000025000.sdf -b

echo " --- f_signature ---"
echo %time%
java -jar CDKDescUI-1.4.6.jar -f signature    -o f_signature.csv    Compound_000000001_000025000.sdf -b

echo " --- f_circular ---"
echo %time%
java -jar CDKDescUI-1.4.6.jar -f circular     -o f_circular.csv     Compound_000000001_000025000.sdf -b

echo "finished"
echo %time%

なんとなくのぼやき?

GUIとCUIで出力できる情報が違うの・・・なんか間違ったかな?
正直、DescriptorsをGUIとCUIの両方で出してみてファイルを比較してびっくり。
CrLfとLfが違うとかそんなレベルじゃなく、列の並び順自体が違う。。。
いや、各列を列名でDBに落としてゆけば、ファイル内で整合性が取れているならそれでも・・・

ん・・・それでも気味が悪いけど。

ぼやきの蛇足

Java有償化って、非Windowsの最大のメリットがなくなったように感じてる。
っていうか、.netもpowershellもLinuxで動くみたいだしね。
Windows系べったりなあたしからするとJavaに感じていた魅力はC#で代替可能なので
Javaなくてもいいかな・・・と。
違うよ、なくなったらJava依存のCDKって使えなくなっちゃうじゃん?まあ、なくなることはないでしょうね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Spring Cloud Streamのデモを公開しました

GitHubに公開しました!

各ファイルにTODOが書いてあるので、それに従って進めることで体験できます。

https://github.com/MasatoshiTada/spring-cloud-stream-demo

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaでOpenCVのカメラキャリブレーション(CameraCalibration)をやった

はじめに

カメラキャリブレーションというものが必要になったのでやってみました。

カメラキャリブレーション(CameraCalibration)とは

空間の位置と画像上の位置を変換できる式がありますが、これはカメラのパラメーターが必要です。
カメラパラメーターには種類があり、大きく内部パラメーターと外部パラメーターに分けられます。
また、内部パラメーターに含まれるのかわからないですが、レンズ歪み係数(歪曲収差)というものもあります。

内部パラメーター

内部パラメーターとは、「カメラによって決定されるパラメーター」です。
・焦点距離 f
・画素の物理的な間隔 δu, δv
・正規化座標に対する画像座標における画像中心 cu, cv

外部パラメーター

外部パラメーターとは、「ワールド座標系に対するカメラの位置と姿勢のパラメーター」です。
・回転行列 R3
・平行移動ベクトル t3

カメラキャリブレーションとは

さて、カメラキャリブレーションとは、このカメラのパラメーターを求めることです。
この際に得られる、内部パラメーターと外部パラメーターを合わせて、カメラ行列または透視投影行列と言います。

手法としては、予め位置がわかっている空間点と、その画像上への投影点(つまり、画像上の座標)を行列の式に当てはめて決定するします。

具体的に言えば、キャリブレーションターゲット(チェスボードなど)を動かしながら写真を撮影します。
チェスボードの格子の長さが既知であるため、格子点間の距離がわかり、空間上の位置が定まります。(逆に言えば、ワールド座標系を定めます)
また、画像上でも格子点の座標を取得します。(画像座標の取得)
画像を複数枚撮影し、最小二乗法を用いて、パラメーターを求めます。

引用(参考)元: 「ディジタル画像処理[改訂新版]」, なお都合より表現を改変している。
参考: カメラキャリブレーションと3次元再構成 - OpenCV.jp

OpenCVでカメラキャリブレーションを行う

今回は比較的簡単だと思う、チェストボードによるカメラキャリブレーションを以下の大まかな手順で行いました。

コードについてはOpenCV_CameraCalibration - GitHubを参照してください。

  1. ワールド座標系と空間上の格子点の座標を定める
  2. 画像上のチェストボードの格子点の座標を求める [Calib3d.findChessboardCorners()を利用]
  3. Calib3d.calibrateCamera()を実行する
  4. 返された カメラ行列とレンズ歪み係数を保存する 概要はこのような感じである。

それぞれについて少し詳しく解説します。

ワールド座標系と空間上の格子点の座標を定める

ワールド座標系を、平面なキャリブレーションターゲット(チェストボード)の平面がZ=0となるように任意に定めます。
このときに格子点の間隔を測って、mm単位でPointを定めます。
ここで呼び出ししています。

List<Mat> objectPoints = getObjectPoints(outputFindChessboardCorners.size(), patternSize); // チェスボードのコーナーの三次元座標(z=0)を、撮影画像枚数分入れる。

OpenCV_CameraCalibration_L68 - GitHub

getObjectPoints()の中身は以下のようになっています。

    public List<Mat> getObjectPoints(int size, Size patternSize) {
        List<Mat> objectPoints = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            objectPoints.add(getObjectPoint(patternSize));
        }
        return objectPoints;
    }

    public MatOfPoint3f getObjectPoint(Size patternSize) {
        MatOfPoint3f objectPoint = new MatOfPoint3f();

        List<Point3> objectPoint_ = new ArrayList<>();
        // final Size patternSize = new Size(6, 9); // 探査するコーナーの数
        for (int row = 0; row < patternSize.height; row++) {
            for (int col = 0; col < patternSize.width; col++) {
                objectPoint_.add(getPoint(row, col));
            }
        }

        objectPoint.fromList(objectPoint_);
        return objectPoint;
    }

    public Point3 getPoint(int row, int col) {
        final double REAL_HEIGHT = 20.0, REAL_WIDTH = 20.0;
        return new Point3(col * REAL_WIDTH, row * REAL_HEIGHT, 0.0); // 多分x, y, zはこういう感じ。
    }

OpenCV_CameraCalibration_L96 - GitHub

画像上のチェストボードの格子点の座標を求める

自分で、findChessboardCorners()というメソッドを書きました。呼び出しは以下のようになっています。

        List<Mat> outputFindChessboardCorners = new ArrayList<>();
        try (DirectoryStream<Path> ds = Files.newDirectoryStream(picFolderPath)) {
            for (Path path : ds) {
                System.out.println(path.toString());

                final Optional<Mat> outputMat = findChessboardCorners(path.toString(), imagePoints, patternSize);

                if (outputMat.isPresent()) {
                    outputFindChessboardCorners.add(outputMat.get());
                    System.out.println("successful to find corners.");
                } else {
                    System.err.println("unsuccessful to find corners.");
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }

OpenCV_CameraCalibration_L50 - GitHub

findChessboardCorners()の中身は以下のようになっています。
Calib3d.findChessboardCorners()というメソッドを利用しました。
なお、返却しているMatは、Calib3d.findChessboardCorners()が正常に実行できた画像が入っています。

    public Optional<Mat> findChessboardCorners(String picPathString, List<Mat> imagePoints, Size patternSize) {
        Mat inputMat = Imgcodecs.imread(picPathString);
        Mat mat = inputMat.clone();
        // final Size patternSize = new Size(6, 9); // 探査するコーナーの数
        MatOfPoint2f corners = new MatOfPoint2f(); // in, 検出されたコーナーの二次元座標のベクトルを受け取る。

        Imgproc.cvtColor(inputMat, inputMat, Imgproc.COLOR_BGR2GRAY);

        final boolean canFindChessboard = Calib3d.findChessboardCorners(inputMat, patternSize, corners);

        if (!canFindChessboard) {
            System.err.println("Cannot find Chessboard Corners.");
            return Optional.empty();
        }

        imagePoints.add(corners);

        Calib3d.drawChessboardCorners(mat, patternSize, corners, true);

        Path picPath = Paths.get(picPathString);
        Path folderPath = Paths.get("S:\\CameraCaliblation\\2018-12-31_output");
        Path path = Paths.get(folderPath.toString(), picPath.getFileName().toString());

        if (!Files.exists(folderPath) || !Files.isDirectory(folderPath)) {
            try {
                System.out.println("There was no folder, so it is createing a folder. : " + folderPath.toString());
                Files.createDirectory(folderPath);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        Imgcodecs.imwrite(path.toString(), mat);

        return Optional.of(inputMat);
    }

Calib3d.calibrateCamera()を実行する

先程用意した空間上の格子点の座標と、先程求めた画像上のチェストボードの格子点の座標を引数として、Calib3d.calibrateCamera()を実行します。
また、このメソッドでカメラ行列とレンズ歪み係数の値が返されるので、それを格納する変数を作っておきます。

        // 受け取るもの
        Mat cameraMatrix = new Mat(), distortionCoefficients = new Mat();
        List<Mat> rotationMatrixs = new ArrayList<>(), translationVectors = new ArrayList<>();

        Calib3d.calibrateCamera(objectPoints, imagePoints, imageSize,
                cameraMatrix, distortionCoefficients, rotationMatrixs, translationVectors);

OpenCV_CameraCalibration_L81 - GitHub

返された カメラ行列とレンズ歪み係数を保存する

カメラ行列とレンズ歪み係数を取得できましたが、この処理を毎回行うのは面倒かつ無駄なので、行列の値を保存しましょう。
CやPythonならはOpenCV側でMatの値を入力・出力するものがあるのですが、Java版ではないので、自分で今回は作りました。
Javaの標準ライブラリにあるXMLの入出力を使いました。

        Map<String, Mat> exportMats = new HashMap<>();
        exportMats.put("CameraMatrix", cameraMatrix);
        exportMats.put("DistortionCoefficients", distortionCoefficients);
        final Path exportFilePath = Paths.get("S:\\CameraCaliblation\\CameraCalibration_2018-12-31.xml");
        MatIO.exportMat(exportMats, exportFilePath);

OpenCV_CameraCalibration_L87 - GitHub

MatIOの中身は、OpenCV_CameraCalibration_MatIO.java - GitHub を参照してください。

おわりに

一応、これを使って、ArUcoのARマーカーの姿勢推定 を行ったところ、正常に動作しました。
我が部の情報班の後輩にも理解&実行してもらい、成功しましたので良かったです。

参考リンク

OpenCV - カメラキャリブレーションを行う方法 - Pynote
カメラキャリブレーション (OpenCV 1.0) - OpenCV.jp
OpenCVとVisual C++による画像処理と認識
pythonとOpenCVでカメラキャリブレーション(1個のカメラの内部パラメータと歪み係数を求める)するコード(パクリ)
カメラ校正
OpenCV 2.4.11&C++によるカメラキャリブレーション - 技術的特異点
Camera Calibration and 3D Reconstruction - OpenCV公式- 改めて公式サイト見ると良い説明ありますね。
CC_Controller.java - opencv-java/camera-calibration(GitHub) - Java版のやり方に参考になりました。
cameracalibration - opencv(GitHub)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DTOデザインパターンでgetter/setterを利用することは思考停止していないか?

JavaでDTOデザインパターンを実装するときにsetter/getterを付けているのって
思考停止していないでしょうか、私は疑問を感じます。

※DTO Wikipedia引用
Data Transfer Object(DTO)はデザインパターンの一種で、アプリケーションソフトウェアのサブシステム間でデータを転送するのに使う

実装としてはこんな感じ。

class Hoge
{
    private int value;
    public int getValue(){ return value; }
    public void setValue(int value){ this.value = value; }
}

目的を鑑みるとロジックを含むべきものではないものと考えます。
そうするとフィールドに対するgetter/setterがあるだけの実装になります。
カプセル化も全く機能していないので、何がしたいのかはさっぱりです。
※全体の統一性のために気持ち悪いとかそういう話は理解できます。

なのでフィールドをpublicにしてしまう実装が簡潔です。
IDEからも補完がでて便利!

class Hoge
{
    public int value;
}

んじゃ次に突っ込まれる要因として、JavaのBeanになってないやんと
言われるかもしれません。

ただし、DTOの目的を考えるとBeanになる必要は無いはず。
なんでBeanにしたいの?と考えると

「BeanUtils.copyProperties」が使えないやんけ!と言われるかも。
でもそれって、目的と手段を勘違いしていませんか?と私は思います。
DTOとしては成立しているはずなのです。

んじゃなぜ「BeanUtils.copyProperties」を使いたいの?となると思います。

次回
BeanUtils.copyPropertiesを利用することは思考停止していないか?

ご意見ご感想などございましたらお願いいたします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む