質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.62%

Raspberry Piのカメラを使って赤色を抽出して、赤色の対象物までの距離を測りたい

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 307

tada20

score 4

Raspberry Piのカメラを使って赤色を抽出して、赤色の対象物までの距離を測りたい

Raspberry Piのカメラで赤色を抽出し、赤色の対象物までの距離を計測するシステムを作っています。
HSVをしきい値とした機能を実装中に以下のエラーメッセージが発生しました。

発生している問題・エラーメッセージ

distance:inf mm
OpenCV Error: Assertion failed (dims <= 2 && step[0] > 0) in locateROI, file /build/opencv-L65chJ/opencv-3.2.0+dfsg/modules/core/src/matrix.cpp, line 949
terminate called after throwing an instance of 'cv::Exception'
  what():  /build/opencv-L65chJ/opencv-3.2.0+dfsg/modules/core/src/matrix.cpp:949: error: (-215) dims <= 2 && step[0] > 0 in function locateROI

中止

該当のソースコード

#include <opencv2/core/core.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <stdio.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <sys/time.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <cmath>
#include <limits>
#include "image_processing.h"

using namespace cv;
using namespace std;
void switch_cam(int);

#define XSIZE 320
#define YSIZE 240

const unsigned short width       = 320;
const unsigned short height      = 240;

int main()
{
    Mat Leftimage(XSIZE,YSIZE,CV_8UC3);
    Mat Rightimage(XSIZE,YSIZE, CV_8UC3);
    Mat frame1;
    Mat frame2;

    wiringPiSetup();
    pinMode(7, OUTPUT);
    pinMode(0, OUTPUT);
    pinMode(1, OUTPUT);
    digitalWrite(1, 1);
    digitalWrite(0, 1);
    pinMode(3, OUTPUT);
    digitalWrite(3, 1);
    pinMode(4, OUTPUT);
    digitalWrite(4, 1);
    pinMode(13, OUTPUT);
    digitalWrite(13, 1);
    pinMode(6, OUTPUT);
    digitalWrite(6, 1);

    VideoCapture cap(0);
    if(!cap.isOpened()){
        return -1;
    }

    namedWindow("Left", 1);
    namedWindow("Right", 1);

    int camera = 1;
    int flg = 0;
    while(1){

        double left_center_x, right_center_x;

        Mat LeftCam, RightCam;
        cap.set(CV_CAP_PROP_FRAME_WIDTH, XSIZE);
        cap.set(CV_CAP_PROP_FRAME_HEIGHT, YSIZE);
        switch_cam(camera);

        if(camera == 0){
            cap >> LeftCam;
            //imshow("Left", LeftCam);            
            frame1 = LeftCam.clone();
        }

        if(camera == 1){
            cap >> RightCam;
            //imshow("Right", RightCam);
            frame2 = RightCam.clone();
        }

        if(camera==2){

            Mat gray_left;
            Mat bin_left;
            cvtColor(Leftimage, gray_left, CV_RGB2GRAY);
            threshold(gray_left, bin_left, 0, 255, THRESH_BINARY|THRESH_OTSU);

            Mat gray_right;
            Mat bin_right;
            cvtColor(Rightimage, gray_right, CV_RGB2GRAY);
            threshold(gray_right, bin_right, 0, 255, THRESH_BINARY|THRESH_OTSU);

            hsv_threshold threshold0 = {120, 180, 80, 50};

            Mat binary1, binary2;
            Mat hsv_gray1, hsv_gray2;
            Mat gray1, gray2;

            hsv_gray1 = extract_color(frame1, threshold0);
            hsv_gray2 = extract_color(frame2, threshold0);
            threshold(hsv_gray1, binary1, 128, 255, THRESH_BINARY);
            threshold(hsv_gray2, binary2, 128, 255, THRESH_BINARY);
            cvtColor(binary1, gray1, CV_GRAY2BGR);
            cvtColor(binary2, gray2, CV_GRAY2BGR);

            int xmax1=0, xmin1=319, ymin1=279, ymax1=0;
            for(int y = 0; y < binary1.rows; y++){
                for(int x = 0; x < binary1.cols; x++){
                    if(gray1.at <Vec3b>(y, x)[0] > 0){
                        xmax1 = x > xmax1 ? x : xmax1;
                        xmin1 = x < xmin1 ? x : xmin1;
                        ymax1 = y > ymax1 ? y : ymax1;
                        ymin1 = y < ymin1 ? y : ymin1;
                    }
                }
            }

            int xmax2=0, xmin2=319, ymin2=279, ymax2=0;
            for(int y = 0; y < binary2.rows; y++){
                for(int x = 0; x < binary2.cols; x++){
                    if(gray2.at <Vec3b>(y, x)[0] > 0){
                        xmax2 = x > xmax2 ? x : xmax2;
                        xmin2 = x < xmin2 ? x : xmin2;
                        ymax2 = y > ymax2 ? y : ymax2;
                        ymin2 = y < ymin2 ? y : ymin2;
                    }
                }
            }

            double d1=0.0;
            int xl1, yl1;
            xl1 = xmax1 - xmin1;
            yl1 = ymax1 - ymin1;
            d1 = sqrt(xl1 * xl1 + yl1 * yl1);

            double radius1=d1/2.0;

            double center_x1=(double)(xmax1-xmin1)/2.0+xmin1;
            double center_y1=(double)(ymax1-ymin1)/2.0+ymin1;
            right_center_x = center_x1;

            double d2=0.0;
            int xl2, yl2;
            xl2 = xmax2 - xmin2;
            yl2 = ymax2 - ymin2;
            d2 = sqrt(xl2 * xl2 + yl2 * yl2);

            double radius2=d2/2.0;

            double center_x2=(double)(xmax2-xmin2)/2.0+xmin2;
            double center_y2=(double)(ymax2-ymin2)/2.0+ymin2;
            left_center_x = center_x2;

            circle(binary1, Point((int)center_x1, (int)center_y1), (int)radius1, Scalar(200,0,200), 1, CV_AA);
            circle(binary2, Point((int)center_x2, (int)center_y2), (int)radius2, Scalar(200,0,200), 1, CV_AA);

            std::cout << "right_center_x: " << center_x1 << " right_center_y: " << center_y1 << std::endl;
            std::cout << "right_center_x: " << center_x2 << " right_center_y: " << center_y2 << std::endl;

            imshow("gray_left",    binary1);
            imshow("gray_right",    binary2);
            while(waitKey(0)!=27);
        }

        double distance = 9000.0/(left_center_x-right_center_x);
        if(distance<0) distance -= distance*2;
        cout << "distance:" << distance << " mm" <<endl;

        //cout << "camera:" << camera << endl;
        camera++;
        camera = camera % 3;
        flg++;
        //if(flg > 20 ) flg = 20;
ls
        //waitKey(10);
        if(waitKey(1) == 27) break;
   }
    return 0;
}

