こしあん
2019-10-05

OpenCVのsubtractについての小ネタ

Pocket
LINEで送る


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の引き算の差は、オーバーフローを引き起こすかどうか

Related Posts

Numpyだけで複数の画像をタイルし1つの画像にまとめる方法... 「torchvision.utilsのmake_gridやテンソルをタイルして保存するのって便利だよね。でも、いちいちこのためにPyTorchのテンソルに変えるのって面倒だよね」ということで同じことをNumpyでも実装してみました。Numpy配列の扱い方を工夫すればいけます。 コード make...
PyTorchでOnehotエンコーディングするためのワンライナー... PyTorchでクラスの数字を0,1のベクトルに変形するOnehotベクトルを簡単に書く方法を紹介します。ワンライナーでできます。 TL;DR PyTorchではこれでOnehotエンコーディングができます。 onehot = torch.eye(10) ただし、labelはLongTe...
argparseに直接dictを読み込ませる怪しいやり方... argparseにコマンドライン引数ではなく、ファイルから読み込んだdictをオーバーラップさせる方法を試してみました。本来のargparseの使い方ではない怪しいやり方ですが、JSONやyamlファイルとの連携が可能なので便利ではないかなと思います。 注意 これは本来のargparseの使い...
Kerasで重みを共有しつつ、必要に応じて入力の位置を変える方法... Kerasで訓練させて、途中から新しく入力を作ってそこからの出力までの値を取りたいということがたまにあります。例えば、Variational Auto Encoderのサンプリングなんかそうです。このあまり書かれていないのでざっとですが整理しておきます。 こういうことをやりたい 言葉で書いても...
Pillowでグレースケール化するときに3チャンネルで出力するテクニック... カラー画像をグレースケール化すると1チャンネルの出力になりますが、カラー画像と同時に扱うと整合性からグレースケールでも3チャンネルで欲しいことがあります。Numpyのブロードキャストを使わずに簡単に3チャンネルで出力する方法を書きます。 グレースケール化してカラー化すればOK これでOK i...
Pocket
Delicious にシェア

Add a Comment

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