Java OpenCV 〜画像の一部分を書き換える〜

画像の一部分を変更して、他のファイルから読み取った画像を書き込む方法

結論


下の画像のように、道の写真に「Tea!」と書いた絵を重ねたようなものに書き換える処理です。

手こずったところ

Roiの使い方、つまりはMat#submat()とMat#copyTo()の使い方に手こずりました。

以下のような画像を使用しました。
道路のイメージ=img1
Teaのイメージ=img2

Mat roi = img.submat(new Rect(20, 20, tea.width(), tea.height()));
Mat dst = new Mat();
tea.copyTo(roi);

上の処理で、土台になるいmg1にimg2の内容を書き込みます。
あとは、表示するだけです。

ソースはGithubにあります。

ポイント

画像の取得部分

URL url = this.getClass().getResource("/road.png");
Mat img = Imgcodecs.imread(url.getPath(), Imgcodecs.IMREAD_UNCHANGED);

画像の抜き出し

Mat roi = img.submat(new Rect(20, 20, tea.width(), tea.height()));

変数teaはimg2の画像です。
つまりは、道路の画像からx=20, y=20からteaのサイズ分を抜き出していると言うことです。

書き込み

tea.copyTo(roi);

これだけです。

ここにたどり着くのに、3日くらいかかりました。(笑)

しかし!

これでは、いまいち納得がいきませんでした。
なぜなら、「重ねる」のが目的であるからです。
これじゃ「上書き」です。

そんなわけで

やっと見つけました。こうすれば良いと言うものです。
理論的には、以下のような手順です。

  1. 書き込みたい画像を取得する
  2. 取得した画像と同じサイズ文のROI(画像の一部分)を取得する
  3. 抜き出したROIをCore.addWeighted()で書き込みたい画像とROIを重ねます。
  4. copyToで重ねたデータをROIにコピーする
URL url = this.getClass().getResource("/road.png");
Mat img = Imgcodecs.imread(url.getPath(), Imgcodecs.IMREAD_UNCHANGED);
printAttribute(img);

 URL url2 = this.getClass().getResource("/Tea.png");
 Mat tea = Imgcodecs.imread(url2.getPath(), Imgcodecs.IMREAD_UNCHANGED);
// 文字列の配置
Imgproc.putText(img, "sample!", new Point(10, 10), Core.FONT_HERSHEY_SIMPLEX, 0.5, Scalar.all(0));
// 
Mat roi = img.submat(new Rect(20, 20, tea.width(), tea.height()));
Mat dst = new Mat();
Core.addWeighted(tea, 0.2, roi, 0.8, 0.5, dst);
dst.copyTo(roi);

すると以下のような画像になります。

元にした画像が、透過PNG担っていないのが気になりますが、今回はここら辺で

でわでわ。。。