2025年6月15日日曜日

シームレスなエフェクトを適用するアプリ CV-Masker を作った

シームレスなエフェクトを適用するアプリ CV-Masker を作りました。 マスクを手書きで設定して、そのマスクに対してグラデーションをかけつつシームレスなエフェクトを適用できます。



色々なエフェクトを用意しているので画像はあくまでイメージですが、こんな感じの画像をサクッと作れます。



最初は cv.colorChange, cv.illuminationChange, textureFlattening などの シームレスなエフェクトを与える関数の確認のために作っていたのですが、 いくつかボツ案があったので、マスクにエフェクトを掛けて遊ぶアプリに変えました。

当初の目的のシームレスなエフェクトの関数は、良い感じの画像を作れるのですが、 へぼい CPU だと処理速度がちょっと遅かったです。 コードを見ると SIMD + Threads の最適化は甘そうなので、将来の改善に期待です。 やはり OpenCV と言えども、コア部分以外は遅い時もあるとわかりました。 あと textureFlattening は実行するたびに結果が異なるので元の実装がバグってると思う。

OpenCV の cv.colorChange などの関数は高度なシームレス処理を行っていますが、 たいていそこまで精度は必要ありません。 そこで自作の軽量な汎用局所シームレス関数を作って遊べるアプリにしました。 0/255 で書いたマスクを boxFilter でグラデーション化して、 グラデーション化したマスクに任意のエフェクトを掛け合わせます。 処理は非常に軽いですが、十分なシームレス感があります。 どんなエフェクトでもシームレスに適用できますが、 一般的かつシンプルなエフェクトをいくつか利用できるようにしておきました。 局所モザイク、局所シャープ化、局所色調補正などが利用できます。 いざ作り始めたら追加したいエフェクトが多すぎて困ってきましたが、 応用的なエフェクトは別のアプリで作ります。 アルゴリズム多すぎのものはすぐに組み込むのが難しいです。

シームレスなエフェクトを加える関数は、メモリリークが直らず苦労しました。 やはり C++ は行数が増えてくると、ハマったときになかなか厳しい。 結局少し前のバージョンでは直らず、すべて書き直したら直りました。 メモリリークそのものは input event で大量に処理させるとすぐに見つかります。 たぶん MatVector の扱いが一番難しいのですが、 push_back() はコピーらしいので、すぐに delete() するのが綺麗だと思う。 参照がどうなってるか熟知してないとできないのが厳しい。
const resultVec = new cv.MatVector();
for (let i = 0; i < 4; i++) {
  const ch = srcChannels.get(i);
  resultVec.push_back(ch);
  ch.delete();
}
手軽にいい感じのエフェクトが作れるので、結構使いやすい気がします。

0 件のコメント:

コメントを投稿