Brykyz
Brykyz

Reputation: 657

2D Blur convolution with separable kernel

I am trying to make blur convolution with custom float array.

My array is defined as float array[width*height]. I edited these functions, so it can work with custom array, and not only OpenCV cv::Mat

My code looks like this:

int reflect(int M, int x)
{
    if(x < 0)
    {
        return -x - 1;
    }
    if(x >= M)
    {
        return 2*M - x - 1;
    }

    return x;
}

void separable2DConvolution(float * data, Size dataSize, float *kernel, int kernelSize)
{
    // make copy of original image
    float * dataCopy = new float[dataSize.width()*dataSize.height()];
    memcpy(dataCopy, data, dataSize.width()*dataSize.height());
    float * temp = new float[dataSize.width()*dataSize.height()];
    memcpy(temp, data, dataSize.width()*dataSize.height());

    float sum;
    int x1, y1;
    int kernelRadius = floor(kernelSize/2);

    // along y - direction
    for(int y = 0; y < dataSize.height(); y++){
        for(int x = 0; x < dataSize.width(); x++){
            sum = 0.0;
            for(int i = -kernelRadius; i <= kernelRadius; i++){
                y1 = reflect(dataSize.height(), y - i);
                sum = sum + kernel[i + kernelRadius]*dataCopy[y1*x+y1];
            }
            temp[y*x+y] = sum;
        }
    }

    // along x - direction
    for(int y = 0; y < dataSize.height(); y++){
        for(int x = 0; x < dataSize.width(); x++){
            sum = 0.0;
            for(int i = -kernelRadius; i <= kernelRadius; i++){
                x1 = reflect(dataSize.width(), x - i);
                sum = sum + kernel[i + kernelRadius]*temp[x1*y+x1];
            }
            data[x*y+y] = sum;
        }
    }

    delete [] temp;
    delete [] dataCopy;
}

Array is passed to separable2DConvolution as data, Size is custom class with defined width and height (both are valid and greater than 0), kernel is normalized Gaussian array (almost same as the one from cv::getGaussianKernel) and kernelSize is size of Gaussian array (I'm using size 11).

I use this function to replace cv::sepFilter2D from OpenCV, but somehow, output is different. After using my function, I am converting image to see difference.

OpenCV output has (as expected) "blurred" values, but with the very same input passed to my function, the first third is noised (not blurred at all) and the other part of image is intact.

What's problem with my code?

Thank you for your help!

Upvotes: 1

Views: 648

Answers (1)

1201ProgramAlarm
1201ProgramAlarm

Reputation: 32732

Your subscripting for saving the pixel sums is wrong. temp[y*x+y] will write all the results for the first column to the first pixel (temp[0]). Many other pixels will be unchanged. You probably want temp[y * dataSize.width() + x], with a similar change for data[x*y+y] in the next loop and when calculating subscripts to read the pixel values.

Unrelated, you don't need to memcpy the bitmap to make copies since you should be writing to every pixel in the image. You don't need dataCopy at all, since the original data array hasn't been changed yet.

Using floor is overkill for an integer. Since kernelSize is positive, you can just say int kernelRadius = kernelSize / 2; since this will round down.

Upvotes: 2

Related Questions