3

opencv cannyedge 検出を使用して非方向エッジの数をカウントする方法を教えてもらえますか? 私はopencvからのcannyEdgeイメージを持っています。エッジの方向に基づいたヒストグラムが欲しいので、方向性と非方向性のエッジの数を数えることができます。

4

1 に答える 1

38

エッジ検出と勾配検出を混同していると思います。Canny は勾配の大きさに基づいてエッジ マップを提供します (通常は Sobel 演算子を使用しますが、他の演算子を使用することもできます)。これは、Canny が方向情報を提供できないしきい値勾配の大きさの情報のみを返すためです。

編集:キャニー アルゴリズムは非最大抑制ステップに勾配方向を使用することを明確にする必要があります。ただし、 の OpenCV 実装でCannyは、この方向情報が隠され、エッジ マグニチュード マップのみが返されます。

勾配の大きさと方向を取得する基本的なアルゴリズムは次のとおりです。

  1. X 方向のソーベルを計算します ( Sx)。
  2. Y 方向のソーベルを計算します ( Sy)。
  3. 勾配の大きさ を計算しsqrt(Sx*Sx + Sy*Sy)ます。
  4. で勾配方向を計算しarctan(Sy / Sx)ます。

このアルゴリズムは、次の OpenCV 関数を使用して実装できます:ソーベルマグニチュード、およびフェーズ

以下は、勾配の大きさと位相を計算し、勾配方向の粗いカラー マッピングを示すサンプルです。

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <iostream>
#include <vector>

using namespace cv;
using namespace std;

Mat mat2gray(const cv::Mat& src)
{
    Mat dst;
    normalize(src, dst, 0.0, 255.0, cv::NORM_MINMAX, CV_8U);

    return dst;
}

Mat orientationMap(const cv::Mat& mag, const cv::Mat& ori, double thresh = 1.0)
{
    Mat oriMap = Mat::zeros(ori.size(), CV_8UC3);
    Vec3b red(0, 0, 255);
    Vec3b cyan(255, 255, 0);
    Vec3b green(0, 255, 0);
    Vec3b yellow(0, 255, 255);
    for(int i = 0; i < mag.rows*mag.cols; i++)
    {
        float* magPixel = reinterpret_cast<float*>(mag.data + i*sizeof(float));
        if(*magPixel > thresh)
        {
            float* oriPixel = reinterpret_cast<float*>(ori.data + i*sizeof(float));
            Vec3b* mapPixel = reinterpret_cast<Vec3b*>(oriMap.data + i*3*sizeof(char));
            if(*oriPixel < 90.0)
                *mapPixel = red;
            else if(*oriPixel >= 90.0 && *oriPixel < 180.0)
                *mapPixel = cyan;
            else if(*oriPixel >= 180.0 && *oriPixel < 270.0)
                *mapPixel = green;
            else if(*oriPixel >= 270.0 && *oriPixel < 360.0)
                *mapPixel = yellow;
        }
    }

    return oriMap;
}

int main(int argc, char* argv[])
{
    Mat image = Mat::zeros(Size(320, 240), CV_8UC1);
    circle(image, Point(160, 120), 80, Scalar(255, 255, 255), -1, CV_AA);

    imshow("original", image);

    Mat Sx;
    Sobel(image, Sx, CV_32F, 1, 0, 3);

    Mat Sy;
    Sobel(image, Sy, CV_32F, 0, 1, 3);

    Mat mag, ori;
    magnitude(Sx, Sy, mag);
    phase(Sx, Sy, ori, true);

    Mat oriMap = orientationMap(mag, ori, 1.0);

    imshow("magnitude", mat2gray(mag));
    imshow("orientation", mat2gray(ori));
    imshow("orientation map", oriMap);
    waitKey();

    return 0;
}

円の画像を使用する:
ここに画像の説明を入力

これにより、次のマグニチュードと方向のイメージが得られます。
マグニチュード オリエンテーション

最後に、グラデーション方向マップは次のとおりです。
地図

更新 : Abid は実際に、「ここでのオリエンテーションとは何を意味するのか?」というコメントで素晴らしい質問をしました。これについては、さらに議論する必要があると思いました。phase正のy軸が下、正のx軸が右の通常の画像処理の観点から、関数は座標フレームを切り替えないと仮定しています。この仮定により、円の周りの勾配方向ベクトルを示す次の画像が得られます。

ここに画像の説明を入力

軸が数学の授業で通常使用されているものとは反転しているため、これに慣れるのは難しい場合があります...したがって、勾配方向は、勾配面に対する法線ベクトルが変化を増加させる方向になす角度です。

お役に立てば幸いです。

于 2012-06-22T13:45:55.530 に答える