こしあん
2019-10-05

OpenCVのsubtractについての小ネタ


7.8k{icon} {views}


OpenCVのsubtractと通常のNumpyの引き算の差が気になったのでメモ。実際に試してみました。

環境:Numpy:1.16.3, OpenCV:4.1.0

NumpyとOpenCVのsubtractの差

OpenCVとNumpy配列は密接に関係していて、新しい画像を作るときにnp.zerosなどのNumpy関数で初期化します。

ありがちなのがuint8型で初期化して、OpenCVで画像として扱うパターンです。uint8のNumpy配列を画像と見たてみます。普通にNumpyで引くケースと、OpenCVのsubtractで引くケースを比較します。

import cv2
import numpy as np

x = np.arange(27, dtype=np.uint8).reshape(3, 3, 3)
y = np.arange(27, dtype=np.uint8)[::-1].reshape(3, 3, 3)
print(x - y) # 普通に引き算
print(cv2.subtract(x, y)) # OpenCVのsubtract
# Numpyの引き算
[[[230 232 234]
  [236 238 240]
  [242 244 246]]

 [[248 250 252]
  [254   0   2]
  [  4   6   8]]

 [[ 10  12  14]
  [ 16  18  20]
  [ 22  24  26]]]
# OpenCVのsubtract
[[[ 0  0  0]
  [ 0  0  0]
  [ 0  0  0]]

 [[ 0  0  0]
  [ 0  0  2]
  [ 4  6  8]]

 [[10 12 14]
  [16 18 20]
  [22 24 26]]]

Numpyの引き算はオーバーフローしているのに、OpenCVの引き算は0で底打ちされていてオーバーフローしていません

uint8以外ならどうか?

OpenCVのsubtractはただ単にマイナスの値を0と決め打ちしている疑惑が否定できないので、uint8からint32に変更して計算してみます。

x = np.arange(27, dtype=np.int32).reshape(3, 3, 3)
y = np.arange(27, dtype=np.int32)[::-1].reshape(3, 3, 3)
print(x - y)
print(cv2.subtract(x, y))
# Numpyの引き算
[[[-26 -24 -22]
  [-20 -18 -16]
  [-14 -12 -10]]

 [[ -8  -6  -4]
  [ -2   0   2]
  [  4   6   8]]

 [[ 10  12  14]
  [ 16  18  20]
  [ 22  24  26]]]
# OpenCVのsubtract
[[[-26 -24 -22]
  [-20 -18 -16]
  [-14 -12 -10]]

 [[ -8  -6  -4]
  [ -2   0   2]
  [  4   6   8]]

 [[ 10  12  14]
  [ 16  18  20]
  [ 22  24  26]]]

結果は同じになりました。つまり、OpenCVのsubtractはマイナスの値を0に丸めておらず、型に応じてオーバーフロー起こさないように調整しているだけのようです。

まとめ

OpenCVのsubtractとNumpyの引き算の差は、オーバーフローを引き起こすかどうか



Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内

技術書コーナー

北海道の駅巡りコーナー


Add a Comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です