Armadilloフォーラム

matchShapes関数呼出時の発生例外について(OpenCV)

m-koseki

2018年7月5日 14時15分

お世話になっております。小関と申します。

Armadillo-810カメラモデル開発セットとATDE5を用いて、カメラからの撮影画像でのHuモーメントを試行しています。
その際、matchShapes()関数呼び出しで下記エラーが発生してしまいます。

OpenCV Error: Assertion failed (contour1.checkVector(2) >= 0 && contour2.checkVector(2) >= 0 && (contour1.depth() == CV_32F || contour1.depth() == CV_32S) && contour1.depth() == contour2.depth()) in matchShapes, file /build/sh_mobile_ceu sh_mobile_ceu.0: SuperH Mobile CEU driver detached from camera 0
buildd-opencv_2.3.1-11-armhf-d9JIli/opencv-2.3.1/modules/imgproc/src/contours.cpp, line 1705
terminate called after throwing an instance of 'cv::Exception' what(): /build/buildd-opencv_2.3.1-11-armhf-d9JIli/opencv-2.3.1/modules/imgproc/src/contours.cpp:1705: error: (-215) contour1.checkVector(2) >= 0 && contour2.checkVector(2) >= 0 && (contour1.depth() == CV_32F || contour1.depth() == CV_32S) && contour1.depth() == contour2.depth() in function matchShapes

ソースの流れは以下のように組んでいます。

Mat inputImage, tgtGray, tgtDst;
cap >> inputImage;    ⇒カメラからの画像入力
cvtColor(inutImage, tgtGray, CV_BGR2GRAY);    ⇒グレー色への変更
threshold(tgtGray, tgtDst, 0, 255, THRESH_BINARY | THRESH_OTSU);    ⇒二値化

比較対象となる画像データも、ディレクトリから読み出して上記と同じ手順で二値化までおこないます。

その後、下記呼び出しにてHuモーメントをおこないたいのですが上記エラーが発生してしまいます。

double matchResult = matchShapes(tgtDst, srcDst, CV_CONTOURS_MATCH_I1, 0);

二値化後にimwrite()を呼び出してファイル出力画像を確認していますが、特に問題ないように思えます。

Makefileは以下のとおりです。

TARGET = targetfile

CROSS_COMPILE ?= arm-linux-gnueabihf-
CC = $(CROSS_COMPILE)g++
LDLIBS := -lopencv_core -lopencv_highgui -lopencv_imgproc -lm
SOURCE := targetfile.cpp

all: $(TARGET)

$(TARGET):
$(CC) $(LDFLAGS) $(LDLIBS) -o $@ $(SOURCE)

romfs: $(TARGET)
$(ROMFSINST) /usr/bin/$(TARGET)

clean:
$(RM) *~ *.o $(TARGET)

OpenCVについて初心者なために稚拙な質問かもしれませんが、ご教示のほどよろしくお願いします。

コメント

at_kojiro.yamada

2018年7月5日 17時08分

> お世話になっております。小関と申します。
>
> Armadillo-810カメラモデル開発セットとATDE5を用いて、カメラからの撮影画像でのHuモーメントを試行しています。
> その際、matchShapes()関数呼び出しで下記エラーが発生してしまいます。
>
> OpenCV Error: Assertion failed (contour1.checkVector(2) >= 0 && contour2.checkVector(2) >= 0 && (contour1.depth() == CV_32F || contour1.depth() == CV_32S) && contour1.depth() == contour2.depth()) in matchShapes, file /build/sh_mobile_ceu sh_mobile_ceu.0: SuperH Mobile CEU driver detached from camera 0
> buildd-opencv_2.3.1-11-armhf-d9JIli/opencv-2.3.1/modules/imgproc/src/contours.cpp, line 1705
> terminate called after throwing an instance of 'cv::Exception' what(): /build/buildd-opencv_2.3.1-11-armhf-d9JIli/opencv-2.3.1/modules/imgproc/src/contours.cpp:1705: error: (-215) contour1.checkVector(2) >= 0 && contour2.checkVector(2) >= 0 && (contour1.depth() == CV_32F || contour1.depth() == CV_32S) && contour1.depth() == contour2.depth() in function matchShapes
>

Assertion failed なので、その直後に続いている 式 が false になることが問題だと思います。

matchShapes()関数内での tgtDst, srcDst が contour1, contour2 で、
おそらく、どちらか(両方の可能性もあります)が、上記 式 がfalseになる要素を持っているのだと思います。

まずは、tgtDst と srcDstについて、
checkVector(2) や Depth() の値を確認してみてはいかがでしょうか?

