0
0

More than 1 year has passed since last update.

OpenCVのinpaintは32-bit floatを入れても動く

Last updated at Posted at 2021-10-23

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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0