c++ - 高斯平滑输出未对齐

标签 c++ opencv convolution blur gaussianblur

我试图在不使用任何opencv函数(显示图像除外)的情况下对此图像执行高斯平滑。

input image

但是,在用高斯内核对图像进行卷积后得到的输出如下:

output image

输出图像似乎未对齐,看起来很奇怪。知道发生了什么吗?

生成高斯内核:

double gaussian(int x, int y,double sigma){
    return (1/(2*M_PI*pow(sigma,2)))*exp(-1*(pow(x,2)+pow(y,2))/(2*pow(sigma,2)));
}



double generateFilter(vector<vector<double>> & kernel,int width,double sigma){
    int value = 0;
    double total =0;

    if(width%2 == 1){
        value = (width-1)/2;
    }else{
        value = width/2;
    }

    double smallest = gaussian(-1*value,-1*value,sigma);

    for(int i = -1*value; i<=value; i++){
        vector<double> temp;
        for(int k = -1*value; k<=value; k++){
            int gVal = round(gaussian(i,k,sigma)/smallest);
            temp.push_back(gVal);
            total += gVal;

        }
        kernel.push_back(temp);

    }

    cout<<total<<endl;

    return total;


}

卷积:
vector<vector<unsigned int>>  convolution(vector<vector<unsigned int>> src,  vector<vector<double>> kernel,double total){
    int kCenterX = floor(kernel.size() / 2); //center of kernel
    int kCenterY = kCenterX; //center of kernel
    int kRows = kernel.size(); //height of kernel
    int kCols = kRows; //width of kernel
    int imgRows = src.size(); //height of input image
    int imgCols = src[0].size(); //width of input image
    vector<vector<unsigned int>> dst = vector<vector<unsigned int>> (imgRows, vector<unsigned int>(imgCols ,0));


    for ( size_t row = 0; row < imgRows; row++ ) { 
        for ( size_t col = 0; col < imgCols; col++ ) {
        float accumulation = 0;
        float weightsum = 0; 
        for ( int i = -1*kCenterX; i <= 1*kCenterX; i++ ) {
            for ( int j = -1*kCenterY; j <= 1*kCenterY; j++ ) {
                int k = 0;

                if((row+i)>=0 && (row+i)<imgRows && (col+j)>=0 && (col+j)<imgCols){
                    k = src[row+i][col+j];
                    weightsum += kernel[kCenterX+i][kCenterY+j];
                }

                accumulation += k * kernel[kCenterX +i][kCenterY+j];


            }
        } 
        dst[row][col] = round(accumulation/weightsum);
        }

    }

    return dst;
}

谢谢。

最佳答案

