OpenCV 5.0.0
Open Source Computer Vision
読み込み中...
検索中...
見つかりません
🤖 AIによる機械翻訳(非公式) — これは OpenCV 5.0.0 公式リファレンス(英語)を AI (Claude) で自動翻訳したものです。訳に誤りを含む場合があります。正確な情報は 公式英語版(原文) を参照してください。
画像のインペインティング

目的

本章では、

  • インペインティングと呼ばれる手法を用いて、古い写真から小さなノイズや傷などを除去する方法を学ぶ
  • OpenCVのインペインティング機能について見ていく。

基礎

多くの人は、黒い斑点や傷などが付いた古く劣化した写真を自宅に持っているだろう。それを元に戻して復元したいと思ったことはないだろうか。ペイントツールで単に消すことはできない。なぜなら、黒い構造を白い構造に置き換えるだけで役に立たないからである。こうした場合には、画像インペインティング(image inpainting)と呼ばれる技術が使われる。基本的な考え方は単純で、これらの悪い跡を周囲のピクセルで置き換え、周辺に馴染むようにするというものである。下に示す画像(Wikipedia から引用)を見てみよう:

image

この目的のためにいくつかのアルゴリズムが設計されており、OpenCVはそのうちの2つを提供している。どちらも同じ関数 cv.inpaint() からアクセスできる

1つ目のアルゴリズムは、2004年にAlexandru Teleaによって発表された論文"An Image Inpainting Technique Based on the Fast Marching Method"に基づいている。これはFast Marching Methodをベースにしている。画像中にインペイント対象となる領域があると考える。アルゴリズムはこの領域の境界から始まり、まず境界部分をすべて徐々に埋めながら領域の内側へと進んでいく。インペイント対象のピクセルの周囲にある小さな近傍領域を取り出す。このピクセルは、近傍内のすべての既知ピクセルの正規化された重み付き和で置き換えられる。重みの選び方は重要な問題である。対象点に近いピクセル、境界の法線に近いピクセル、境界の輪郭上にあるピクセルほど大きな重みが与えられる。あるピクセルがインペイントされると、Fast Marching Methodを使って次の最も近いピクセルへ移動する。FMMにより既知ピクセルに近いピクセルから先にインペイントされるため、ちょうど人手によるヒューリスティックな操作のように動作する。このアルゴリズムはフラグ cv.INPAINT_TELEA を使うことで有効になる。

2つ目のアルゴリズムは、2001年にBertalmio, Marcelo、Andrea L. Bertozzi、Guillermo Sapiroによって発表された論文"Navier-Stokes, Fluid Dynamics, and Image and Video Inpainting"に基づいている。このアルゴリズムは流体力学に基づいており、偏微分方程式を利用する。基本原理はヒューリスティックである。まず既知領域から未知領域へとエッジに沿って進む(エッジは連続しているはずだからである)。インペイント領域の境界で勾配ベクトルを一致させながら、等光度線(同じ輝度を持つ点を結んだ線。ちょうど輪郭線が同じ標高の点を結ぶのと同じ)を延長していく。このために流体力学の手法がいくつか用いられる。それらが得られると、その領域内の分散が最小になるように色が埋められる。このアルゴリズムはフラグ cv.INPAINT_NS を使うことで有効になる。

コード

入力画像と同じサイズのマスクを作成する必要がある。マスクでは非ゼロのピクセルがインペインティング対象の領域に対応する。それ以外はすべて単純である。私の画像は(手作業で加えた)いくつかの黒い傷で劣化している。これに対応する傷を Paint ツールで作成した。

import numpy as np
import cv2 as cv
img = cv.imread('messi_2.jpg')
mask = cv.imread('mask2.png', cv.IMREAD_GRAYSCALE)
dst = cv.inpaint(img,mask,3,cv.INPAINT_TELEA)
cv.imshow('dst',dst)
void imshow(const String &winname, InputArray mat)
Displays an image in the specified window.
int waitKey(int delay=0)
Waits for a pressed key.
void destroyAllWindows()
Destroys all of the HighGUI windows.
Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
Loads an image from a file.
void inpaint(InputArray src, InputArray inpaintMask, OutputArray dst, double inpaintRadius, int flags)
Restores the selected region in an image using the region neighborhood.

下に結果を示す。1枚目の画像は劣化した入力を示す。2枚目はマスクである。3枚目は1つ目のアルゴリズムの結果、最後の画像は2つ目のアルゴリズムの結果である。

image

追加リソース

  1. Bertalmio, Marcelo, Andrea L. Bertozzi, and Guillermo Sapiro. "Navier-stokes, fluid dynamics, and image and video inpainting." In Computer Vision and Pattern Recognition, 2001. CVPR 2001. Proceedings of the 2001 IEEE Computer Society Conference on, vol. 1, pp. I-355. IEEE, 2001.
  2. Telea, Alexandru. "An image inpainting technique based on the fast marching method." Journal of graphics tools 9.1 (2004): 23-34.

演習

  1. OpenCVにはインペインティングに関するインタラクティブなサンプル samples/python/inpaint.py が付属しているので、試してみよう。
  2. 数か月前、Adobe Photoshop で使われている高度なインペインティング技術である Content-Aware Fill についての動画を見た。さらに調べたところ、同じ技術が "Resynthesizer" という別の名前で既に GIMP に存在していることがわかった(別途プラグインのインストールが必要)。きっとこの技術を楽しめるはずだ。