twistedhat
twistedhat

Reputation: 55

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

I need some help to figure this problem what i have right now. I have 3 images that are the same only the the different things, is that they represent Blue, Green and Red. I need to combine them and get a colored image back. I am using opencv and c++, but now i have this problem that i can't figure it out.

NEEDED: working on edge detection.

---- Update ---- I wrote some new code

  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);

I get this result bad example

But it should be like this. correct one

---- FULL CODE -----

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);

Upvotes: 1

Views: 1460

Answers (1)

Miki
Miki

Reputation: 41765

You are thresholding your sobel_image with threshold min.

However min will (almost) always be 0, since it's the minimum value of the sobel_L1_norm image. Note that a pixel with no gradient will have a value of 0 in sobel_L1_norm.

The solution to this is to choose a meaningful value for the threshold. Since you normalize the values to be in the range [0, 255], you can pick a value in that range (greater than 0).

If you normalize with values in [0,1], pick a value in this interval.


You can use normalize(..., NORM_MINMAX) instead of finding the maximum and rescaling.


Also take care that edgeThreshold will be a matrix of type CV_32F after the call to threshold, so it will be also img_r_edge. To save the image correcly with imwrite, wither use CV_32F images in range [0,1], or CV_8U images in range [0,255]. So you need either to rescale img_r_edge in range [0,1], or convert it to CV_8U.


You're mixing a lot of OpenCV types here. It's usually easier to use Mat_<Tp> to know exactly the type.

You can always work with CV_32F images, with range in [0,1].


Code that will produce correct output, with suggested modifications:

#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;
}

Upvotes: 1

Related Questions