卷积函数基本上是正确的,因此问题在于输入和输出格式。

  • 确保您以灰度(而不是RGB)读取图像:
    cv::Mat I = cv::imread("img.png", cv::IMREAD_GRAYSCALE);
    
  • 您正在将vector<vector<unsigned int>>参数传递给convolution
    我不能说这是否是问题的一部分,但建议您传递cv::Mat类型的参数(并返回cv::Mat):
    cv::Mat convolution(cv::Mat src, vector<vector<double>> kernel, double total)
    

    我假设您可以将输入与vector<vector<unsigned int>>进行相互转换,但这不是必需的。

  • 这是一个工作代码示例:
    #include <vector>
    #include <iostream>
    
    #include "opencv2/opencv.hpp"
    #include "opencv2/highgui.hpp"
    
    using namespace std;
    
    
    double gaussian(int x, int y, double sigma) {
        return (1 / (2 * 3.141592653589793*pow(sigma, 2)))*exp(-1 * (pow(x, 2) + pow(y, 2)) / (2 * pow(sigma, 2)));
    }
    
    
    double generateFilter(vector<vector<double>> & kernel, int width, double sigma)
    {
        int value = 0;
        double total = 0;
    
        if (width % 2 == 1) {
            value = (width - 1) / 2;
        }
        else {
            value = width / 2;
        }
    
        double smallest = gaussian(-1 * value, -1 * value, sigma);
    
        for (int i = -1 * value; i <= value; i++) {
            vector<double> temp;
            for (int k = -1 * value; k <= value; k++) {
                int gVal = round(gaussian(i, k, sigma) / smallest);
                temp.push_back(gVal);
                total += gVal;
            }
            kernel.push_back(temp);    
        }
    
        cout << total << endl;
    
        return total;
    }
    
    
    //vector<vector<unsigned int>>  convolution(vector<vector<unsigned int>> src,  vector<vector<double>> kernel, double total) {
    cv::Mat convolution(cv::Mat src, vector<vector<double>> kernel, double total) {
        int kCenterX = floor(kernel.size() / 2); //center of kernel
        int kCenterY = kCenterX; //center of kernel
        int kRows = kernel.size(); //height of kernel
        int kCols = kRows; //width of kernel
        int imgRows = src.rows;//src.size(); //height of input image
        int imgCols = src.cols;//src[0].size(); //width of input image
        //vector<vector<unsigned int>> dst = vector<vector<unsigned int>> (imgRows, vector<unsigned int>(imgCols ,0));
        cv::Mat dst = cv::Mat::zeros(src.size(), CV_8UC1);  //Create destination matrix, and fill with zeros (dst is Grayscale image with byte per pixel).
    
        for (size_t row = 0; row < imgRows; row++) {
            for (size_t col = 0; col < imgCols; col++) {
                double accumulation = 0;
                double weightsum = 0;
                for (int i = -1 * kCenterX; i <= 1 * kCenterX; i++) {
                    for (int j = -1 * kCenterY; j <= 1 * kCenterY; j++) {
                        int k = 0;
    
                        if ((row + i) >= 0 && (row + i) < imgRows && (col + j) >= 0 && (col + j) < imgCols) {
                            //k = src[row+i][col+j];
                            k = (int)src.at<uchar>(row + i, col + j);   //Read pixel from row [row + i] and column [col + j]
                            weightsum += kernel[kCenterX + i][kCenterY + j];
                        }
    
                        accumulation += (double)k * kernel[kCenterX + i][kCenterY + j];
                    }
                }
                //dst[row][col] = round(accumulation/weightsum);
                dst.at<uchar>(row, col) = (uchar)round(accumulation / weightsum);   //Write pixel from to row [row] and column [col]
    
                //dst.at<uchar>(row, col) = src.at<uchar>(row, col);
            }
    
        }
    
        return dst;
    }
    
    
    int main()
    {
        vector<vector<double>> kernel;
        double total = generateFilter(kernel, 11, 3.0);
    
        //Read input image as Grayscale (one byte per pixel).
        cv::Mat I = cv::imread("img.png", cv::IMREAD_GRAYSCALE);
    
        cv::Mat J = convolution(I, kernel, total);
    
        //Display input and output
        cv::imshow("I", I);
        cv::imshow("J", J);
        cv::waitKey(0);
        cv::destroyAllWindows();
    
        return 0;
    }
    

    结果:
    enter image description here

    关于c++ - 高斯平滑输出未对齐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60471248/

    相关文章:

    python - 从源代码 : ModuleNotFoundError: No module named 'cv2' 构建 opencv

    matlab - 为什么 OpenCV 中的 filter2D 给出的结果与 Matlab 中的 imfilter 不同?

    Tensorflow:如何处理多个输入

    c++ - linux flex gcc 编译失败,出现 `undefined reference to ` TclReError'`

    c++ - 如何在 if () 语句中声明变量?

    c++ - Metro C++/XAML ListView 捕捉项

    python - OpenCV HoughCircles 偶尔会返回 [0. 0. 0.]

    c++ - 为什么我的 while 循环永远不会结束,即使生成的整数不符合运行条件

    python+openCV : only size-1 arrays can be converted to Python scalars

    python - keras和scipy的2D卷积结果不同