C++ Image filtering algorithm

Viewed 3635

I'm busy trying to implement an image filtering algorithm that works as follows: A filter is a 2-dimensional array of size N (N has to be an odd number), therefore having N*N elements. An example filter of size 3 would be:

0.25 1 0.25
0.25 0 0.25
0.25 1 0.25

For every unsigned char (pixel) in the image data, place the center of the filter array at the current working pixel. Then for every pixel that the filter covers in the image, find the weighted sum of all the pixels covered by the filter (i.e each filter value multiplied by the pixel it is currently covering) and set your current working image pixel value to that weighted sum. Do this for every pixel in the image. If a filter pixel falls out of range of the image 2D array (i.e off left, right, top, bottom), then it must wrap around the appropriate edge of the image.

So I have the following code:

Image Image::operator%(const Filter & g) {
    Image filtered = *this;
    std::vector<std::vector<float>> filter = g.get_filter();
    Image::iterator beg = filtered.begin();
    Image::iterator end = filtered.end();
    unsigned char* pixel_data = filtered.data.get();
    int pixel_index = 0;

    while(beg != end) {
        // current working pixel value
        unsigned char* c_pixel = *beg;

        float weight = 0;

        // starting x and y position (top left) relative to the centre
        // of the filter at index 'pixel'
        int start_y = pixel_index - (g.get_size()-1) / 2;
        int start_x = pixel_index - (g.get_size()-1) / 2;

        for(int row = 0; row < g.get_size(); ++row) {
            std::vector<float> r = filter.at(row);
            int c_row = start_y + row;

            if(c_row >= height) {
                c_row %= height;
            } else if(c_row < 0) {
                c_row += height;
            }

            for(int col = 0; col < g.get_size(); ++col) {
                // current column of filter relative
                // to the image pixel
                int c_col = start_x + col;

                if(c_col >= width) {
                    c_col %= width;
                } else if(c_col < 0) {
                    c_col += width;
                }
                weight += pixel_data[this->index(c_col, c_row)]*r.at(col);
            }
        }
        *c_pixel = weight;
        ++beg;
        ++pixel_index;
    }
    return filtered;
}

In-case you are wondering, this->index(c_col, c_row) is treating a 1D array as a 2D array:

int Image::index(int x, int y) {
    return width*y + x;
}

... and the image data is protected by a std::unique_ptr<unsigned char[]>. This code gives me some strange output. The resulting image has vertical streaks of different pixel colors, somewhat resembling the original image color. I have no idea what I am doing wrong, because this method checks out on paper but not in code. I'll be glad to add any extra information if needed. :)

1 Answers
Related