topical media & game development

talk show tell print

basic-visual-04-discreteconvolution.c

? / basic-visual-04-discreteconvolution.c


  // ------------------------------------------------------------------------
  // This program is complementary material for the book:
  //
  // Frank Nielsen
  //
  // Visual Computing: Geometry, Graphics, and Vision
  //
  // ISBN: 1-58450-427-7
  //
  // Charles River Media, Inc.
  //
  //
  // All programs are available at www.charlesriver.com/visualcomputing/
  //
  // You may use this program for ACADEMIC and PERSONAL purposes ONLY. 
  //
  //
  // The use of this program in a commercial product requires EXPLICITLY
  // written permission from the author. The author is NOT responsible or 
  // liable for damage or loss that may be caused by the use of this program. 
  //
  // Copyright (c) 2005. Frank Nielsen. All rights reserved.
  // ------------------------------------------------------------------------
   
  // ------------------------------------------------------------------------
  // File: discreteconvolution.cpp
  // 
  // Description: A simple program to perform a discrete convolution on images.
  // ------------------------------------------------------------------------
  
  include <stdafx.h>
  include <fstream>
  include <math.h>
  
  using namespace std;
  
  void SaveImagePPM(unsigned char * data, int w, int h, char * file);
  unsigned char * LoadImagePPM(char *ifile,  int &w, int &h);
  
  char filenameinput[]="convolution-input.ppm";
  char filenameoutput[]="convolution-result.ppm";
  
  class filter {public:
  int d;
  double **array;
  
  filter(int dim)
  {d=dim;
  array=new double *[d];
  for(int i=0;i<d;i++) array[i]=new double[d];
  }
  
  void normalize(double n)
  {int i,j;
  
  if (n==0.0){
  for(i=0;i<d;i++)
  for(j=0;j<d;j++)
          n+=array[i][j];
  }
  
  n=1.0/n;
  
  for(i=0;i<d;i++)
  for(j=0;j<d;j++)
          array[i][j]*=n;
  }
  
  Write()
  {
  int i,j;
  
  for(i=0;i<d;i++)
  {
          printf("\n");
          for(j=0;j<d;j++)
  {
  printf("\%lf\t",array[i][j]);
  }}
  printf("\n");
  }
  
  };
  
  void DiscreteConvolution(unsigned char * imgs, int w, int h, unsigned char * imgr, filter * F)
  {
  int i,j,k,l,band;
  int s,index;
  double accum;
  
  s=(F->d-1)/2;
  
  for(band=0;band<3;band++) //RGB
  {
          // for all pixels
  for(i=0;i<h;i++)
          for(j=0;j<w;j++)
          {
                  accum=0.0; index=-1;
                  // convolve
          for(k=-s;k<=s;k++)
                  for(l=-s;l<=s;l++)
                  {
                  if ((i+k>=0)&&(i+k<h)&&(j+l>=0)&&(j+l<w))
                  {
                  index=3*((i+k)*w+j+l);
                  accum += (F->array[k+s][l+s]*imgs[index+band]);
                  }
  
                  index=3*(i*w+j);
                  
                  // clamping
                  if (accum<0) accum=0.0; 
                  if (accum>255) accum=255.0;
                  imgr[index+band]=(unsigned char)accum;
                  
                  }
          }
  }
  }
  
  //
  // discrete convolution test program
  //
  int _tmain(int argc, _TCHAR* argv[])
  {
  int w,h;
  unsigned char *imgsource, * imgresult;
  filter *kernel;
  
  cout<<"Visual Computing: Geometry, Graphics, and Vision (ISBN:1-58450-427-7)"<<endl;
  cout<<"Demo program\n\n"<<endl;
  
  cout<<"Convolving an input image with a kernel."<<endl;
  
  // Laplacian kernel
  kernel=new filter(3);
  kernel->array[0][0]=0;
  kernel->array[0][1]=-1;
  kernel->array[0][2]=0;
  
  kernel->array[1][0]=-1;
  kernel->array[1][1]=4;
  kernel->array[1][2]=-1;
  
  kernel->array[2][0]=0;
  kernel->array[2][1]=-1;
  kernel->array[2][2]=0;
  
  // Identity kernel
  /*
  kernel=new filter(3);
  kernel->array[0][0]=0;kernel->array[0][1]=0;kernel->array[0][2]=0;
  kernel->array[1][0]=0;kernel->array[1][1]=1;kernel->array[1][2]=0;
  kernel->array[2][0]=0;kernel->array[2][1]=0;kernel->array[2][2]=0;
  */
  
  imgsource=LoadImagePPM(filenameinput,w,h);
  
  imgresult=new unsigned char [3*w*h];
  DiscreteConvolution(imgsource,w,h,imgresult, kernel);
  
  SaveImagePPM(imgresult,w,h,filenameoutput);
  
  delete [] imgresult;
  
  char line[256];
  cout<<"Press Return key"<<endl;
  gets(line);
  
          return 0;
  }
  
  // Save a PPM Image
  void SaveImagePPM(unsigned char * data, int w, int h, char * file)
  {
          ofstream OUT(file, ios::binary);
          if (OUT){
      OUT << "P6" << endl << w << ' ' << h << endl << 255 << endl;
          OUT.write((char *)data, 3*w*h);
          OUT.close();}
  }
  
  // Load a PPM Image that does not contain comments.
  unsigned char * LoadImagePPM(char *ifile,  int &w, int &h)
  {
           char dummy1=0, dummy2=0; int maxc;
          unsigned char * img;
          ifstream IN(ifile, ios::binary);
  
          IN.get(dummy1);IN.get(dummy2);
          if ((dummy1!='P')&&(dummy2!='6')) {cerr<<"Not P6 PPM file"<<endl; return NULL;}
   
      IN >> w >> h;
      IN >> maxc;
      IN.get(dummy1);
          
      img=new  unsigned char[3*w*h];
          IN.read((char *)img, 3*w*h); 
          IN.close();
          return img;
  }


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.