こしあん
2019-02-08

[Python]OpenCVのアフィン変換でAssertion failed

Pocket
LINEで送る


OpenCVのアフィン変換のgetAffineTransformで、起点と終点の行列をちゃんと正しいshapeで指定しているのにもかかわらず「(-215:Assertion failed)」とエラーになってしまいました。かなり難解なエラーだったので、原因を探ってみました。

このコード

アフィン変換を使って画像を歪ませるコードです。

def shear_image_center(base_image, shear_range):
    assert shear_range >= 0.0 and shear_range <= 1.0
    h = base_image.shape[0] // 2
    w = base_image.shape[1] // 2
    randoms = np.random.uniform(1.0-shear_range, 1.0+shear_range, (3,2))
    coefs = np.array([[-1,-1],[1,-1],[1,1]], np.float32)
    centers = np.array([[h,w]], np.float32)
    origin = centers + centers * coefs
    dest = centers + centers * coefs * randoms
    affine_matrix = cv2.getAffineTransform(origin, dest)
    return cv2.warpAffine(base_image, affine_matrix, (base_image.shape[1], base_image.shape[0]))

こんなエラーが出てきます。

    affine_matrix = cv2.getAffineTransform(origin, dest)
cv2.error: OpenCV(3.4.2) C:\Miniconda3\conda-bld\opencv-suite_1534379934306\work
\modules\imgproc\src\imgwarp.cpp:3163: error: (-215:Assertion failed) src.checkV
ector(2, 5) == 3 && dst.checkVector(2, 5) == 3 in function 'cv::getAffineTransfo
rm'

エラー文を読むと、「originとdestの配列の1次元目が3(3点分のxy座標)でないといけない」というような趣旨です。しかし、originとdestのshapeを確認すると、

print(origin.shape) #(3,2)
print(dest.shape) #(3,2)

と、特にshape上は問題がありません。どういうことでしょう?

原因はNumpy配列のfloatの型

実は、getAffineTransformの引数はfloat32でなくてはいけません。このコード

randoms = np.random.uniform(1.0-shear_range, 1.0+shear_range, (3,2))

ここの部分で生成される乱数がnp.float64であるために、destの型が64ビット変数になってしまっていたのです。実際printで型を確認すると、

print(origin.dtype) # float32
print(dest.dtype) # float64

このように2つの型が違います。これに気づいてしまえば解決法は簡単です。destをastypeでfloat32にすればいいのです。

def shear_image_center(base_image, shear_range):
    assert shear_range >= 0.0 and shear_range <= 1.0
    h = base_image.shape[0] // 2
    w = base_image.shape[1] // 2
    randoms = np.random.uniform(1.0-shear_range, 1.0+shear_range, (3,2)).astype(np.float32) #32ビット変数にする
    coefs = np.array([[-1,-1],[1,-1],[1,1]], np.float32)
    centers = np.array([[h,w]], np.float32)
    origin = centers + centers * coefs
    dest = centers + centers * coefs * randoms
    affine_matrix = cv2.getAffineTransform(origin, dest)
    return cv2.warpAffine(base_image, affine_matrix, (base_image.shape[1], base_image.shape[0]))

これで解決しました。もうちょっとコードが長ければ最後にastypeでもいいでしょう。ちなみに、両方np.float64に揃えるとエラーになってしまうので、やはりnp.float32でなくてはいけないのだと思います。

shapeについてのassertion errorなのに、実は問題なのが変数の型というのはちょっとわかりづらいですよね。

Related Posts

PyTorchで行列(テンソル)積としてConv2dを使う... PyTorchではmatmulの挙動が特殊なので、思った通りにテンソル積が取れないことがあります。この記事では、基本的な畳み込み演算である「Conv2D」を使い、Numpyのドット積相当の演算を行うという方法を解説します。 はじめに PyTorchの変態コーディング技術です。多分。 画像のテ...
Numpyだけでサクッと画像を拡大する方法... Numpyだけで画像をサクッと拡大する方法を紹介します。OpenCVやPillowを使うまでもないな、というようなときに便利な方法です。ニューラルネットワークでインプットのサイズを調整するときも使えます。 ただのNearest Neighbor法 拡大前の1ピクセルを1つの四角形と見立てて、拡...
PyTorchでSliced Wasserstein Distance (SWD)を実装した... PyTorchでSliced Wasserstein Distance (SWD)を実装してみました。オリジナルの実装はNumpyですが、これはPyTorchで実装しているので、GPU上で計算することができます。本来はGANの生成画像を評価するためのものですが、画像の分布不一致を見るためにも使うこ...
Pillowでグレースケール化するときに3チャンネルで出力するテクニック... カラー画像をグレースケール化すると1チャンネルの出力になりますが、カラー画像と同時に扱うと整合性からグレースケールでも3チャンネルで欲しいことがあります。Numpyのブロードキャストを使わずに簡単に3チャンネルで出力する方法を書きます。 グレースケール化してカラー化すればOK これでOK i...
TensorFlow/Kerasでネットワーク内でData Augmentationする方法... NumpyでData Augmentationするのが遅かったり、書くの面倒だったりすることありますよね。今回はNumpy(CPU)ではなく、ニューラルネットワーク側(GPU、TPU)でAugmetationをする方法を見ていきます。 こんなイメージ Numpy(CPU)でやる場合 Num...
Pocket
Delicious にシェア

Add a Comment

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