KiCad PCB EDA Suite
cimage.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
5  * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
30 #include "cimage.h"
31 #include "buffers_debug.h"
32 #include <string.h> // For memcpy
33 
34 #ifndef CLAMP
35 #define CLAMP(n, min, max) {if( n < min ) n=min; else if( n > max ) n = max;}
36 #endif
37 
38 
39 CIMAGE::CIMAGE( unsigned int aXsize, unsigned int aYsize )
40 {
41  m_wxh = aXsize * aYsize;
42  m_pixels = (unsigned char*)malloc( m_wxh );
43  memset( m_pixels, 0, m_wxh );
44  m_width = aXsize;
45  m_height = aYsize;
47 }
48 
49 
50 CIMAGE::CIMAGE( const CIMAGE &aSrcImage )
51 {
52  m_wxh = aSrcImage.GetWidth() * aSrcImage.GetHeight();
53  m_pixels = (unsigned char*)malloc( m_wxh );
54  memcpy( m_pixels, aSrcImage.GetBuffer(), m_wxh );
55  m_width = aSrcImage.GetWidth();
56  m_height = aSrcImage.GetHeight();
58 }
59 
60 
62 {
63  free( m_pixels );
64 }
65 
66 
67 unsigned char* CIMAGE::GetBuffer() const
68 {
69  return m_pixels;
70 }
71 
72 
73 bool CIMAGE::wrapCoords( int *aXo, int *aYo ) const
74 {
75  int x = *aXo;
76  int y = *aYo;
77 
78  switch(m_wraping)
79  {
80  case WRAP_CLAMP:
81  x = (x < 0 )?0:x;
82  x = (x >= (int)(m_width - 1))?(m_width - 1):x;
83  y = (y < 0)?0:y;
84  y = (y >= (int)(m_height - 1))?(m_height - 1):y;
85  break;
86 
87  case WRAP_WRAP:
88  x = (x < 0)?((m_width - 1)+x):x;
89  x = (x >= (int)(m_width - 1))?(x - m_width):x;
90  y = (y < 0)?((m_height - 1)+y):y;
91  y = (y >= (int)(m_height - 1))?(y - m_height):y;
92  break;
93 
94  default:
95  break;
96  }
97 
98  if( (x < 0) || (x >= (int)m_width) ||
99  (y < 0) || (y >= (int)m_height) )
100  return false;
101 
102  *aXo = x;
103  *aYo = y;
104 
105  return true;
106 }
107 
108 void CIMAGE::plot8CircleLines( int aCx, int aCy, int aX, int aY, unsigned char aValue )
109 {
110  Hline( aCx - aX, aCx + aX, aCy + aY, aValue );
111  Hline( aCx - aX, aCx + aX, aCy - aY, aValue );
112  Hline( aCx - aY, aCx + aY, aCy + aX, aValue );
113  Hline( aCx - aY, aCx + aY, aCy - aX, aValue );
114 }
115 
116 
117 void CIMAGE::Setpixel( int aX, int aY, unsigned char aValue )
118 {
119  if( wrapCoords( &aX, &aY ) )
120  m_pixels[aX + aY * m_width] = aValue;
121 }
122 
123 
124 unsigned char CIMAGE::Getpixel( int aX, int aY ) const
125 {
126  if( wrapCoords( &aX, &aY ) )
127  return m_pixels[aX + aY * m_width];
128  else
129  return 0;
130 }
131 
132 
133 void CIMAGE::Hline( int aXStart, int aXEnd, int aY, unsigned char aValue )
134 {
135  if( ( aY < 0 ) ||
136  ( aY >= (int)m_height ) ||
137  ( ( aXStart < 0 ) && ( aXEnd < 0) ) ||
138  ( ( aXStart >= (int)m_width ) && ( aXEnd >= (int)m_width) ) )
139  return;
140 
141  if( aXStart > aXEnd )
142  {
143  int swap = aXStart;
144 
145  aXStart = aXEnd;
146  aXEnd = swap;
147  }
148 
149  // Clamp line
150  if( aXStart < 0 )
151  aXStart = 0;
152 
153  if( aXEnd >= (int)m_width )
154  aXEnd = m_width - 1;
155 
156  unsigned char* pixelPtr = &m_pixels[aXStart + aY * m_width];
157  unsigned char* pixelPtrEnd = pixelPtr + (unsigned int)((aXEnd - aXStart) + 1);
158 
159  while( pixelPtr < pixelPtrEnd )
160  {
161  *pixelPtr = aValue;
162  pixelPtr++;
163  }
164 }
165 
166 // Based on paper
167 // http://web.engr.oregonstate.edu/~sllu/bcircle.pdf
168 void CIMAGE::CircleFilled(int aCx, int aCy, int aRadius, unsigned char aValue)
169 {
170  int x = aRadius;
171  int y = 0;
172  int xChange = 1 - 2 * aRadius;
173  int yChange = 0;
174  int radiusError = 0;
175 
176  while( x >= y )
177  {
178  plot8CircleLines( aCx, aCy, x, y, aValue );
179  y++;
180  radiusError += yChange;
181  yChange += 2;
182 
183  if( (2 * radiusError + xChange) > 0 )
184  {
185  x--;
186  radiusError += xChange;
187  xChange += 2;
188  }
189  }
190 }
191 
192 
194 {
195  for( unsigned int it = 0; it < m_wxh; it++ )
196  m_pixels[it] = 255 - m_pixels[it];
197 }
198 
199 
200 void CIMAGE::CopyFull( const CIMAGE *aImgA, const CIMAGE *aImgB, E_IMAGE_OP aOperation )
201 {
202  int aV, bV;
203 
204  if( aOperation == COPY_RAW )
205  {
206  if( aImgA == NULL )
207  return;
208  }
209  else
210  {
211  if( (aImgA == NULL) || (aImgB == NULL) )
212  return;
213  }
214 
215  switch(aOperation)
216  {
217  case COPY_RAW:
218  memcpy( m_pixels, aImgA->m_pixels, m_wxh );
219  break;
220 
221  case COPY_ADD:
222  for( unsigned int it = 0;it < m_wxh; it++ )
223  {
224  aV = aImgA->m_pixels[it];
225  bV = aImgB->m_pixels[it];
226 
227  aV = (aV + bV);
228  aV = (aV > 255)?255:aV;
229 
230  m_pixels[it] = aV;
231  }
232  break;
233 
234  case COPY_SUB:
235  for( unsigned int it = 0;it < m_wxh; it++ )
236  {
237  aV = aImgA->m_pixels[it];
238  bV = aImgB->m_pixels[it];
239 
240  aV = (aV - bV);
241  aV = (aV < 0)?0:aV;
242 
243  m_pixels[it] = aV;
244  }
245  break;
246 
247  case COPY_DIF:
248  for( unsigned int it = 0;it < m_wxh; it++ )
249  {
250  aV = aImgA->m_pixels[it];
251  bV = aImgB->m_pixels[it];
252 
253  m_pixels[it] = abs( aV - bV );
254  }
255  break;
256 
257  case COPY_MUL:
258  for( unsigned int it = 0;it < m_wxh; it++ )
259  {
260  aV = aImgA->m_pixels[it];
261  bV = aImgB->m_pixels[it];
262 
263  m_pixels[it] = (unsigned char)((((float)aV / 255.0f) * ((float)bV / 255.0f)) * 255);
264  }
265  break;
266 
267  case COPY_AND:
268  for( unsigned int it = 0;it < m_wxh; it++ )
269  {
270  m_pixels[it] = aImgA->m_pixels[it] & aImgB->m_pixels[it];
271  }
272  break;
273 
274  case COPY_OR:
275  for( unsigned int it = 0;it < m_wxh; it++ )
276  {
277  m_pixels[it] = aImgA->m_pixels[it] | aImgB->m_pixels[it];
278  }
279  break;
280 
281  case COPY_XOR:
282  for( unsigned int it = 0;it < m_wxh; it++ )
283  {
284  m_pixels[it] = aImgA->m_pixels[it] ^ aImgB->m_pixels[it];
285  }
286  break;
287 
288  case COPY_BLEND50:
289  for( unsigned int it = 0;it < m_wxh; it++ )
290  {
291  aV = aImgA->m_pixels[it];
292  bV = aImgB->m_pixels[it];
293 
294  m_pixels[it] = (aV + bV) / 2;
295  }
296  break;
297 
298  case COPY_MIN:
299  for( unsigned int it = 0;it < m_wxh; it++ )
300  {
301  aV = aImgA->m_pixels[it];
302  bV = aImgB->m_pixels[it];
303 
304  m_pixels[it] = (aV < bV)?aV:bV;
305  }
306  break;
307 
308  case COPY_MAX:
309  for( unsigned int it = 0;it < m_wxh; it++ )
310  {
311  aV = aImgA->m_pixels[it];
312  bV = aImgB->m_pixels[it];
313 
314  m_pixels[it] = (aV > bV)?aV:bV;
315  }
316  break;
317 
318  default:
319  break;
320  }
321 }
322 
323 // TIP: If you want create or test filters you can use GIMP
324 // with a generic convolution matrix and get the values from there.
325 // http://docs.gimp.org/nl/plug-in-convmatrix.html
326 static const S_FILTER FILTERS[] = {
327  // FILTER_HIPASS
328  {
329  { { 0, -1, -1, -1, 0},
330  {-1, 2, -4, 2, -1},
331  {-1, -4, 13, -4, -1},
332  {-1, 2, -4, 2, -1},
333  { 0, -1, -1, -1, 0}
334  },
335  7,
336  255
337  },
338 
339  // FILTER_GAUSSIAN_BLUR
340  {
341  { { 3, 5, 7, 5, 3},
342  { 5, 9, 12, 9, 5},
343  { 7, 12, 20, 12, 7},
344  { 5, 9, 12, 9, 5},
345  { 3, 5, 7, 5, 3}
346  },
347  182,
348  0
349  },
350 
351  // FILTER_GAUSSIAN_BLUR2
352  {
353  { { 1, 4, 7, 4, 1},
354  { 4, 16, 26, 16, 4},
355  { 7, 26, 41, 26, 7},
356  { 4, 16, 26, 16, 4},
357  { 1, 4, 7, 4, 1}
358  },
359  273,
360  0
361  },
362 
363  // FILTER_INVERT_BLUR
364  {
365  { { 0, 0, 0, 0, 0},
366  { 0, 0, -1, 0, 0},
367  { 0, -1, 0, -1, 0},
368  { 0, 0, -1, 0, 0},
369  { 0, 0, 0, 0, 0}
370  },
371  4,
372  255
373  },
374 
375  // FILTER_CARTOON
376  {
377  { {-1, -1, -1, -1, 0},
378  {-1, 0, 0, 0, 0},
379  {-1, 0, 4, 0, 0},
380  { 0, 0, 0, 1, 0},
381  { 0, 0, 0, 0, 4}
382  },
383  3,
384  0
385  },
386 
387  // FILTER_EMBOSS
388  {
389  { {-1, -1, -1, -1, 0},
390  {-1, -1, -1, 0, 1},
391  {-1, -1, 0, 1, 1},
392  {-1, 0, 1, 1, 1},
393  { 0, 1, 1, 1, 1}
394  },
395  1,
396  128
397  },
398 
399  // FILTER_SHARPEN
400  {
401  { {-1, -1, -1, -1, -1},
402  {-1, 2, 2, 2, -1},
403  {-1, 2, 8, 2, -1},
404  {-1, 2, 2, 2, -1},
405  {-1, -1, -1, -1, -1}
406  },
407  8,
408  0
409  },
410 
411  // FILTER_MELT
412  {
413  { { 4, 2, 6, 8, 1},
414  { 1, 2, 5, 4, 2},
415  { 0, -1, 1, -1, 0},
416  { 0, 0, -2, 0, 0},
417  { 0, 0, 0, 0, 0}
418  },
419  32,
420  0
421  },
422 
423  // FILTER_SOBEL_GX
424  {
425  { { 0, 0, 0, 0, 0},
426  { 0, -1, 0, 1, 0},
427  { 0, -2, 0, 2, 0},
428  { 0, -1, 0, 1, 0},
429  { 0, 0, 0, 0, 0}
430  },
431  1,
432  0
433  },
434 
435  // FILTER_SOBEL_GY
436  {
437  { { 1, 2, 4, 2, 1},
438  {-1, -1, 0, 1, 1},
439  {-2, -2, 0, 2, 2},
440  {-1, -1, 0, 1, 1},
441  {-1, -2, -4, -2, -1},
442  },
443  1,
444  0
445  },
446 
447  // FILTER_BLUR_3X3
448  {
449  { { 0, 0, 0, 0, 0},
450  { 0, 1, 2, 1, 0},
451  { 0, 2, 4, 2, 0},
452  { 0, 1, 2, 1, 0},
453  { 0, 0, 0, 0, 0},
454  },
455  16,
456  0
457  }
458 };// Filters
459 
460 
461 // !TODO: This functions can be optimized slipting it between the edges and
462 // do it without use the getpixel function.
463 // Optimization can be done to m_pixels[ix + iy * m_width]
464 // but keep in mind the parallel process of the algorithm
465 void CIMAGE::EfxFilter( CIMAGE *aInImg, E_FILTER aFilterType )
466 {
467  S_FILTER filter = FILTERS[aFilterType];
468 
469  aInImg->m_wraping = WRAP_CLAMP;
471 
472  #pragma omp parallel for
473  for( int iy = 0; iy < (int)m_height; iy++)
474  {
475  for( int ix = 0; ix < (int)m_width; ix++ )
476  {
477  int v = 0;
478 
479  for( int sy = 0; sy < 5; sy++ )
480  {
481  for( int sx = 0; sx < 5; sx++ )
482  {
483  int factor = filter.kernel[sx][sy];
484  unsigned char pixelv = aInImg->Getpixel( ix + sx - 2,
485  iy + sy - 2 );
486 
487  v += pixelv * factor;
488  }
489  }
490 
491  v /= filter.div;
492 
493  v += filter.offset;
494 
495  CLAMP(v, 0, 255);
496 
497  m_pixels[ix + iy * m_width] = v;
498  }
499  }
500 }
501 
502 
503 void CIMAGE::SetPixelsFromNormalizedFloat( const float * aNormalizedFloatArray )
504 {
505  for( unsigned int i = 0; i < m_wxh; i++ )
506  {
507  int v = aNormalizedFloatArray[i] * 255;
508 
509  CLAMP( v, 0, 255 );
510  m_pixels[i] = v;
511  }
512 }
513 
514 
515 void CIMAGE::SaveAsPNG( wxString aFileName ) const
516 {
517  DBG_SaveBuffer( aFileName, m_pixels, m_width, m_height );
518 }
Coords are wrapped arround.
Definition: cimage.h:55
bool wrapCoords(int *aXo, int *aYo) const
Function wrapCoords calculate the coordinates points in accord with the current clamping settings...
Definition: cimage.cpp:73
~CIMAGE()
Definition: cimage.cpp:61
unsigned int m_height
height of the image
Definition: cimage.h:224
#define CLAMP(n, min, max)
Definition: cimage.cpp:35
unsigned char * GetBuffer() const
Function GetBuffer get the image buffer pointer.
Definition: cimage.cpp:67
unsigned char Getpixel(int aX, int aY) const
Function Getpixel get the pixel value from pixel position, position is clamped in accord with the cur...
Definition: cimage.cpp:124
unsigned char * m_pixels
buffer to store the image 8bit-channel
Definition: cimage.h:222
void Hline(int aXStart, int aXEnd, int aY, unsigned char aValue)
hline - Draws an horizontal line
Definition: cimage.cpp:133
void CircleFilled(int aCx, int aCy, int aRadius, unsigned char aValue)
CircleFilled.
Definition: cimage.cpp:168
#define abs(a)
Definition: auxiliary.h:84
void Setpixel(int aX, int aY, unsigned char aValue)
Function Setpixel set a value in a pixel position, position is clamped in accord with the current cla...
Definition: cimage.cpp:117
unsigned int GetHeight() const
Definition: cimage.h:207
CIMAGE(unsigned int aXsize, unsigned int aYsize)
Constructor CIMAGE constructs a CIMAGE based on image size.
Definition: cimage.cpp:39
E_IMAGE_OP
Image operation type.
Definition: cimage.h:36
unsigned int GetWidth() const
Definition: cimage.h:206
void SaveAsPNG(wxString aFileName) const
Function SaveAsPNG save image buffer to a PNG file into the working folder.
Definition: cimage.cpp:515
void CopyFull(const CIMAGE *aImgA, const CIMAGE *aImgB, E_IMAGE_OP aOperation)
Function CopyFull perform a copy operation, based on operation type.
Definition: cimage.cpp:200
void Invert()
Function Invert invert the values of image this <- (255 - this)
Definition: cimage.cpp:193
unsigned char offset
Definition: cimage.h:78
unsigned int m_width
width of the image
Definition: cimage.h:223
unsigned int m_wxh
width * height precalc value
Definition: cimage.h:225
void plot8CircleLines(int aCx, int aCy, int aX, int aY, unsigned char aValue)
Definition: cimage.cpp:108
one 8bit-channel image definition
E_WRAP m_wraping
current wrapping type
Definition: cimage.h:226
signed char kernel[5][5]
Definition: cimage.h:76
unsigned int div
Definition: cimage.h:77
Definition: cimage.h:43
5x5 Filter struct parameters
Definition: cimage.h:75
static const S_FILTER FILTERS[]
Definition: cimage.cpp:326
E_FILTER
Filter type enumeration.
Definition: cimage.h:60
void SetPixelsFromNormalizedFloat(const float *aNormalizedFloatArray)
Function SetPixelsFromNormalizedFloat set the current channel from a float normalized (0...
Definition: cimage.cpp:503
Class CIMAGE manages a 8-bit channel image.
Definition: cimage.h:86
void DBG_SaveBuffer(wxString aFileName, const unsigned char *aInBuffer, unsigned int aXSize, unsigned int aYSize)
void EfxFilter(CIMAGE *aInImg, E_FILTER aFilterType)
Function EfxFilter apply a filter to the input image and stores it in the image class this <- FilterT...
Definition: cimage.cpp:465
E_WRAP
Image wrap type enumeration.
Definition: cimage.h:52
Coords are clamped to image size.
Definition: cimage.h:54