こしあん
2019-02-08

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

Pocket
LINEで送る
Delicious にシェア

1.7k{icon} {views}

新刊情報

技術書典8の新刊『モザイク除去から学ぶ 最先端のディープラーニング』(A4・195ページ)好評通販中です! 機械学習の入門からGANの最先端までを書いたおすすめの本となっています! Boothで試し読みできます。情報まとめ・質問用GitHub



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なのに、実は問題なのが変数の型というのはちょっとわかりづらいですよね。


新刊情報

技術書典8の新刊『モザイク除去から学ぶ 最先端のディープラーニング』好評通販中(A4・195ページ)です! Boothで試し読みもできるのでよろしくね!


Pocket
LINEで送る
Delicious にシェア

Add a Comment

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