【问题标题】:What's the differences between Opencv Sobel operator and my Sobel operator, the output is differentOpencv Sobel算子和我的Sobel算子有什么区别,输出不一样
【发布时间】:2019-12-04 18:20:59
【问题描述】:

我正在尝试使用 Sobel 掩码在彩色图像中找到边缘,我实现了 Sobel 函数,但 Opencv Sobel 和我之间的输出是不同的。

void Sobel(const Mat &image, Mat &new_image) {
    int gx[3][3] = { -1,0,1,
                     -2,0,2,
                     -1,0,1 };
    int gy[3][3] = { 1,2,1,
                     0,0,0,
                    -1,-2,-1 };
    for (int i = 1; i < image.rows - 1; i++)
        for (int j = 1; j < image.cols - 1; j++) {
            int XR = 0, XG = 0, XB = 0, YR = 0, YG = 0, YB = 0;
            for (int r = -1; r < 2; ++r) {
                for (int c = -1; c < 2; ++c) {
                    XR += gx[r + 1][c + 1] * image.at<Vec3b>(i + r, j + c)[0];
                    YR += gy[r + 1][c + 1] * image.at<Vec3b>(i + r, j + c)[0];

                    XG += gx[r + 1][c + 1] * image.at<Vec3b>(i + r, j + c)[1];
                    YG += gy[r + 1][c + 1] * image.at<Vec3b>(i + r, j + c)[1];

                    XB += gx[r + 1][c + 1] * image.at<Vec3b>(i + r, j + c)[2];
                    YB += gy[r + 1][c + 1] * image.at<Vec3b>(i + r, j + c)[2];
                }
            }
            int sumR = std::abs(XR) + std::abs(YR);
            int sumG = std::abs(XG) + std::abs(YG);
            int sumB = std::abs(XB) + std::abs(YB);

            new_image.at<Vec3b>(i, j)[0] = (sumR < 255 ? sumR>0 ? sumR : 0 : 255);
            new_image.at<Vec3b>(i, j)[1] = (sumG < 255 ? sumG>0 ? sumG : 0 : 255);
            new_image.at<Vec3b>(i, j)[2] = (sumB < 255 ? sumB>0 ? sumB : 0 : 255);
        }
}

int main()
{
    Mat image = imread("valve.png");
    Mat new_image = image.clone();

    //Sobel(image, new_image);
    cv::Sobel(image, new_image, -1, 1, 1);

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

    namedWindow("Sobel", WINDOW_NORMAL);
    imshow("Sobel", new_image);

    waitKey();
    return 0;
}

【问题讨论】:

  • 你的结果是什么?我在您提供的链接中看不到它们。
  • 点击下方链接,有2张照片
  • 我看不到它们:“您的临时相册 0 张照片”您可以直接将它们上传到 Stack Overflow 上吗?
  • 我更改了链接,再试一次
  • 好的,现在我明白了。你也可以发布源图像吗?

标签: c++ opencv


【解决方案1】:

cv::Sobel 在内部使用getDerivKernels 创建滤波器系数,它为两个方向的导数创建一维滤波器掩码。一阶导数的形式为 [-1, 0, 1]。之后它们通过outer product 相乘并形成一个矩阵:

`1 0 -1
 0 0 0
-1 0 1

如果将此矩阵应用于 Sobel 函数并在梯度计算中删除 abs 函数,您将获得与 OpenCV 相同的结果。

void Sobel2(const Mat &image, Mat &new_image) {

double gy[3][3] = { 1,0,-1,
                 0,0,0,
                -1,0,1 };

for (int i = 1; i < image.rows - 1; i++)
    for (int j = 1; j < image.cols - 1; j++) {
        double XR = 0, XG = 0, XB = 0, YR = 0, YG = 0, YB = 0;
        for (int r = -1; r < 2; ++r) {
            for (int c = -1; c < 2; ++c) {
                YR += gy[r + 1][c + 1] * image.at<Vec3b>(i + r, j + c)[0];

                YG += gy[r + 1][c + 1] * image.at<Vec3b>(i + r, j + c)[1];

                YB += gy[r + 1][c + 1] * image.at<Vec3b>(i + r, j + c)[2];
            }
        }

        new_image.at<Vec3b>(i, j)[0] = (YR < 255 ? YR>0 ? YR : 0 : 255);
        new_image.at<Vec3b>(i, j)[1] = (YG < 255 ? YG>0 ? YG : 0 : 255);
        new_image.at<Vec3b>(i, j)[2] = (YB < 255 ? YB>0 ? YB : 0 : 255);
    }
}

以下代码可帮助您了解如何计算过滤器矩阵:

cv::Mat kx, ky;
cv::getDerivKernels(kx, ky, 1, 1, 3);
cv::Mat k = kx * ky.t(); // k is the filter matrix that is used internally in cv::Sobel function

【讨论】:

    猜你喜欢
    • 2020-03-12
    • 2021-08-31
    • 2013-06-09
    • 2023-04-03
    • 2017-06-21
    • 2018-01-31
    • 2022-01-23
    • 2016-10-03
    • 2014-04-18
    相关资源
    最近更新 更多