Skip to content

Latest commit

 

History

History
51 lines (30 loc) · 17.4 KB

CppDoFilterOperation.md

File metadata and controls

51 lines (30 loc) · 17.4 KB

 

 

 

 

 

 

Graphics and math code Snippet to perform a filter operation (also called a convolution) on an image. This image is a 2D std::vector of int (y-x-ordered).

 

The tool FilterOperationer demonstrates the use of DoFilterOperation.

 

 


#include <vector> #include <cassert> //Return a y-x-ordered 2D std::vector with the intensitief of grey //values from range [0,255] (0=black,255=white) after the filter operation //From http://www.richelbilderbeek.nl/CppDoFilterOperation.htm const std::vector<std::vector<int> > DoFilterOperation(   const std::vector<std::vector<int> >& source, //y-x-ordered   const std::vector<std::vector<double> >& filter) //y-x-ordered {   assert(!source.empty());   assert(!filter.empty());   const int width = source[0].size();   const int height = source.size();   std::vector<std::vector<int> > v(height, std::vector<int>(width));   const int maxx = source[0].size();   const int maxy = source.size();   const int midX = filter[0].size() / 2;   const int midY = filter.size()    / 2;   const std::pair<double, double> filterRange = GetFilterRange(filter);   assert(filterRange.first < filterRange.second);   for (int y=0; y!=maxy; ++y)   {     const int writeY = y;     assert(writeY >= 0 && writeY < static_cast<int>(v.size()) );     std::vector<int>& vLine = v[writeY];     for (int x=0; x!=maxx; ++x)     {       //The x and y values are the topleft coordinate of where       //  the filter will be applied to. This coordinat can be out of       //  the range, but at least one pixel of where the filter will be       //  applied to will be in range       //The pixel value is normalized to the area the       //  filter operation took place on       //The outcome of the filter operation is written to       //  (x + midX, y + midY), which HAS to be in range       const double unscaledPixelValue = GetFilterOperationPixel(source,x-midX,y-midY,filter);       //Scale the unscaledPixelValue.       //The maximal value of unscaledPixelValue is the sum of all positive       //values in the filter * 255.       //The minimum value of unscaledPixelValue is the sum of all negative       //values in the filter * 255.       //The scaled pixel value must be obtained by transforming the unscaled       //range [min,max] to [0,256>.       const double relUnscaledRange         = (unscaledPixelValue - filterRange.first)         / (filterRange.second - filterRange.first);       assert(relUnscaledRange >= 0.0 && relUnscaledRange <= 1.0);       const double scaledRange = relUnscaledRange * 255;       assert(scaledRange >= 0.0 && scaledRange < 256.0);       const int pixel = scaledRange;       const int writeX = x;       assert(writeX >= 0 && writeX < width);       vLine[writeX] = pixel;     }   }   assert(source[0].size()==v[0].size());   assert(source.size()==v.size());   return v; } //The sourceX and sourceY values are the topleft coordinate of where //  the filter will be applied to. This coordinat can be out of //  the range, but at least one pixel of where the filter will be //  applied to will be in range. If there are no pixels in range, //  an assertion will fail. //The pixel value is normalized to the area the //  filter operation took place on. Therefore, this area must be non-zero //The outcome of this filter operation will be written to //  (x + midX, y + midY), which HAS to be in range //From http://www.richelbilderbeek.nl/CppDoFilterOperation.htm const double GetFilterOperationPixel(   const std::vector<std::vector<int> >& source, //y-x-ordered   const int sourceX,   const int sourceY,   const std::vector<std::vector<double> >& filter) //y-x-ordered {   assert(!source.empty());   assert(!filter.empty());   const int sourceMaxY = source.size();   const int sourceMaxX = source[0].size();   const int filterMaxY = filter.size();   const int filterMaxX = filter[0].size();   double result = 0.0;   int nPixels = 0;   for (int y=0; y!=filterMaxY; ++y)   {     const int readY = sourceY + y;     if ( readY < 0 || readY >= sourceMaxY) continue;     assert(y >= 0);     assert(y < static_cast<int>(filter.size()));     const std::vector<double>& lineFilter = filter[y];     assert(readY >= 0);     assert(readY < static_cast<int>(source.size()));     const std::vector<int>& lineSource = source[readY];     for (int x=0; x!=filterMaxX; ++x)     {       const int readX = sourceX + x;       if ( readX < 0 || readX >= sourceMaxX) continue;       assert(x >= 0);       assert(x < filterMaxX);       assert(readX >= 0);       assert(readX < sourceMaxX);       const double deltaResult = static_cast<double>(lineSource[readX]) * lineFilter[x];       result += deltaResult;       ++nPixels;     }   }   assert(nPixels!=0);   const double filteredValue = result / static_cast<double>(nPixels);   return filteredValue; } //Obtains the range a filter can have //Assumes the every element has a maximum value of 255 //From http://www.richelbilderbeek.nl/CppDoFilterOperation.htm const std::pair<double, double> GetFilterRange(const std::vector<std::vector<double> >& filter) {   assert(!filter.empty());   const int maxx = filter[0].size();   const int maxy = filter.size();   assert(maxx + maxy > 2 && "Filter size must be bigger then 1x1");   double min = 0.0;   double max = 0.0;   for (int y=0; y!=maxy; ++y)   {     assert(y >= 0);     assert(y  < static_cast<int>(filter.size()) );     const std::vector<double>& lineFilter = filter[y];     for (int x=0; x!=maxx; ++x)     {       assert(x >= 0);       assert(x  < static_cast<int>(lineFilter.size()) );       const double value = lineFilter[x];       if (value < 0.0) min +=value;       else if (value > 0.0) max +=value;     }   }   const std::pair<double,double> range   = std::make_pair(min * 255.0, max * 255.0);   return range; }