在OpenCV中绘制Sobel算子幅度和角度的直方图

时间:2017-09-05 12:39:35

标签: opencv image-processing

我想在OpenCV C ++中绘制直方图。任务是x轴应该是角度,y轴应该是直方图的幅度。我使用Sobel算子计算幅度和角度。现在我如何通过使用幅度和角度绘制直方图?

提前致谢。简单的问题代码是

// Read image
        Mat img = imread("abs.jpg");
    img.convertTo(img, CV_32F, 1 / 255.0);
    /*GaussianBlur(img, img, Size(3, 3), 0, 0, BORDER_CONSTANT);*/
    // Calculate gradients gx, gy
    Mat gx, gy;
    Sobel(img, gx, CV_32F, 1, 0, 1);
    Sobel(img, gy, CV_32F, 0, 1, 1);

    // C++ Calculate gradient magnitude and direction (in degrees)
    Mat mag, angle;
cartToPolar(gx, gy, mag, angle, 1);
imshow("magnitude of image is", mag);
imshow("angle of image is", angle);

1 个答案:

答案 0 :(得分:0)

好的,所以它的第一部分是计算每个的直方图。由于两者已经分开(在他们自己的Mat中),我们不必拆分它们或任何东西,我们可以直接在OpenCV的calcHist函数中使用它们。

通过我们的文件:

void calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false )

所以你必须这样做:

cv::Mat histMag, histAng;
// number of bins of the histogram, adjust to your liking
int histSize = 10;
// degrees goes from 0-360 if radians then change acordingly
float rangeAng[] = { 0, 360} ; 
const float* histRangeAng = { rangeAng };
double minval, maxval;
// get the range for the magnitude
cv::minMaxLoc(mag, &minval, &maxval);
float rangeMag[] = { static_cast<float>(minval), static_cast<float>(maxval)} ; 
const float* histRangeMag = { rangeMag };
cv::calcHist(&mag, 1, 0, cv::NoArray(), histMag, 1, &histSize, &histRangeMag, true, false);
cv::calcHist(&angle, 1, 0, cv::NoArray(), histAng, 1, &histSize, &histRangeAng, true, false);

现在您必须绘制histMaghistAng中的两个直方图。

在turtorial中,我在评论中发布了你在情节中的线条,角度就是这样的:

// Draw the histograms for B, G and R
  int hist_w = 512; int hist_h = 400;
  int bin_w = cvRound( (double) hist_w/histSize );

  cv::Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );

  /// Normalize the result to [ 0, histImage.rows ]
  cv::normalize(histAng, histAng, 0, histImage.rows, cv::NORM_MINMAX, -1, Mat() );

  // Draw the lines
  for( int i = 1; i < histSize; i++ )
  {
      cv::line( histImage, cv::Point( bin_w*(i-1), hist_h - cvRound(histAng.at<float>(i-1)) ) ,
                       cv::Point( bin_w*(i), hist_h - cvRound(histAng.at<float>(i)) ),
                       cv::Scalar( 255, 0, 0), 2, 8, 0  );
  }

使用此功能,您可以对幅度执行相同操作,或者可以将其转换为绘制直方图(如果已提供)的函数。

在文档中他们有另一种选择,要绘制矩形作为箱子,使其适应我们的情况,我们得到类似的东西:

// Draw the histograms for B, G and R
  int hist_w = 512; int hist_h = 400;
  int bin_w = std::round( static_cast<double>(hist_w)/static_cast<double>(histSize) );

  cv::Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );

  /// Normalize the result to [ 0, histImage.rows ]
  cv::normalize(histAng, histAng, 0, histImage.rows, cv::NORM_MINMAX, -1, Mat() );

  for( int i = 1; i < histSize; i++ )
  {
      cv::rectangle(histImage, cv::Point(bin_w*(i-1), hist_h - static_cast<int>(std::round(histAng.at<float>(i-1)))), cv::Point(bin_w*(i), hist_h),);
  }

同样,这也可以以相同的方式完成。这是超级简单的图,如果您需要更复杂或更漂亮的图,您可能需要调用外部库并将数据传递到计算的直方图中。此外,此代码尚未经过测试,因此可能会出现拼写错误或错误,但如果出现问题,只需撰写评论即可找到解决方案。

我希望这会对你有所帮助,并为迟到的回答感到抱歉。