Skip to content

Instantly share code, notes, and snippets.

@omaraflak
Last active March 23, 2024 14:44
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 13 You must be signed in to fork a gist
  • Save omaraflak/aca9d0dc8d583ff5a5dc16ca5cdda86a to your computer and use it in GitHub Desktop.
Save omaraflak/aca9d0dc8d583ff5a5dc16ca5cdda86a to your computer and use it in GitHub Desktop.
Image convolution in C++ + Gaussian blur
#include <iostream>
#include <vector>
#include <assert.h>
#include <cmath>
#include <png++/png.hpp>
using namespace std;
typedef vector<double> Array;
typedef vector<Array> Matrix;
typedef vector<Matrix> Image;
Matrix getGaussian(int height, int width, double sigma)
{
Matrix kernel(height, Array(width));
double sum=0.0;
int i,j;
for (i=0 ; i<height ; i++) {
for (j=0 ; j<width ; j++) {
kernel[i][j] = exp(-(i*i+j*j)/(2*sigma*sigma))/(2*M_PI*sigma*sigma);
sum += kernel[i][j];
}
}
for (i=0 ; i<height ; i++) {
for (j=0 ; j<width ; j++) {
kernel[i][j] /= sum;
}
}
return kernel;
}
Image loadImage(const char *filename)
{
png::image<png::rgb_pixel> image(filename);
Image imageMatrix(3, Matrix(image.get_height(), Array(image.get_width())));
int h,w;
for (h=0 ; h<image.get_height() ; h++) {
for (w=0 ; w<image.get_width() ; w++) {
imageMatrix[0][h][w] = image[h][w].red;
imageMatrix[1][h][w] = image[h][w].green;
imageMatrix[2][h][w] = image[h][w].blue;
}
}
return imageMatrix;
}
void saveImage(Image &image, const char *filename)
{
assert(image.size()==3);
int height = image[0].size();
int width = image[0][0].size();
int x,y;
png::image<png::rgb_pixel> imageFile(width, height);
for (y=0 ; y<height ; y++) {
for (x=0 ; x<width ; x++) {
imageFile[y][x].red = image[0][y][x];
imageFile[y][x].green = image[1][y][x];
imageFile[y][x].blue = image[2][y][x];
}
}
imageFile.write(filename);
}
Image applyFilter(Image &image, Matrix &filter){
assert(image.size()==3 && filter.size()!=0);
int height = image[0].size();
int width = image[0][0].size();
int filterHeight = filter.size();
int filterWidth = filter[0].size();
int newImageHeight = height-filterHeight+1;
int newImageWidth = width-filterWidth+1;
int d,i,j,h,w;
Image newImage(3, Matrix(newImageHeight, Array(newImageWidth)));
for (d=0 ; d<3 ; d++) {
for (i=0 ; i<newImageHeight ; i++) {
for (j=0 ; j<newImageWidth ; j++) {
for (h=i ; h<i+filterHeight ; h++) {
for (w=j ; w<j+filterWidth ; w++) {
newImage[d][i][j] += filter[h-i][w-j]*image[d][h][w];
}
}
}
}
}
return newImage;
}
Image applyFilter(Image &image, Matrix &filter, int times)
{
Image newImage = image;
for(int i=0 ; i<times ; i++) {
newImage = applyFilter(newImage, filter);
}
return newImage;
}
int main()
{
Matrix filter = getGaussian(5, 5, 10.0);
cout << "Loading image..." << endl;
Image image = loadImage("image.png");
cout << "Applying filter..." << endl;
Image newImage = applyFilter(image, filter);
cout << "Saving image..." << endl;
saveImage(newImage, "newImage.png");
cout << "Done!" << endl;
}
@mzyil
Copy link

mzyil commented Apr 20, 2018

@ivanp2015 kind of like "dot product of two vectors is not a vector but a scalar" https://i.stack.imgur.com/SFST9.gif

@proogra
Copy link

proogra commented May 19, 2018

hello,
I wan't to do a convolution kernel with silhouette size, how to choose the size , and after i will do the threscholding

@zychen2016
Copy link

could you consider the image borders?

@Himujjal
Copy link

Not a very good algo as it is reducing the image size upon each filter we apply.

@nasirco2020
Copy link

guys , i am new with C++ , when i tried to run this codes i get this massage :
fatal error: png++/png.hpp: No such file or directory
what is the problem ?

@giacom0c
Copy link

giacom0c commented Nov 11, 2018

guys , i am new with C++ , when i tried to run this codes i get this massage :
fatal error: png++/png.hpp: No such file or directory
what is the problem ?

@nasirco2020 You have to include the png++ library. In Ubuntu try with
sudo apt-get install png++
Also, when you compile, don't forget to add the flag -lpng

@atifkarim
Copy link

int newImageHeight = height-filterHeight+1;
int newImageWidth = width-filterWidth+1;

Why output image differs in size from original?
Shouldn't it be the same?

output size will be the same as input if you do padding with the input.

int newImageHeight = (height-filterHeight+2*padding)/(stride) + 1

same formula for width.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment