在 x 方向和 y 方向上计算一次第一索贝尔导数,并将这两者结合起来(对于每个通道)

Calculate 1st Sobel derivative once in x and once in y direction and combine these two(for every channel)

本文关键字:方向 通道 起来 结合 于每个 计算 贝尔 一次      更新时间:2023-10-16

我需要一些帮助来解决这个问题我现在有什么。我有 3 张相同的图像,只是不同的东西,它们代表蓝色、绿色和红色。我需要将它们组合起来并取回彩色图像。我正在使用opencv和c ++,但现在我遇到了这个问题,我无法弄清楚。

需要:从事边缘检测工作。

----更新----我写了一些新代码

  Sobel(img_r, x, CV_16S, 1, 0);
  Sobel(img_r, y, CV_16S, 0, 1);
  //Compute the L1 norm
  sobel_L1_norm = abs(x)+abs(y);
  //Find Sobel max value
  minMaxLoc(sobel_L1_norm, &min, &max);
  sobel_L1_norm.convertTo(sobel_image,  CV_32F, 255.0/(max - min), -min * 255.0/(max - min));
  threshold(sobel_image, edgeThreshold, min, 255, THRESH_BINARY);
  edgeThreshold.copyTo(img_r_edge);

我得到这个结果不好的例子

但它应该是这样的。 正确的一个

----完整代码-----

Mat img_r = imread(input_path + "/01.png", CV_LOAD_IMAGE_GRAYSCALE);
Mat img_g = imread(input_path + "/02.png", CV_LOAD_IMAGE_GRAYSCALE);
Mat img_b = imread(input_path + "/03.png", CV_LOAD_IMAGE_GRAYSCALE);
// Edge Images
Mat img_r_edge = Mat::zeros(img_r.size(), CV_8UC1);
Mat img_g_edge = Mat::zeros(img_g.size(), CV_8UC1);
Mat img_b_edge = Mat::zeros(img_b.size(), CV_8UC1);
std::cout << "Step 1 - calculating edge images... ";
  // TODO: 1) Calculate the 1st Sobel derivative once in x and once in y direction and combine these two
  //          (for every channel).
  Mat x;
  Mat y;
  Mat abs_x;
  Mat abs_y;
  Mat sobel_L1_norm;
  Mat sobel_image;
  Mat edgeThreshold;
  double min, max; //Finding min and max Sobel valuye;

  //---------------------------------------------------
  Sobel(img_r, x, CV_16S, 1, 0);
  Sobel(img_r, y, CV_16S, 0, 1);
  //Compute the L1 norm
  sobel_L1_norm = abs(x)+abs(y);
  //Find Sobel max value
  minMaxLoc(sobel_L1_norm, &min, &max);
  sobel_L1_norm.convertTo(sobel_image,  CV_32F, 255.0/(max - min), -min * 255.0/(max - min));
  threshold(sobel_image, edgeThreshold, min, 255, THRESH_BINARY);
  edgeThreshold.copyTo(img_r_edge);
  //----------------------------------------------------

  //       2) Normalize every gradient image and convert the results to CV_8UC1.
  //       3) Threshold the retrieved (normalized) gradient images using the parameter "edgeThreshold".
  //       4) Save the results in the cv::Mats below.
  imwrite(out_r_edge_filename, sobel);
  imwrite(out_g_edge_filename, img_g_edge);
  imwrite(out_b_edge_filename, img_b_edge);

您正在使用阈值min阈值来阈值sobel_image

然而min(几乎)总是0,因为它是sobel_L1_norm图像的最小值。请注意,没有渐变的像素的值为 0 sobel_L1_norm

此问题的解决方案是为阈值选择一个有意义的值。由于将值规范化为在范围[0, 255] 中,因此可以在该范围内选取一个值(大于 0)。

如果使用 [0,1] 中的值进行归一化,则在此区间中选择一个值。


您可以使用normalize(..., NORM_MINMAX)而不是查找最大值并重新缩放。


还要注意,edgeThreshold 将是调用 thresholdCV_32F 类型的矩阵,因此它也将被img_r_edge。要使用imwrite 、 枯萎CV_32F范围 [0,1] 中的图像或范围 [0,255] 中的CV_8U图像来保存图像。因此,您需要在范围[0,1]中重新缩放img_r_edge,或将其转换为CV_8U


你在这里混合了很多OpenCV类型。使用Mat_<Tp>来准确了解类型通常更容易。

您始终可以使用CV_32F图像,范围在 [0,1] 中。


将生成正确输出的代码,并建议修改:

#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;

int main()
{
    Mat3b img = imread(path_to_color_image");
    vector<Mat1b> planes;
    split(img, planes);
    Mat1b img_r = planes[2].clone();
    Mat1b img_g = planes[1].clone();
    Mat1b img_b = planes[0].clone();
    // Edge Images
    Mat1b img_r_edge;
    Mat1b img_g_edge;
    Mat1b img_b_edge;
    // TODO: 1) Calculate the 1st Sobel derivative once in x and once in y direction and combine these two
    //          (for every channel).
    Mat1f dx, dy;
    Mat1f sobel_L1_norm;
    Mat1f sobel_image;
    Mat1f edgeThreshold;
    double min, max; //Finding min and max Sobel valuye;

    //---------------------------------------------------
    Sobel(img_r, dx, CV_32F, 1, 0);
    Sobel(img_r, dy, CV_32F, 0, 1);
    //Compute the L1 norm
    sobel_L1_norm = abs(dx) + abs(dy); // Type 
    // Normalize
    normalize(sobel_L1_norm, sobel_image, 0, 1, NORM_MINMAX);
    // Use a value different from 'min', which will (almost always) be 0.
    double thresh = 0.5;
    threshold(sobel_image, edgeThreshold, thresh, 255, THRESH_BINARY);
    edgeThreshold.convertTo(img_r_edge, CV_8U);
    imwrite("img_r_edge.png", img_r_edge);

    return 0;
}