こしあん
2019-02-08

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


8.2k{icon} {views}


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



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

技術書コーナー

北海道の駅巡りコーナー


Add a Comment

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