m-koseki

2018年7月6日 14時03分

> > お世話になっております。小関と申します。
> >
> > Armadillo-810カメラモデル開発セットとATDE5を用いて、カメラからの撮影画像でのHuモーメントを試行しています。
> > その際、matchShapes()関数呼び出しで下記エラーが発生してしまいます。
> >
> > OpenCV Error: Assertion failed (contour1.checkVector(2) >= 0 && contour2.checkVector(2) >= 0 && (contour1.depth() == CV_32F || contour1.depth() == CV_32S) && contour1.depth() == contour2.depth()) in matchShapes, file /build/sh_mobile_ceu sh_mobile_ceu.0: SuperH Mobile CEU driver detached from camera 0
> > buildd-opencv_2.3.1-11-armhf-d9JIli/opencv-2.3.1/modules/imgproc/src/contours.cpp, line 1705
> > terminate called after throwing an instance of 'cv::Exception' what(): /build/buildd-opencv_2.3.1-11-armhf-d9JIli/opencv-2.3.1/modules/imgproc/src/contours.cpp:1705: error: (-215) contour1.checkVector(2) >= 0 && contour2.checkVector(2) >= 0 && (contour1.depth() == CV_32F || contour1.depth() == CV_32S) && contour1.depth() == contour2.depth() in function matchShapes
> >
>
> Assertion failed なので、その直後に続いている 式 が false になることが問題だと思います。
>
> matchShapes()関数内での tgtDst, srcDst が contour1, contour2 で、
> おそらく、どちらか(両方の可能性もあります)が、上記 式 がfalseになる要素を持っているのだと思います。
>
> まずは、tgtDst と srcDstについて、
> checkVector(2) や Depth() の値を確認してみてはいかがでしょうか?

ご回答ありがとうございます。

ご教示いただきました内容について確認しました。
tgtDst depth: CV_8U
srcDst depth: CV_8U
tgtDst checkVector(2) = -1
srcDst checkVector(2) = -1
tgtDst channels = 1
srcDst channels = 1

ご指摘通り "checkVector(2) = -1" が問題になるのかと思いますが、同様な処理をWindowsで確認したところ上記depthなどは同じ値にも関わらず、matchshapes()でのエラーは発生しませんでした。
Wiindowsの動作環境は、VisualStudio 2017 + OpenCV 3.4.1になります。

Armadillo-810でのOpenCV環境とWindows環境の相違による注意点など、遭遇しているエラーに寄与する情報などお持ちではないでしょうか

ご教示よろしくお願いします。

at_ohsawa

2018年7月6日 14時29分

> Armadillo-810でのOpenCV環境とWindows環境の相違による注意点など、遭遇しているエラーに寄与する情報などお持ちではないでしょうか。

OpenCVライブラリのソースコードを見るとOpenCV2.xとOpenCV3.xでcv::matchShapes()の
実装が変っており、windowsでもOpenCV v2.3.1を使うと同じ状況になると思います。

試しにlinux pcで2.3.1でcv::thresholdの結果をcv::matchShapes()に代入するとやはり
同じアサーションに止められます。

checkVector(2)でチェックしているということは、OpenCV2.x系のmatchShapes()にはcv::thresholdの結果を
そのまま代入することができないように見えます。

cv::findContours()で得られる輪郭のvectorならデータ型が合うので使えそうです。cv::thresholdの結果を
cv:findContourで輪郭に変換したらどうなりますか?

m-koseki

2018年7月6日 16時21分

> > Armadillo-810でのOpenCV環境とWindows環境の相違による注意点など、遭遇しているエラーに寄与する情報などお持ちではないでしょうか。
>
> OpenCVライブラリのソースコードを見るとOpenCV2.xとOpenCV3.xでcv::matchShapes()の
> 実装が変っており、windowsでもOpenCV v2.3.1を使うと同じ状況になると思います。
>
> 試しにlinux pcで2.3.1でcv::thresholdの結果をcv::matchShapes()に代入するとやはり
> 同じアサーションに止められます。
>
> checkVector(2)でチェックしているということは、OpenCV2.x系のmatchShapes()にはcv::thresholdの結果を
> そのまま代入することができないように見えます。
>
> cv::findContours()で得られる輪郭のvectorならデータ型が合うので使えそうです。cv::thresholdの結果を
> cv:findContourで輪郭に変換したらどうなりますか?

ご回答ありがとうございます。
OpenCV2.xとOpenCV3.xの違いによるかもしれないということですね。

ご教示いただいたfindContour()を用いてmatchShapes()を呼び出したところ、エラーが発生しませんでした。

