LoginSignup
5
2

More than 3 years have passed since last update.

Numpy で画像マスクを作るときは型に気をつける

Posted at

やりたいこと

画像や動画の一部以外を黒く塗りつぶして切り抜きたい場合、画像のマスクを作成して、それを重ね合わせることで実現する。

元画像
lena.png
マスク済み画像
masked_image.png

失敗

Numpy を使って黒塗りしたい範囲は 0、切り抜きたい範囲は 1 とするマスクを作成。
行列の各要素をかけるとマスクできると思ったら、思ってたのと違う出力になった。

h_img, w_img = img.shape[:2]
mask = np.zeros((h_img, w_img, 3))
radius = int(h_img / 2)
center = radius
cv2.circle(mask, (center, center), radius, (1, 1, 1), thickness=-1, shift=0)
masked_img = img * mask

Numpy で作ったマスク (mask)
err_mask.png

マスク済み画像 (masked_img)
err_masked_image.png

原因と解決策

Numpy で行列を定義するとき、 dtype を指定しないとデフォルトでは float64 型になる。一方で、opencv の imread で読み込んだ画像は、その輝度によって、CV_8U や CV_16F、 CV_32F で読み込まれる(通常は CV_8U)。 CV_8U だと Numpy のデータ型では np.uint8 に対応している。
つまり、失敗した例では CV_8U の画像に対して、 float64 型のマスクをかけている。

Numpy で行列を定義するときに、型を np.uint8 に指定してやる。
できた。

mask = np.zeros((h_img, w_img, 3), dtype=np.uint8) # 型を uint8 に指定

マスク済み画像
masked_image.png

マスクを画像として表示してみると、真っ黒。
mask.png

所感

データ型の不一致という初歩的なミスだが、最近 python ばかり使っていて、型を意識する機会が減っているせいか、気がつくのに時間がかかった。
そもそも、 np.zeros で定義せずに、np.zeros_like を使って image の型含めて行列定義すればよかった。

5
2
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
5
2