Javaアプリにも画像処理させたい
専門的な知識を学んだわけでもないので、ネット情報や書籍を参考にJavaアプリを作っているが、「AIだよ」って言えるようなものにも挑戦したくなった。
ネットなどで公開されている画像処理のサンプルの多くがPythonなので、せっかくだから自分が(比較的)得意とするJavaでやったらどうなるかと思って試した。
参考にしたサイト
-
https://www.hobby-happymylife.com/%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%9f%e3%83%b3%e3%82%b0/python_opencv_ocr/ (今回これをJavaにしたようなものです)
大変参考になる記事を公開してくださり、ありがとうございました。
作ってみた
用意したサンプル画像
必要なライブラリーなど
- openCV(Linuxならば普通にインストール。Windowsの場合はdll一枚をパスの通ったところに。自分は JAVA_HOME/bin の中に入れた)
- OpenCVにアクセスするためのjar(OpenCVインストールすると入っている。今回はopencv-470.jarをプロジェクトに追加)
処理するためのコード
package opencvtest;
import java.util.ArrayList;
import java.util.List;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
public class Main {
public static void main(String[] args) {
// OpenCV ライブラリーをよむ
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
// 画像ファイルを読む(フルカラー)
Mat img = Imgcodecs.imread("input.png");
// グレースケールのMatにする
Mat imgG = new Mat();
Imgproc.cvtColor(img, imgG, Imgproc.COLOR_BGR2GRAY);
// ガウジアンフィルターをかけて平滑化する
// ぼかしがかかることで輪郭抽出しやすくなる
Mat imgB = new Mat();
Imgproc.GaussianBlur(imgG, imgB, new Size(5, 5), 5.0);
// 輪郭抽出のための閾値処理
Mat imgA = new Mat();
Imgproc.adaptiveThreshold(imgB, imgA, 255, 1, 1, 11, 2);
// 輪郭抽出
Mat imgR = new Mat();
List contour = new ArrayList();
Imgproc.findContours(imgA,
contour,
imgR,
Imgproc.RETR_LIST,
Imgproc.CHAIN_APPROX_SIMPLE);
// 輪郭の一つずつを処理
// このforプロックは関数化できるが
// わかりやすくするためこのままにした
for (Object object : contour) {
Rect boundingRect = Imgproc.boundingRect((Mat) object);
int x = boundingRect.x;
int y = boundingRect.y;
int w = boundingRect.width;
int h = boundingRect.height;
// 上記変数の条件設定によって、
// 画像の特定の場所だけ抽出することなどができる
// 高さが40を超えるものだけ処理(適当)
if (40 < h) {
Point point1 = new Point(x, y);
Point point2 = new Point(x + w, y + h);
Scalar color = new Scalar(0, 0, 255); // 赤
int thickness = 2; // 太さ
// 最初のMat(フルカラー)に矩形を上書き
Imgproc.rectangle(img, point1, point2, color, thickness);
}
}
// できあがったMatを画像に書き出す
Imgcodecs.imwrite("output.jpg", img);
}
}
処理後の画像
確かに輪郭は抽出できました。ただ、これで「文字」を抽出したいとする場合、「う」のように一部が切り取られてしまうと、目的とする処理ができなくなるかもしれません。
これよりも大きなサイズの枠にするよう設定すると、アルファベットの小文字が抽出されなくなります。