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

目的

このチュートリアルでは、F変換を用いた画像インペインティングの仕組みを学ぶ。これは次の要素から成る:

  • 背後にある基本理論
  • 3つの異なるアルゴリズム。

はじめに

このチュートリアルの目的は、逆F変換が画像再構成に利用できることを示すことである。ここで画像再構成とは、破損した画像の再構成を意味し、破損とは元画像に含まれないすべてのものを指す。ノイズ、テキスト、傷などが該当する。提案するのは、近似手法を用いて再構成の問題を解くことである。つまり、与えられた画像に近く、かつ破損と認識されるものを含まない近似画像を探すことになる。このタスクは 画像インペインティング (image inpainting) と呼ばれる。

ファジー変換の応用

前のチュートリアルで示したように、F変換は画像処理で非常に有用なファジィ数学のツールである。先に導入したカーネル \(g\) を用いて、この式を書き直してみよう:

\[ F^0_{kl}=\frac{\sum_{x=0}^{2h+1}\sum_{y=0}^{2h+1} \iota_{kl}(x,y) g(x,y)}{\sum_{x=0}^{2h+1}\sum_{y=0}^{2h+1} g(x,y)}, \]

ここで \(\iota_{kl} \subset I\) はピクセル \((k \cdot h,l \cdot h)\) を中心とし、\(g\) はカーネルである。画像処理の目的では、次のようなバイナリマスク \(S\) を用いる

\[ g^s_{kl} = g \circ s_{kl} \]

ここで \(s_{k,l} \subset S\) である。マスク \(S\) の部分領域 \(s\) は、画像 \(I\) の部分領域 \(\iota\) に対応する。演算子 \(\circ\) は要素ごとの行列積(アダマール積)である。式は次のように更新される

\[ F^0_{kl}=\frac{\sum_{x=0}^{2h+1}\sum_{y=0}^{2h+1} \iota_{kl}(x,y) g^s(x,y)}{\sum_{x=0}^{2h+1}\sum_{y=0}^{2h+1} g^s(x,y)}. \]

詳細は関連論文を参照のこと。

コード

/* Sample - Inpainting
* Target is to apply inpainting using F-transform
* on the image "input.png". The image is damaged
* by various types of corruption:
*
* input1 = image & mask1
* input2 = image & mask2
* input3 = image & mask3
*
* Three algorithms "ft::ONE_STEP", "ft::MULTI_STEP"
* and "ft::ITERATIVE" are demonstrated on the
* appropriate type of damage.
*
* ft::ONE_STEP
* "output1_inpaint.png": input1, mask1
*
* ft::MULTI_STEP
* "output2_inpaint.png": input2, mask2
* "output3_inpaint.png": input3, mask3
*
* ft::ITERATIVE
* "output4_inpaint.png": input3, mask3
*
* Linear kernel with radius 2 is used for all
* samples.
*/
#include "opencv2/core.hpp"
using namespace std;
using namespace cv;
int main(void)
{
// Input image
Mat I = imread("input.png");
// Various masks
Mat mask1 = imread("mask1.png", IMREAD_GRAYSCALE);
Mat mask2 = imread("mask2.png", IMREAD_GRAYSCALE);
Mat mask3 = imread("mask3.png", IMREAD_GRAYSCALE);
// Apply the damage
Mat input1, input2, input3;
I.copyTo(input1, mask1);
I.copyTo(input2, mask2);
I.copyTo(input3, mask3);
// Inpaint with various algorithm
Mat output1, output2, output3, output4;
ft::inpaint(input1, mask1, output1, 2, ft::LINEAR, ft::ONE_STEP);
ft::inpaint(input2, mask2, output2, 2, ft::LINEAR, ft::MULTI_STEP);
ft::inpaint(input3, mask3, output3, 2, ft::LINEAR, ft::MULTI_STEP);
ft::inpaint(input3, mask3, output4, 2, ft::LINEAR, ft::ITERATIVE);
// Save output
imwrite("output1_inpaint.png", output1);
imwrite("output2_inpaint.png", output2);
imwrite("output3_inpaint.png", output3);
imwrite("output4_inpaint.png", output4);
// Save damaged input for comparison
imwrite("input1.png", input1);
imwrite("input2.png", input2);
imwrite("input3.png", input3);
return 0;
}
Comma-separated Matrix Initializer.
Definition mat.hpp:964
void copyTo(OutputArray m) const
Copies the matrix to another one.
int main(int argc, char *argv[])
Definition highgui_qt.cpp:3
Definition core.hpp:107
STL namespace.

解説

以下のサンプルでは、画像のインペインティング (修復) の使い方を示す。同じ入力と3種類の異なる破損を用いて、3枚の人工的な画像を生成する。実際の利用では入力画像はすでに用意されているが、ここでは自分で作成している。

まず、画像と、人工的な破損の生成に用いる3枚のマスクを読み込む必要がある。

// Input image
Mat I = imread("input.png");
// Various masks
Mat mask1 = imread("mask1.png", IMREAD_GRAYSCALE);
Mat mask2 = imread("mask2.png", IMREAD_GRAYSCALE);
Mat mask3 = imread("mask3.png", IMREAD_GRAYSCALE);

‍マスクは IMREAD_GRAYSCALE として読み込む必要がある点に注意する。

次のステップでは、これらのマスクを使って入力画像を破損させる。

// Apply the damage
Mat input1, input2, input3;
I.copyTo(input1, mask1);
I.copyTo(input2, mask2);
I.copyTo(input3, mask3);

マスクを使って、同じ入力画像に3種類の異なる破損を適用した。結果は以下のとおりである。

input1, input2 and input3

‍実際の利用では、画像 input1input2input3 は自然に生成され、そのまま入力として使われる点を忘れないこと。

続いて出力画像を宣言する。以降の行ではインペインティングのメソッドを適用する。3種類のアルゴリズムを1つずつ説明する。

1つ目は ONE_STEP である。

ft::inpaint(input1, mask1, output1, 2, ft::LINEAR, ft::ONE_STEP);

ONE_STEP アルゴリズムは、破損部分を無視して半径 2 のカーネル (メソッド呼び出しで指定したとおり) を使い、直接F変換を単純に計算する。逆F変換により、近傍の成分の値を使って欠損領域を埋める。十分大きな半径を選ぶかどうかは利用者次第である。

2つ目は MULTI_STEP である。

ft::inpaint(input2, mask2, output2, 2, ft::LINEAR, ft::MULTI_STEP);
ft::inpaint(input3, mask3, output3, 2, ft::LINEAR, ft::MULTI_STEP);

MULTI_STEP アルゴリズムは同じように動作するが、指定した半径 (この場合は 2) が不十分と判断された場合に自動的に大きくする。穴を埋めたいがどれくらいの半径が必要か分からない場合は、MULTI_STEP を選んでコンピュータに判断させればよい。可能な限り小さい半径が見つけられる。

最後は ITERATIVE である。

ft::inpaint(input3, mask3, output4, 2, ft::LINEAR, ft::ITERATIVE);

大多数の場合に最良の選択は ITERATIVE である。この処理方法は、小さな破損には小さな半径の基底関数を、大きな穴にはより大きな半径を使う。

output1 (ONE_STEP), output2 (MULTI_STEP), output3 (MULTI_STEP), output4 (ITERATIVE)