JP / EN

広告
2025/01/31

cv2.inRangeで "src is not a numpy array, neither a scalar"はnp.arrayを渡しても出る

タグ:python

cv2.inRangeはcv.inRange(img, min, max)のように呼びだすと画像imgに対して値がmin以上max以下の部分を白に、 それ以外を黒にするマスクを作ってくれる関数である。 カラー画像に対してはminとmaxは3次元のタプルやnp.arrayでもよく、BGRの各値が範囲内かどうかを調べてくれる、 色域抽出などの処理で便利な関数である。

地味なハマりどころとして「inRangeのmin, maxはimgがカラーのときはnp.arrayでもよいが、 グレースケールのときはintでなければならない」という仕様だ。 おそらくこれは、カラー画像のときはRGBを3次元のnp.arrayで表現できるようにしておくための仕様と思われる。 これによってカラー画像では動いていたコードが、たまたまグレー画像が来たときにエラーを出すということがある。

    In [1]: import cv2
    In [2]: import numpy as np

    # グレー画像を生成
    In [4]: img = (np.random.rand(30, 20) * 255).astype(np.uint8)
    In [5]: img
    Out[5]:
    array([[171, 163,  88, 178,  67, 140,  58, 119,   1, 100,  43,  74,  87,
            172, 204, 158, 120, 183,  16,  99],
            ... (中略)

    # min, maxがint、これは成功
    In [6]: cv2.inRange(img, 100, 120)
    Out[6]:
    array([[  0,   0,   0,   0,   0,   0,   0, 255,   0, 255,   0,   0,   0,
              0,   0,   0, 255,   0,   0,   0],

    # min, maxがnp.array、これは失敗
    In [8]: cv2.inRange(img, img[0, 0], img[0, 0] + 3)
      ---------------------------------------------------------------------------
      error                                     Traceback (most recent call last)
      Cell In[8], line 1
      ----> 1 cv2.inRange(img, img[0, 0], img[0, 0] + 3)
      
      error: OpenCV(4.8.1) :-1: error: (-5:Bad argument) in function 'inRange'
      > Overload resolution failed:
      >  - lowerb is not a numpy array, neither a scalar
      >  - Expected Ptr<cv::UMat> for argument 'lowerb'

    # min, maxをintに変換してから渡せば成功
    In [9]: cv2.inRange(img, img[0, 0].item(), img[0, 0].item() + 3)
    Out[9]:
    array([[255,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
            255,   0,   0,   0,   0,   0,   0],

  

エラーメッセージは"lowerb is not a numpy array, neither a scalar"というわかりにくいものが、 np.arrayを渡しているにもかかわらず出てしまうのがまた厄介である。
なお、カラー画像の場合はnp.arrayを渡してもよいので、imgからインデックスで引っこ抜いた 色値をそのままinRangeに渡してよい。
    In [10]: img = (np.random.rand(30, 20, 3) * 255).astype(np.uint8)

    In [11]: cv2.inRange(img, img[0, 0], img[0, 0] + 3)
    Out[11]:
    array([[255,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
              0,   0,   0,   0,   0,   0,   0],
  
カラーとグレーで処理をわけるのは面倒なので、飛んでくる画像を全てカラーに変換してしまうのも一つの手である。

おすすめ記事

PyTorchのテンソルを画像にして保存する

NumPy np.clip: arrayの値の範囲を指定した最大値・最小値に合わせて丸める

Python OpenCV/PillowでWebP画像を読み込む



このエントリーをはてなブックマークに追加

https://wonderhorn.net/