Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
269 views
in Technique[技术] by (71.8m points)

c++ - Sobel derivative in OpenCV

I have been tasked with making my own Sobel method, and not use the cv::Sobel found in OpenCV. I tried implementing one I found at Programming techniques

When I run the program, cv::Mat throws an error, however. Anyone have any idea why?

Sobel method:

int sobelCorrelation(Mat InputArray, int x, int y, String xory)
{
    if (xory == "x") {
        return InputArray.at<uchar>(y - 1, x - 1) +
            2 * InputArray.at<uchar>(y, x - 1) +
            InputArray.at<uchar>(y + 1, x - 1) -
            InputArray.at<uchar>(y - 1, x + 1) -
            2 * InputArray.at<uchar>(y, x + 1) -
            InputArray.at<uchar>(y + 1, x + 1);
    }
    else if (xory == "y")
    {
        return InputArray.at<uchar>(y - 1, x - 1) +
            2 * InputArray.at<uchar>(y - 1, x) +
            InputArray.at<uchar>(y - 1, x + 1) -
            InputArray.at<uchar>(y + 1, x - 1) -
            2 * InputArray.at<uchar>(y + 1, x) -
            InputArray.at<uchar>(y + 1, x + 1);
    }
    else
    {
        return 0;
    }
}

Calling and processing it in another function:

void imageOutput(Mat image, String path) {
    image = imread(path, 0);
    Mat dst;
    dst = image.clone();
    int sum, gx, gy;
    if (image.data && !image.empty()){

        for (int y = 0; y < image.rows; y++)
            for (int x = 0; x < image.cols; x++)
                dst.at<uchar>(y, x) = 0.0;

        for (int y = 1; y < image.rows - 1; ++y) {
            for (int x = 1; x < image.cols - 1; ++x){ 
                gx = sobelCorrelation(image, x, y, "x");
                gy = sobelCorrelation(image, x, y, "y");
                sum = absVal(gx) + absVal(gy);
                if (sum > 255)
                    sum = 255;
                else if (sum < 0)
                    sum = 0;
                dst.at<uchar>(x, y) = sum;
            }
        }

        namedWindow("Original");
        imshow("Original", image);

        namedWindow("Diagonal Edges");
        imshow("Diagonal Edges", dst);

    }
    waitKey(0);
}

Main:

int main(int argc, char* argv[]) {

    Mat image;

    imageOutput(image, "C:/Dropbox/2-falling-toast-ted-kinsman.jpg");
    return 0;
}

The absVal method:

int absVal(int v)
{
    return v*((v < 0)*(-1) + (v > 0));
}

When run it throws this error:

Unhandled exception at 0x00007FFC9365A1C8 in Miniproject01.exe: Microsoft C++ exception: cv::Exception at memory location 0x000000A780A4F110.

and points to here:

template<typename _Tp> inline
_Tp& Mat::at(int i0, int i1)
{
    CV_DbgAssert( dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] &&
        (unsigned)(i1 * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels()) &&
        CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1());
    return ((_Tp*)(data + step.p[0] * i0))[i1];
}

If anyone have any advice or ideas what I am doing wrong it would be greatly appreciated!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This code snippet is to demonstrate how to compute Sobel 3x3 derivatives convolving the image with Sobel kernels. You can easily extend to different kernel sizes giving the kernel radius as input to my_sobel, and creating the appropriate kernel.

#include <opencv2opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;


void my_sobel(const Mat1b& src, Mat1s& dst, int direction)
{
    Mat1s kernel;
    int radius = 0;

    // Create the kernel
    if (direction == 0)
    {
        // Sobel 3x3 X kernel
        kernel = (Mat1s(3,3) << -1, 0, +1, -2, 0, +2, -1, 0, +1);
        radius = 1;
    }
    else
    {
        // Sobel 3x3 Y kernel
        kernel = (Mat1s(3, 3) << -1, -2, -1, 0, 0, 0, +1, +2, +1);
        radius = 1;
    }

    // Handle border issues
    Mat1b _src;
    copyMakeBorder(src, _src, radius, radius, radius, radius, BORDER_REFLECT101);

    // Create output matrix
    dst.create(src.rows, src.cols);

    // Convolution loop

    // Iterate on image 
    for (int r = radius; r < _src.rows - radius; ++r)
    {
        for (int c = radius; c < _src.cols - radius; ++c)
        {
            short s = 0;

            // Iterate on kernel
            for (int i = -radius; i <= radius; ++i)
            {
                for (int j = -radius; j <= radius; ++j)
                {
                    s += _src(r + i, c + j) * kernel(i + radius, j + radius);
                }
            }
            dst(r - radius, c - radius) = s;
        }
    }
}

int main(void)
{
    Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);

    // Compute custom Sobel 3x3 derivatives
    Mat1s sx, sy;
    my_sobel(img, sx, 0);
    my_sobel(img, sy, 1);

    // Edges L1 norm
    Mat1b edges_L1;
    absdiff(sx, sy, edges_L1);


    // Check results against OpenCV
    Mat1s cvsx,cvsy;
    Sobel(img, cvsx, CV_16S, 1, 0);
    Sobel(img, cvsy, CV_16S, 0, 1);
    Mat1b cvedges_L1;
    absdiff(cvsx, cvsy, cvedges_L1);

    Mat diff_L1;
    absdiff(edges_L1, cvedges_L1, diff_L1);

    cout << "Number of different pixels: " << countNonZero(diff_L1) << endl;

    return 0;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...