OpenCV Sobel 过滤器产生几乎全黑的图像

OpenCV Sobel Filters resulting in almost completely black images

我的 sobel_y(和 sobel_x,但我认为他们有同样的问题)过滤器有一些问题,因为它一直给我一个基本上只有黑色和黑色的图像白色的。我不得不为 class 重写这个函数,所以不,我不能使用内置的函数,并且它可以工作,减去一些小的调整,因为输出图像看起来有点奇怪,甚至仍然是黑白的虽然它应该被转换回来。我想出了如何解决这个问题,在这个过程中我搞砸了一些东西并破坏了它并且似乎无法让它恢复工作即使只有黑白图像输出。我不断收到一张黑色图像,顶部附近有一些白线。我已经尝试将 Mat 灰度类型(第三个参数)更改为所有不同的值,正如我的教授在 class 中提到的,我们正在使用 32 位浮点图像,但这也没有帮助。

虽然问题出现在运行Studentfilter2D之后,但我认为是图像的灰度问题,虽然我每次调试时似乎都可以正常工作。这也是因为我必须使用 Studentfilter2D 编写另外 2 个过滤函数,它们都给了我预期的结果。我的sobel_y函数如下所示:

// Convert the image in bgr to grayscale OK to use the OpenCV function.  
// Find the coefficients used by the OpenCV function, and give a link where you found it.
// Note: This student function expects the matrix gray to be preallocated with the same width and
// height, but with 1 channel.
void BGR2Gray(Mat& bgr, Mat& gray)
{
    // Y = .299 * R + .587 * G + .114 * B, from http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html#cvtcolor
    // Some extra assistance, for the third parameter for the InputArray, from http://docs.opencv.org/trunk/modules/core/doc/basic_structures.html#inputarray
    // Not sure about the fourth parameter, but was just trying it to see if that may be the issue as well
    cvtColor(bgr, gray, CV_BGR2GRAY, 1);
    return;
}
// Convolve image with kernel - this routine will be called from the other
// subroutines!  (gaussian, sobel_x and sobel_y)
// image is single channel.  Do not use the OpenCV filter2D!!
// Implementation can be with the .at or similar to the
// basic method found in the Chapter 2 of the OpenCV tutorial in CANVAS,  
// or online at the OpenCV documentation here: 
// http://docs.opencv.org/doc/tutorials/core/mat-mask-operations/mat-mask operations.html 
// In our code the image and the kernel are both floats (so the sample code   will need to change)
void Studentfilter2D (Mat& image, Mat& kernel)
{
    int kCenterX = kernel.cols / 2;
    int kCenterY = kernel.rows / 2;
    // Algorithm help from http://www.songho.ca/dsp/convolution/convolution.html
    for (int iRows = 0; iRows < image.rows; iRows++)
    {
        for (int iCols = 0; iCols < image.cols; iCols++)
        {
            float result = 0.0;
            for (int kRows = 0; kRows < kernel.rows; kRows++)
            {
                // Flip the rows for the convolution
                int kRowsFlipped = kernel.rows - 1 - kRows;
                for (int kCols = 0; kCols < kernel.cols; kCols++)
                {
                    // Flip the columns for the convolution
                    int kColsFlipped = kernel.cols - 1 - kCols;
                    // Indices of shifting around the convolution
                    int iRowsIndex = iRows + kRows - kCenterY;
                    int iColsIndex = iCols + kCols - kCenterX;
                    // Check bounds using the indices
                    if (iRowsIndex >= 0 && iRowsIndex < image.rows && iColsIndex >= 0 && iColsIndex < image.cols)
                    {
                        result += image.at<float>(iRowsIndex, iColsIndex) * kernel.at<float>(kRowsFlipped, kColsFlipped);
                    }
                }
            }
            image.at<float>(iRows, iCols) = result;
        }
    }
    return;
}

void sobel_y (Mat& image, int)
{
    // Note, the filter parameter int is unused.
    Mat mask = (Mat_<float>(3, 3) << 1, 2, 1,
        0, 0, 0,
        -1, -2, -1) / 3;
    //Mat grayscale(image.rows, image.cols, CV_32FC1);
    BGR2Gray(image, image);
    Studentfilter2D(image, mask);
    // Here is the documentation on normalize http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#normalize
    normalize(image, image, 0, 1, NORM_MINMAX);
    cvtColor(image, image, CV_GRAY2BGR);
    return;
}

就像我说的,我以前做过这个,只是想找一些新鲜的眼光来看待它,看看我可能遗漏了什么。在过去的 4 天里,我一直在查看相同的代码,以至于我认为我只是遗漏了一些东西。如果有人想知道,我也尝试过更改过滤器的掩码值,但无济于事。

有两点值得一提。

首先是您没有适当注意 matrices/images 的类型。 sobel_yStudentfilter2D的输入是CV_8UC1类型的8位灰度图像,意味着数据是unsigned char的数组。 但是,您的 Studentfilter2D 函数正在索引此输入图像,就好像它是 float 类型一样。这意味着它选择了错误的像素来处理

如果以上不能立即解决你的问题,你应该考虑你最终导数图像的范围。因为它是导数,所以它不再在 [0, 255] 范围内。相反,它甚至可能包含负数。当您尝试将其形象化时,您将 运行 陷入困境,除非您首先 规范化您的图像 。 如果您查看文档,OpenCV 中有内置函数可以执行此操作。