OpenANN  1.1.0
An open source library for artificial neural networks.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Distorter.h
Go to the documentation of this file.
1 #ifndef DISTORTER_H_
2 #define DISTORTER_H_
3 
4 #include <OpenANN/util/Random.h>
7 #include <Eigen/Core>
8 #include <cmath>
9 
32 class Distorter
33 {
34 public:
36  double sigma;
38  double alpha;
40  double beta;
42  double gammaX;
44  double gammaY;
45 
48  Eigen::MatrixXd gaussianKernel;
49  Eigen::MatrixXd distortionH, distortionV;
50 
51  Distorter(double sigma = 5.0, double alpha = 36.0/255.0, double beta = 15.0,
52  double gammaX = 15.0, double gammaY = 15.0)
56  {
57  const double twoSigmaSquared = 2.0 / (sigma * sigma);
58  const double twoPiSigma = std::sqrt(2.0 * M_PI) / (sigma+1e-10);
59  int center = gaussianKernelSize / 2;
60  for(int row = 0; row < gaussianKernelSize; row++)
61  for(int col = 0; col < gaussianKernelSize; col++)
62  gaussianKernel(row, col) = twoPiSigma * std::exp(-twoSigmaSquared *
63  (std::pow((double)(row - center), 2.0) +
64  std::pow((double)(col - center), 2.0)));
66  }
67 
68  void createDistortionMap(int rows, int cols)
69  {
70  // Uniform random matrices in [-1, 1]
71  Eigen::MatrixXd uniformH = Eigen::MatrixXd::Random(rows, cols);
72  Eigen::MatrixXd uniformV = Eigen::MatrixXd::Random(rows, cols);
73 
74  // Gaussian filter
75  distortionH.resize(rows, cols), distortionV.resize(rows, cols);
76  distortionH.setZero();
77  distortionV.setZero();
78  int kernelCenter = gaussianKernelSize / 2;
79  for(int r = 0; r < rows; r++)
80  {
81  for(int c = 0; c < cols; c++)
82  {
83  double convolvedH = 0.0, convolvedV = 0.0;
84  for(int kr = 0; kr < gaussianKernelSize; kr++)
85  {
86  for(int kc = 0; kc < gaussianKernelSize; kc++)
87  {
88  int inputRow = r - kernelCenter + kr;
89  int inputCol = c - kernelCenter + kc;
90  if(inputRow >= 0 && inputRow < rows && inputCol >= 0 && inputCol < cols)
91  {
92  convolvedH += uniformH(inputRow, inputCol) * gaussianKernel(kr, kc);
93  convolvedV += uniformV(inputRow, inputCol) * gaussianKernel(kr, kc);
94  }
95  }
96  }
97  distortionH(r, c) = alpha * convolvedH;
98  distortionV(r, c) = alpha * convolvedV;
99  }
100  }
103 
104  // Image scaling
106  double horizontalScaling = rng.generate<double>(-1.0, 2.0) * gammaX / 100.0;
107  double verticalScaling = rng.generate<double>(-1.0, 2.0) * gammaY / 100.0;
108  OPENANN_CHECK_EQUALS(cols, rows); // could be generalized but YAGNI
109  int imageCenter = rows / 2;
110  for(int r = 0; r < rows; r++)
111  {
112  for(int c = 0; c < cols; c++)
113  {
114  distortionH(r, c) += horizontalScaling * (double)(c - imageCenter);
115  distortionV(r, c) -= verticalScaling * (double)(imageCenter - r); // negative because of top-down bitmap
116  }
117  }
120 
121  // Rotation
122  double angle = beta * rng.generate<double>(-1.0, 2.0) * M_PI / 180.0;
123  double cosAngle = cos(angle);
124  double sinAngle = sin(angle);
125 
126  for(int r = 0; r < rows; r++)
127  {
128  for(int c = 0; c < cols; c++)
129  {
130  distortionH(r, c) += (c - imageCenter) * (cosAngle - 1.0) - (imageCenter - r) * sinAngle;
131  distortionV(r, c) -= (imageCenter - r) * (cosAngle - 1.0) - (c - imageCenter) * sinAngle;
132  }
133  }
136  }
137 
138 
139  void applyDistortions(Eigen::MatrixXd& instances, int rows, int cols)
140  {
141  Eigen::VectorXd instance;
142  for(int n = 0; n < instances.cols(); n++)
143  {
144  instance = instances.col(n);
145  applyDistortion(instance, rows, cols);
146  instances.col(n) = instance;
147  }
148  }
149 
150  void applyDistortion(Eigen::VectorXd& instance, int rows, int cols)
151  {
152  createDistortionMap(rows, cols);
153  Eigen::VectorXd input = instance;
154  for(int r = 0; r < rows; r++)
155  {
156  for(int c = 0; c < cols; c++)
157  {
158  double sourceRow = (double) r - distortionV(r, c);
159  double sourceCol = (double) c - distortionH(r, c);
160  double rowFraction = sourceRow - ceil(sourceRow);
161  double colFraction = sourceCol - ceil(sourceCol);
162  double w1 = (1.0 - rowFraction) * (1.0 - colFraction);
163  double w2 = (1.0 - rowFraction) * colFraction;
164  double w3 = rowFraction * (1.0 - colFraction);
165  double w4 = rowFraction * colFraction;
166 
167  if(!(sourceRow + 1 >= rows || sourceRow < 0 || sourceCol + 1 > cols || sourceCol < 0))
168  {
169  int sr = (int) sourceRow, sc = (int) sourceCol;
170  int srn = sr + 1, scn = sc + 1;
171  while(srn >= rows) srn -= rows;
172  while(srn < 0) srn += rows;
173  while(scn >= cols) scn -= cols;
174  while(scn < 0) scn += cols;
175  instance(r * cols + c) = w1 * input(sr * cols + sc)
176  + w2 * input(sr * cols + scn)
177  + w3 * input(srn * cols + sc)
178  + w4 * input(srn * cols + scn);
179  }
180  }
181  }
182  }
183 };
184 
185 #endif // DISTORTER_H_