vector > tgtDst_contours, srcDst_contours;
findContours(tgtDst, tgtDst_contours, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
findContours(srcDst, srcDst_contours, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);

double matchResult = matchShapes(tgtDst_contours[0], srcDst_contours[0], CV_CONTOURS_MATCH_I1, 0);

しかし、輪郭によるマッチングのためか、期待したマッチング結果とはなりませんでした。

Webでの情報を確認していると、matchShapes()ではグレー画像を扱えるようになっているようなのですが、同じ形(輪郭)でも描いてある模様での差分を取れる方法などありませんでしょうか。
もしくは、Armadillo-810のOpenCV実行環境をOpenCV2.xからOpenCV3.xへ変更することができませんでしょうか。

OpenCV初心者のために手探りでの問合せになってしまい大変恐縮ですが、ご教示のほどよろしくお願いいたします。

at_ohsawa

2018年7月11日 17時16分

> ご回答ありがとうございます。
> OpenCV2.xとOpenCV3.xの違いによるかもしれないということですね。

かもしれないというより、明かにそれが原因です。
OpenCV2.xのcv::matchShapes()の実装は最初にこのassertionを通らないといけないのですが、
checkVector(2)の要件にあうような2次元の1ch画像(つまりグレースケール)は作る事ができないと
思います。

2.xの最新の実装の2.4ですが、コードを見れば明かです。
https://github.com/opencv/opencv/blob/2.4/modules/imgproc/src/contours…

一方で3.xの実装は次のようになっています。
https://github.com/opencv/opencv/blob/3.4/modules/imgproc/src/matchcont…

2.xにあったassertionによるチェックは無くなっており、
cv::moment()の結果を、そのままcv::Humomentに代入して
結果を第三引数で指定した条件で比較するようになっています。

一方で2.xでassertionに書いていた条件は、どこにいったかというと
cv::moment()に移動しており、入力が"輪郭のときだけ"実行する
処理の条件になっています。

cv::moment @ OpenCV3.4
https://github.com/opencv/opencv/blob/3.4/modules/imgproc/src/moments.c…

ここで、グレースケールを2.x系でも入力できるように、3.x系の実装と同等の
呼び出し方にすることを考えると、先の2.x系の実装のassertionを抜けた先の
関数を直接呼ぶと同じ結果になるように見えます。

つまり、cv::matchShapes()ではなく、cvMatchShapes() を使うことでassertionを
回避できそうです。

試しに書いてみたコードを添付します。
元画像と回転縮小した画像のHuMomentの差を計算しています。

ファイル ファイルの説明
ms.zip

m-koseki

2018年7月12日 9時11分

> > ご回答ありがとうございます。
> > OpenCV2.xとOpenCV3.xの違いによるかもしれないということですね。
>
> かもしれないというより、明かにそれが原因です。
> OpenCV2.xのcv::matchShapes()の実装は最初にこのassertionを通らないといけないのですが、
> checkVector(2)の要件にあうような2次元の1ch画像(つまりグレースケール)は作る事ができないと
> 思います。
>
> 2.xの最新の実装の2.4ですが、コードを見れば明かです。
> https://github.com/opencv/opencv/blob/2.4/modules/imgproc/src/contours…
>
> 一方で3.xの実装は次のようになっています。
> https://github.com/opencv/opencv/blob/3.4/modules/imgproc/src/matchcont…
>
> 2.xにあったassertionによるチェックは無くなっており、
> cv::moment()の結果を、そのままcv::Humomentに代入して
> 結果を第三引数で指定した条件で比較するようになっています。
>
> 一方で2.xでassertionに書いていた条件は、どこにいったかというと
> cv::moment()に移動しており、入力が"輪郭のときだけ"実行する
> 処理の条件になっています。
>
> cv::moment @ OpenCV3.4
> https://github.com/opencv/opencv/blob/3.4/modules/imgproc/src/moments.c…
>
> ここで、グレースケールを2.x系でも入力できるように、3.x系の実装と同等の
> 呼び出し方にすることを考えると、先の2.x系の実装のassertionを抜けた先の
> 関数を直接呼ぶと同じ結果になるように見えます。
>
> つまり、cv::matchShapes()ではなく、cvMatchShapes() を使うことでassertionを
> 回避できそうです。
>
> 試しに書いてみたコードを添付します。
> 元画像と回転縮小した画像のHuMomentの差を計算しています。

詳細な情報ありがとうございました。
とても参考になりました。

添付コードを参照し、当方でも動作確認してみたいと思います。
今後ともよろしくお願いします。