Sobel在OpenCV中的衍生工具

时间:2015-10-06 14:26:27

标签: c++ opencv sobel

我的任务是制作自己的Sobel方法,而不是使用OpenCV中的cv :: Sobel。 我尝试实现我在Programming techniques

找到的一个

当我运行程序时,cv :: Mat会抛出错误。任何人都知道为什么?

Sobel方法:

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

在另一个函数中调用和处理它:

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

主:

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

    Mat image;

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

absVal方法:

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

运行时会抛出此错误: &#34; Miniproject01.exe中0x00007FFC9365A1C8处的未处理异常:Microsoft C ++异常:cv ::内存位置0x000000A780A4F110处的异常。&#34; 并指向这里:

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

如果有人有任何建议或想法我做错了,我们将不胜感激!

2 个答案:

答案 0 :(得分:1)

此代码片段用于演示如何计算使用Sobel内核对图像进行卷积的Sobel 3x3衍生产品。您可以轻松扩展到不同的内核大小,将内核半径作为my_sobel的输入,并创建适当的内核。

#include <opencv2\opencv.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;
}

答案 1 :(得分:1)

如果我是你,我几乎总是避免使用for循环(如果可能的话)。不必要的循环往往会减慢执行速度。相反,尽可能重用。例如,下面的代码使用filter2D给出2d Correlation结果:

Mat kern = (Mat_<float>(3,3)<<-1,0,1,-2,0,2,-1,0,1);
Mat dest;
cv::filter2D(src,dest,src.type(),kern);

如果你想获得卷积结果,你需要翻转内核&#39; kern&#39;在过滤之前。

cv::flip(kern,kern, -1);

如果您想要提高性能,可以使用可分离的过滤器&sefFilter2D&#39;。