void switch_cam(int cam)
{
    if(cam == 0){
        system("i2cset -y 1 0x70 0x00 0x04");
        digitalWrite(7, 0);
        digitalWrite(0, 0);
        digitalWrite(1, 1);
    }
    else if( cam == 1){
        system("i2cset -y 1 0x70 0x00 0x06");
        digitalWrite(7, 0);
        digitalWrite(0, 1);
        digitalWrite(1, 0);
    }
}

試したこと

1つにまとめている関数(camera==2)のところを、別々の関数に分けて書いたところ、エラーは消えてプログラム自体は動いたが、右カメラだけ真っ黒になった。(これはおそらく右カメラの赤色に対するHSVのしきい値が抽出するのに適した値に設定できていないためだと思われる。)

※左カメラは映りもクリアで、赤色もすぐに抽出できたため、右カメラと左カメラは、かなりの個体差があると思われる。

補足情報(FW/ツールのバージョンなど)

Raspberry Pi 3

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • yuki23

    2020/01/08 15:18

    質問は何ですか?

    キャンセル

  • tada20

    2020/01/08 15:36

    エラーの意味がわからないので教えていただきたいです。また、hsv_threshold threshold0 = {120, 180, 80, 50};で赤色を抽出するためのしきい値を適切な値に設定したいのですが、どうすればよいでしょうか

    hsv_thresholdは構造体で、第一引数から順に、Hの最小値、Hの最大値、Sの値、Vの値としています。

    キャンセル

  • fana

    2020/01/09 11:04

    (物理的に可能なのかどうか不明ですが)カメラの個体差を疑うなら,とりあえず左右カメラを入れ替えてみたらどうなるのか?を見てみるとか.

    キャンセル

回答 1

0

エラーの意味がわからないので教えていただきたいです。

私の手元には動かす環境もないし、する気もないので代わりにデバッグしてあげることはしませんが、
ご自分でGDBなどでステップ実行されてみれば、発生している箇所がわかるでしょう。
OpenCVの関数を呼んでいるところで例外が発生するはずです。
そこで渡している引数を確認してみれば、おかしな値を渡していることに気づくはずです。

ご自分で推測されているとおり、物体が抽出できなかった場合のことを全く考慮していないので、その時の値がおかしいのではないでしょうか。
たぶん、cv::circle に渡す座標なり半径なりが原因ではないかと思います(あてずっぽうです)

また、hsv_threshold threshold0 = {120, 180, 80, 50};で赤色を抽出するためのしきい値を適切な値に設定したいのですが、どうすればよいでしょうか

一般論としては、対象物の性質とカメラの特性によって変わります、としか言えません。
あなたのやりたいこととしては、同じ物体を同じ距離で撮影したとき、両方のカメラで同じ大きさで抽出されることを期待しているはずです。
ならば、そうなるように調整すればよいでしょう。

また、カメラがおかしいことがわかっているのならば、直すなり、買い換えるなり、他のものを買うなりすることも考慮してください。
他にも、照明の当て方、レンズの選び方など覚えなければいけないことは無数にあります。画像処理の開発において、プログラムだけいじっていればいいという考えは捨ててください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.62%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る