はじめに
写真を撮る際、望んでいないものが写り込んでしまうことがよくあります。カメラのレンズに付いた塵埃、画像のデジタルノイズ、写真に写り込んだ人物の顔を隠したい、などなど。
そんな時、「この写真を修復できたらいいのに」と誰もが思うことでしょう。
写真を修正するのは難しそうで、面倒だしスキルも必要と思ってしまいますよね。
OpenCVのcv2.inpaint関数を使えば、「写真の修復」を簡単に実現できます。
今回は、OpenCVのinpaint関数を使って、写真の傷を魔法のように修復する方法をご紹介します。
cv2.inpaint関数
inpaint関数は、OpenCV 3.0以降のバージョンで利用可能な画像修復機能です。この関数は、指定した領域の欠損部分を、周辺の画像情報から推測して自然に補完(インペインティング)することができます。
例えば、写真に写り込んだ人物の顔を消す場合、単に画像をぼかしたり塗り潰したりすると、その部分が不自然に見えてしまいます。しかしinpaint関数を使えば、自然な補完ができるのです。
(広告) OpenCV関連書籍をAmazonで探す引数
名称 | 説明 |
入力画像(必須) | 入力画像 |
inpaintMask(必須) | マスク画像。欠損部分を白(255)、それ以外を黒(0)で指定します。 |
inpaintRadius(必須) | 周辺の画素を参照する半径(int) |
flags(必須) | 補完手法を指定するフラグ ・ cv2.INPAINT_NS : Navier-Stokesに基づく手法・ cv2.INPAINT_TELEA : Alexandru Teleaにより提案されたアルゴリズム |
戻り値
修復された画像が戻り値となります。
使い方
実際にコードを見ながら、使い方を確認していきましょう。
ここでは、2つの写真について修復をします。
具体例1
下の様な、雲と飛行機の写真を入力画像とします。
飛行機の部分を消してみようとと思います。
マスク画像は下になります。
入力画像から飛行機の部分を白(255)、それ以外の部分を黒(0)とした入力画像と同じサイズの画像です。
後に示すサンプルコードでは、補完手法を指定するフラグとinpaintRadius
の違いについて確認します。
フラグは、cv2.INPAINT_NS
とcv2.INPAINT_TELEA
、inpaintRadius
は0, 5, 10の3通りに変化させています。
結果は下の様になりました。
どの条件も、概ね飛行機の姿を消すことができていますが、よく見ると飛行機の形が残っている様です。
右下のcv2.INPAINT_NS
のinpaintRadius
=10の場合のみ、飛行機の形が残らず、きれいに消せています。
具体例2
入力画像を次の画像に変えてみました。
雲の様なぼんやりした背景ではなく、木の幹が放射状に配置されているシャープな線が多い背景に太さと色が異なる3つのジグザグの線が描かれているものです。
これらのジグザグの線を消せるか試してみましょう。
マスク画像は次になります。
結果は下の様になりました。
一番細い真ん中のジグザグの線は概ね自然に消すことができましたが、線が太くなるにつれて残った痕跡が目立つ様になりました。
また、背景にシャープな線が多い場合、痕跡が残りやすい様です。inpaintRadius
は修復対象の太さ(大きさ)と背景画像にシャープな線が多い・少ないなどの状態によって決めると良さそうです。
最後に、修復対象の色の影響はないことがわかりました。
サンプルコードを示します。
具体例1と2は5, 6行目で読み込む画像が変えただけです。
import cv2 from matplotlib import pyplot as plt # 画像の読み込み image = cv2.imread('image.jpg') mask = cv2.imread('mask.jpg', cv2.IMREAD_GRAYSCALE) # 修復を実行 result1 = cv2.inpaint(image, mask, 0, cv2.INPAINT_TELEA) result2 = cv2.inpaint(image, mask, 5, cv2.INPAINT_TELEA) result3 = cv2.inpaint(image, mask, 15, cv2.INPAINT_TELEA) result4 = cv2.inpaint(image, mask, 0, cv2.INPAINT_NS) result5 = cv2.inpaint(image, mask, 5, cv2.INPAINT_NS) result6 = cv2.inpaint(image, mask, 15, cv2.INPAINT_NS) # BGRのチャンネル並びをRGBの並びに変更(matplotlibで結果を表示するため) rgb_result1 = cv2.cvtColor(result1, cv2.COLOR_BGR2RGB) rgb_result2 = cv2.cvtColor(result2, cv2.COLOR_BGR2RGB) rgb_result3 = cv2.cvtColor(result3, cv2.COLOR_BGR2RGB) rgb_result4 = cv2.cvtColor(result4, cv2.COLOR_BGR2RGB) rgb_result5 = cv2.cvtColor(result5, cv2.COLOR_BGR2RGB) rgb_result6 = cv2.cvtColor(result6, cv2.COLOR_BGR2RGB) # 結果の可視化 plt.rcParams["figure.figsize"] = [16,8] # 表示領域のアスペクト比を設定 title = "cv2.inpaint: codevace.com" plt.figure(title) # ウィンドウタイトルを設定 plt.subplots_adjust(left=0.05, right=0.95, bottom=0.05, top=0.95) # 余白を設定 plt.subplot(231) # 2行3列の1番目の領域にプロットを設定 plt.imshow(rgb_result1) # 修復後の画像を表示 plt.title("cv2.INPAINT_TELEA, radius=0") # 画像タイトル設定 plt.axis("off") # 軸目盛、軸ラベルを消す plt.subplot(232) # 2行3列の2番目の領域にプロットを設定 plt.imshow(rgb_result2) # 修復後の画像を表示 plt.title("cv2.INPAINT_TELEA, radius=5") # 画像タイトル設定 plt.axis("off") # 軸目盛、軸ラベルを消す plt.subplot(233) # 2行3列の3番目の領域にプロットを設定 plt.imshow(rgb_result3) # 修復後の画像を表示 plt.title("cv2.INPAINT_TELEA, radius=15") # 画像タイトル設定 plt.axis("off") # 軸目盛、軸ラベルを消す plt.subplot(234) # 2行3列の4番目の領域にプロットを設定 plt.imshow(rgb_result4) # 修復後の画像を表示 plt.title("cv2.INPAINT_NS, radius=0") # 画像タイトル設定 plt.axis("off") # 軸目盛、軸ラベルを消す plt.subplot(235) # 2行3列の5番目の領域にプロットを設定 plt.imshow(rgb_result5) # 修復後の画像を表示 plt.title("cv2.INPAINT_NS, radius=5") # 画像タイトル設定 plt.axis("off") # 軸目盛、軸ラベルを消す plt.subplot(236) # 2行3列の6番目の領域にプロットを設定 plt.imshow(rgb_result6) # 修復後の画像を表示 plt.title("cv2.INPAINT_NS, radius=15") # 画像タイトル設定 plt.axis("off") # 軸目盛、軸ラベルを消す plt.show() # ウィンドウを表示する(広告) OpenCV関連書籍をAmazonで探す
おわりに
OpenCVのcv2.inpaint
関数を使って写真の傷を修復する方法を解説しました。
数行のコードで、高度な画像修復処理を実現できることが確認できました。
こちらの記事もオススメです。
ご質問や取り上げて欲しい内容などがありましたら、コメントをお願いします。
最後までご覧いただきありがとうございました。
参考リンク
OpenCV: inpaint()
Restores the selected region in an image using the region neighborhood.
(広告)あなたに合ったプログラミング スクールが見つかるかも
プログラミングの学習が、新しい世界を開きます。副業からキャリアの転換まで、目標に向かって一歩を踏み出しましょう。
これらのプログラミング スクールは、あなたの目的に合わせて選択できるさまざまなプログラムを提供しています。どのスクールを選ぶにせよ、プログラミングは未来への扉を開き、新しい機会を切り開く手段として素晴らしい選択です。あなたの夢や目標を実現する第一歩を踏み出す準備はできていますか?