OpenCVのinpaintは便利ですがuint8の画像でしか動かないと思っていました。
しかしエラーメッセージをよく読むと……
inpainted = cv2.inpaint(src, mask, 3, cv2.INPAINT_TELEA)
cv2.error: OpenCV(4.0.1) C:\ci\opencv-suite_1573470242804\work\modules\photo\src\inpaint.cpp:756: error: (-210:Unsupported format or combination of formats) 8-bit, 16-bit unsigned or 32-bit float 1-channel and 8-bit 3-channel input/output images are supported in function 'icvInpaint'
実は16-bit unsigned shortや32-bit floatを入れても動くらしいです。ただし1チャンネル限定。
issueによると2017年にはこの仕様になっていたらしい。知らなかった。
https://github.com/opencv/opencv/pull/8776
issueによるとinpaintはあんま使われてない&テンプレートで書かれているのでバイナリが肥大化することを避けたい、という判断で限定された型とチャンネル数の組み合わせしかサポートされていないらしい。
いやinpaintはよく使うので全部の型をサポートしてほしいんですが……
チャンネル毎にループを回せば複数チャンネルの画像も扱えます。pythonで書くとこんな感じ。
# cv2.INPAINT_TELEA: image should be 0.0-255.0 range
# https://github.com/opencv/opencv/blob/9267536feefa0e0c5ca6f1113b6e22debe438ddf/modules/photo/src/inpaint.cpp#L403
# cv2.INPAINT_NS: accept float range
# https://github.com/opencv/opencv/blob/9267536feefa0e0c5ca6f1113b6e22debe438ddf/modules/photo/src/inpaint.cpp#L514
def inpaint_float32(image, mask, radius=3, method=cv2.INPAINT_NS):
image = image.astype(np.float32)
inpainted = np.zeros(image.shape, dtype=np.float32)
if len(image.shape) == 2:
inpainted = cv2.inpaint(image, mask, radius, method)
elif len(image.shape) == 3:
_, _, ch = image.shape
# apply inpaint per channel
# because only 1 channel input is supported for float
for i in range(ch):
inpainted[..., i] = cv2.inpaint(
image[..., i], mask, radius, method)
else:
raise Exception('image shape is not supported')
return inpainted
gistにも載せました。
https://gist.github.com/unclearness/2397f8b893d46aef76dbee203b2bbbd1
OpenCVに実装されている手法はチャンネル毎に独立にinpaintするのでアルゴリズム的にはおそらく問題ないです。
INPAINT_TELEA
はインペイント処理の最後でuint8にキャストしているので入力が[0.0 255.0]のレンジでないと結果がおかしくなるようです。普通にfloatにキャストすればいい気がするのですがアルゴリズム的に問題があるのかもしれない。
https://github.com/opencv/opencv/blob/9267536feefa0e0c5ca6f1113b6e22debe438ddf/modules/photo/src/inpaint.cpp#L403
INPAINT_NS
はfloatの範囲なら問題なく動きそうです。未確認ですが入力が負でも扱えると思います。
https://github.com/opencv/opencv/blob/9267536feefa0e0c5ca6f1113b6e22debe438ddf/modules/photo/src/inpaint.cpp#L514