] 映画の郷 [ 電子工作部:python + kivyで修復プログラムを構築する(経過報告)

ラズベリーパイと戦前映写機を組みあわせた自作のフィルムスキャナーで賞をいただいてから2年が経過しました。スキャナー自体は快調に動いているのですが古いフィルムが相手でもあって傷や汚れも多く、スキャン画像を修復する技術が必要だ…と痛感した2年間でもありました。

昨年、折に触れて画像修復のプログラムをpythonで試していて、今年中に一つのアプリとしてまとめていこうと思っています。

指定したフォルダ(「data」)に連番を付したスキャン画像を放りこんでおき、アプリを立ち上げると画像を読みこんで左側にサムネイル表示。調整や修正を加えた画像が右側に表示され、その設定を保持したまま一括で画像すべてを修正&保存、必要であれば動画化する…フィルム修復を一つのインターフェースで直感的に処理できるといいな、が元々の発想です。

昨年1月、同じ試みをした際はうまくいきませんでした。

2020年に試作したインターフェイスのプロトタイプ

この時は「読みこんだ画像を縦スクロール可能なサムネイル表示する」でつまずきました。kivyのファイル選択ウィジェットを使おうとしたのですが失敗。今回はてなブログでkivyでのサムネイルを実装しているサイト(「ふたり暮らし」)を見つけたのでそれをアレンジさせてもらいました。

現時点ではアプリを立ち上げるとまず空のディスプレイが表示されます。左側にはスクロール式のサムネイルとファイル名が表示されていて、適当なファイル名をクリックするとその画像が2面に表示されます。

下部にボタンとスライダーを配置しておいたので試しに「セピア」のスライダーにプログラムを割り当ててみました。以前にデジタル染色で試したプログラムを援用したものです。スライダーは左端が「0」、右端が「180」の値となる設定になっています。真ん中よりやや右寄り、「110」の辺りにスライドを動かすと右の画像が青色になります。

そのままスライドを少し左に戻して「70」の辺りにすると綠、右端まで寄せて「180」にすると赤色に変わります。

もうひとつ「修復1」のボタンに一括簡易修復のプログラムを割り当てていきます。厳密にはスキャン画像上の傷を修復しているわけではないのですが、修正前(上の写真左)に目立つ「黒い汚れ」を消す(写真右)ことができます。100枚ほどの連番画像をまとめて修復してみたところ、時間はかかるものの狙った通りの結果になっていました。

クリアすべき問題が多く実用に耐えるものが完成するのか定かではありません。最終的に修復プロセスを学習した人工知能(AI)に手伝ってもらう所まで念頭に入れていて、長丁場の開発になるはずなのでボチボチ進めていきます。

] 映画の郷 [ 電子工作部:「綺乃九五式」スキャン画像修復プログラム(4)マウスクリックで矩形を指定しピンポイント修正を行う

この数日行っていたのがマウスクリックで画面上に領域を指定し、その部分をピンポイントで修正するプログラム製作です。画像の一部を処理する作業は「ROI(Region Of Interest)」と呼ばれているそうで、参考になるプログラムがオンラインで見つかりました。

【OpenCV】画像の一部のみ処理するROIの設定について【Python版】

このプログラムでは座標は予めコード内に記述しておく設定になっています。マウスクリックで座標を取得するプログラムは別に探しました。

OpenCVを使ってマウスイベント(手動)でテニスコート領域を選択できるようにする

クリックを4回するとその4点のxy座標をリストに格納し、その4点を頂点とする矩形を描くことができます。

「ROI」は矩形(台形などを含む)ではなく長方形しか処理できないようでしたので、4点クリックではなく左上と右下の2点クリックで座標を取得する形に修正します。ざっと書いたのが「denoising-roi2.py」(左)です。

先日スキャンした『聖女ベアトリクス伝説』からの一コマ。額の辺りに楕円形の汚れが付着しています。この部分をピンポイントで修復していきます。

sample18-roi01

プログラムを起動します。額の汚れの部分を左上と右下で挟みこむように2回クリック。すると自動でマスク画像が生成され、inpaint関数がそのマスク画像を介して元画像を修復していきます。

もう少し詳しい流れとしては:
1)加工用に元画像全体を一旦複製する(「dst_img」)
2)クリックした2点を対角線上の頂点とした長方形の画像「s_roi」を「dst_img」から抽出する
3)「s_roi」をhsv変換してからマスク画像「hsv_mask」を生成する
4)「hsv_mask」をパッチとし、inpaint関数で「s_roi」に修復をかけ画像「dst」を生成する
5)「dst」を「dst_img」の元の位置に置き換える
6)修復完了した画像を別名義で保存する(必要なら元画像を上書きする)

おでこの汚れを一か所消すだけにしては複雑な作業をしています。

参考サイトでは「ぼかし処理(blur関数)」を使っていて、これだと一行で済みます。ただぼかし処理は修復ではないんですよね。blur関数では下の結果になります。

copy-2836b-blurredcopy-2836b-blurred-detail

散らした感じとなり四角い跡が残ってしまいます。

一方のinpaint関数は設定次第でかなり綺麗な修復結果になります。設定値「uppervalue(uv)」を変えながら修正結果の違いを比較してみます。

copy-2836b-uv50
uv = 50 (7.896 秒)
ほとんど変化なし

copy-2836b-uv90
uv = 90(9.26 秒)
輪郭部分が残ってシミの様に見えます

copy-2836b-uv120
uv = 120(9.028 秒)
だいぶ薄くなりました

copy-2836b-uv150
uv = 150(9.091 秒)
かなり綺麗に消えています

copy-2836b-uv150b
uv = 150の拡大

uppervalueを150まであげるとダメージはほとんど見えなくなります。拡大するとうっすら輪郭は残っていますが、blur関数の様な不自然な感覚はありません。

フィルムのスキャン画像でダメージが一か所しかない、というのはあり得ない話で、傷や汚れは数ヶ所〜数十か所に及びます。そのまま修復システムに組みこむ感じではなさそう。それでもマウスクリック2回でxy座標を格納し、画像領域を指定してピンポイント修復出来るようになったのは収穫でした。