Initial commit
[distort.git] / pictures.cc
1 /*-----------------------------------------------------------------------------
2   Code written by Francois Fleuret, using GCC & Emacs
3   Jun-Nov 1995
4   Contact <francois.fleuret@inria.fr>
5 -----------------------------------------------------------------------------*/
6
7 #include "pictures.h"
8
9 /*---------------------------------------------------------------------------*/
10
11 Picture::Picture()
12 {}
13
14 Picture::Picture(int SX, int SY)
15 {
16   SizeX = SX;
17   SizeY = SY;
18   Body.resize(SizeX*SizeY*PIC_DEPTH);
19   Clear();
20 }
21
22 Picture::Picture(Picture &v)
23 {
24   int i;
25   SizeX = v.SizeX;
26   SizeY = v.SizeY;
27   Body.resize(SizeX*SizeY*PIC_DEPTH);
28   for(i=0; i<SizeX*SizeY*PIC_DEPTH; i++) Body.set(i, v.Body.get(i));
29 }
30
31 Picture::~Picture() {}
32
33 void Picture::Blur(int s)
34 {
35   int nSizeX, nSizeY, x, y, xx, yy, c;
36   float sum;
37   Array<float> newBody;
38
39   nSizeX = SizeX - 2*s;
40   nSizeY = SizeY - 2*s;
41   newBody.resize(nSizeX*nSizeY*PIC_DEPTH);
42
43   for(x=0; x<nSizeX; x++)
44     for(y=0; y<nSizeY; y++)
45       for(c=0; c<PIC_DEPTH; c++)
46         {
47           sum = 0;
48           for(xx=x; (xx<x+2*s+1) || (xx<SizeX); xx++)
49             for(yy=y; (yy<y+2*s+1) || (yy<SizeY); yy++)
50               sum += Body.get(PIC_DEPTH*(xx+yy*SizeX)+c);
51           newBody.set(PIC_DEPTH*(x+y*nSizeX)+c, sum/((2*s+1)*(2*s+1)));
52         };
53
54   Body.absorb(newBody);
55   SizeX = nSizeX;
56   SizeY = nSizeY;
57 };
58
59 // renvoie la n-ieme composante du pixel (x, y)
60 float Picture::GetComponent(int x, int y, int n)
61 {
62   return Body.get(PIC_DEPTH*(x+y*SizeX)+n);
63 }
64
65 // Modifie la n-ieme composante du pixel (x, y)
66 void Picture::SetComponent(int x, int y, int n, float v)
67 {
68  Body.set(PIC_DEPTH*(x+y*SizeX)+n, v);
69 }
70
71 // Efface "graphiquement" l'image (i.e. met du noir partout)
72 void Picture::Clear()
73 {
74   Fill(0);
75 }
76
77 void Picture::Fill(float v)
78 {
79   int k;
80   for(k=0; k<SizeX*SizeY*PIC_DEPTH; k++) Body.set(k, v);
81 }
82
83 void Picture::Reformat(int x, int y)
84 {
85   SizeX = x; SizeY = y; 
86   Body.resize(SizeX*SizeY*PIC_DEPTH);
87 }
88
89 // Detruit l'image (i.e. libere la memoire et met la size a 0)
90 void Picture::Free()
91 {
92   SizeX = 0; SizeY = 0;
93   Body.kill();
94 }
95
96 void Picture::Reverse()
97 {
98   int k;
99   for(k=0; k<SizeX*SizeY*PIC_DEPTH; k++) Body.set(k, 1 - Body.get(k));
100 };
101
102 void Picture::ToBN()
103 {
104   int x, y, c;
105   float v;
106   for(x = 0; x<SizeX; x++)
107     for(y = 0; y<SizeY; y++)
108       if(GetComponent(x, y, PIC_BLUE) < 0.999)
109         {
110           v = 0;
111           for(c=0; c<PIC_DEPTH; c++) v += GetComponent(x, y, c);
112           v /= PIC_DEPTH;
113           for(c=0; c<PIC_DEPTH; c++) SetComponent(x, y, c, v);
114         };
115 };
116
117 void Picture::AddBorders(int w, float r, float g, float b)
118 {
119   int nSizeX, nSizeY, x, y, d;
120   Array<float> nBody;
121
122   nSizeX = SizeX + 2*w;
123   nSizeY = SizeY + 2*w;
124
125   nBody.resize(nSizeX*nSizeY*PIC_DEPTH);
126
127   for(d = 0; d<nSizeX*nSizeY; d++)
128     {
129       nBody.set(d*PIC_DEPTH + PIC_RED, r);
130       nBody.set(d*PIC_DEPTH + PIC_GREEN, g);
131       nBody.set(d*PIC_DEPTH + PIC_BLUE, b);
132     }
133
134   for(x = 0; x<SizeX; x++)
135     for(y = 0; y<SizeY; y++)
136       for(d = 0; d<PIC_DEPTH; d++) 
137         nBody.set(PIC_DEPTH*((x+w)+(y+w)*nSizeX)+d,
138                   Body.get(PIC_DEPTH*(x+y*SizeX)+d));
139
140   Body.absorb(nBody);
141   SizeX = nSizeX;
142   SizeY = nSizeY;
143 };
144
145 #define ATTEND_MODEP 0
146 #define ATTEND_XY 1
147 #define ATTEND_SCALE 2
148 #define LOAD_PIXELS 3
149
150 #define MODE_UNKNOWN -1
151 #define MODE_P5 5
152 #define MODE_P6 6
153
154 void Picture::LoadPpm(char *file_name)
155 {
156   char buffer[BUFFER_SIZE];
157   int mode, modeP;
158   FILE *from;
159   int x, y, c, s, k;
160   unsigned char ch, *cht;
161
162   Free();
163
164   from = fopen(file_name, "r");
165
166   modeP = MODE_UNKNOWN;
167   s = -1;
168   mode = ATTEND_MODEP;
169   if(from != NULL)
170     {
171       do
172         {
173           k = 0;
174           do
175             {
176               fscanf(from, "%c", &ch);
177               if(ch != '\n') buffer[k++] = ch;
178               else buffer[k++] = '\0';
179             }
180           while(ch != '\n');
181           if(strlen(buffer)>0) if(buffer[0] != '#')
182             {
183               switch(mode)
184                 {
185               case ATTEND_MODEP:
186                   if(strcmp("P5", buffer) == 0)
187                     {
188                       modeP = MODE_P5;
189                       mode = ATTEND_XY;
190                     }
191                   else if(strcmp("P6", buffer) == 0)
192                     {
193                       modeP = MODE_P6;
194                       mode = ATTEND_XY;
195                     }
196                   else cerr<<"Picture::LoadPpm ERROR, not P5 or P6 format\n";
197                   break;
198               case ATTEND_XY:
199                   x = -1; y = -1;
200                   sscanf(buffer, "%d %d", &x, &y);
201                   if((x>0) && (y>0))
202                     {
203                       SizeX = x;
204                       SizeY = y;
205                       Body.resize(SizeX*SizeY*PIC_DEPTH);
206                     }
207                   else cerr<<"Picture::LoadPpm ERROR, incoherent size\n";
208                   mode = ATTEND_SCALE;
209                   break;
210               case ATTEND_SCALE:
211                   s = -1;
212                   sscanf(buffer, "%d", &s);
213                   mode = LOAD_PIXELS;
214                   break;
215                 };
216             };
217         }
218       while(mode != LOAD_PIXELS);
219       
220       if((Body.size != 0) && (s>0))
221         {
222           cht = new unsigned char[SizeX*PIC_DEPTH];
223           if(cht != NULL)
224             {
225               switch(modeP)
226                 {
227               case MODE_P5:
228                   for(y=0; y<SizeY; y++)
229                     {
230                       fread(cht, sizeof(unsigned char), SizeX, from);
231                       for(x=0; x<SizeX; x++)
232                         for(c=0; c<PIC_DEPTH; c++)
233                           SetComponent(x, y, c, float(cht[x])/s);
234                     };
235                   break;
236               case MODE_P6:
237                   for(y=0; y<SizeY; y++)
238                     {
239                       fread(cht, sizeof(unsigned char), SizeX*PIC_DEPTH, from);
240                       for(x=0; x<SizeX; x++)
241                         for(c=0; c<PIC_DEPTH; c++)
242                           SetComponent(x, y, c,
243                                        float(cht[x*PIC_DEPTH+c])/s);
244                     };
245                   break;
246               default:
247                   cerr<<"Unknown format in LoadPpm\n";
248                   break;
249                 };
250             };
251           delete cht;
252         }
253       else cerr<<"Creation error : memory allocation failed\n";
254       
255       fclose(from);
256     }
257   else cerr<<"Picture::LoadPpm fopen ERROR\n";
258 }
259
260 void Picture::SavePpm(char *file_name)
261 {
262   FILE *to;
263   int x, y, c;
264   unsigned char ch;
265
266   to = fopen(file_name, "w");
267   if(to != NULL)
268     {
269       fprintf(to, "P6\n");
270       fprintf(to, "# Created with Pictures::SavePpm, Contact <francois.fleuret@inria.fr> for infos.\n");
271       fprintf(to, "%d %d\n", SizeX, SizeY);
272       fprintf(to, "255\n");
273       
274       if(Body.size != 0)
275         for(y=0; y<SizeY; y++)
276           for(x=0; x<SizeX; x++)
277             for(c=0; c<PIC_DEPTH; c++)
278               {
279                 ch = (unsigned char) (255*GetComponent(x, y, c));
280                 fwrite(&ch, sizeof(ch), 1, to);
281               }
282     }
283   else cerr<<"Picture::SavePpm fopen ERROR\n";
284 }
285
286 void Picture::ReSize(int nx, int ny)
287 {
288   Array<float> newBody;
289   int x, y, c, dx, dy, tt1, ss1, tt2, ss2;
290   float s1, s2, t1, t2, sx, sy;
291   dx = SizeX/nx;
292   dy = SizeY/ny;
293
294   newBody.resize(nx*ny*PIC_DEPTH);
295
296   for(x=0; x<nx; x++) for(y=0; y<ny; y++)
297     for(c=0; c<PIC_DEPTH; c++)
298       newBody.set((y*nx+x)*PIC_DEPTH+c, 0);
299
300   for(x=0; x<SizeX; x++) for(y=0; y<SizeY; y++)
301     {
302       t1 = float(x)*nx/SizeX;
303       t2 = float(x+0.9999)*nx/SizeX;
304       s1 = float(y)*ny/SizeY;
305       s2 = float(y+0.9999)*ny/SizeY;
306
307       tt1 = int(t1); tt2 = int(t2); ss1 = int(s1); ss2 = int(s2);
308
309 #ifdef DEBUG
310       if((ss1 < 0) || (ss1 >= ny) || (ss2 < 0) || (ss2 >= ny) ||
311          (tt1 < 0) || (tt1 >= nx) || (tt2 < 0) || (tt2 >= nx))
312         {
313           cerr<<"ss1 out of boudaries in Picture::ReSize()\n";
314         }
315       abort();
316 #endif
317
318       sx = (tt2 - t1)*SizeX/nx;
319       sy = (ss2 - s1)*SizeY/nx;
320
321       if(tt1 == tt2)
322         {
323           if(ss1 == ss2)
324             for(c=0; c<PIC_DEPTH; c++)
325               newBody.set((ss1*nx+tt1)*PIC_DEPTH+c, 
326                   newBody.get((ss1*nx+tt1)*PIC_DEPTH+c) + GetComponent(x, y, c));
327           else
328             {
329               for(c=0; c<PIC_DEPTH; c++)
330                 {
331                   newBody.set((ss1*nx+tt1)*PIC_DEPTH+c, 
332                               newBody.get((ss1*nx+tt1)*PIC_DEPTH+c) + sy*GetComponent(x, y, c));
333                   newBody.set((ss2*nx+tt1)*PIC_DEPTH+c, 
334         newBody.get((ss2*nx+tt1)*PIC_DEPTH+c) + (1-sy)*GetComponent(x, y, c));
335                 };
336             };
337         }
338       else
339         {
340           if(ss1 == ss2)
341             {
342               for(c=0; c<PIC_DEPTH; c++)
343                 {
344                   newBody.set((ss1*nx+tt1)*PIC_DEPTH+c, 
345         newBody.get((ss1*nx+tt1)*PIC_DEPTH+c) + sx*GetComponent(x, y, c));
346                   newBody.set((ss1*nx+tt2)*PIC_DEPTH+c, 
347         newBody.get((ss1*nx+tt2)*PIC_DEPTH+c) + (1-sx)*GetComponent(x, y, c));
348                 };
349             }
350           else
351             {
352               for(c=0; c<PIC_DEPTH; c++)
353                 {
354                   newBody.set((ss1*nx+tt1)*PIC_DEPTH+c, 
355    newBody.get((ss1*nx+tt1)*PIC_DEPTH+c) + sx*sy*GetComponent(x, y, c));
356
357                   newBody.set((ss2*nx+tt1)*PIC_DEPTH+c, 
358    newBody.get((ss2*nx+tt1)*PIC_DEPTH+c) + sx*(1-sy)*GetComponent(x, y, c));
359
360                   newBody.set((ss1*nx+tt2)*PIC_DEPTH+c, 
361    newBody.get((ss1*nx+tt2)*PIC_DEPTH+c) + (1-sx)*sy*GetComponent(x, y, c));
362
363                   newBody.set((ss2*nx+tt2)*PIC_DEPTH+c, 
364    newBody.get((ss2*nx+tt2)*PIC_DEPTH+c) + (1-sx)*(1-sy)*GetComponent(x, y, c));
365                 };
366             };
367         };
368     };
369
370   for(x=0; x<nx; x++) for(y=0; y<ny; y++)
371     for(c=0; c<PIC_DEPTH; c++)
372       newBody.set((y*nx+x)*PIC_DEPTH+c, newBody.get((y*nx+x)*PIC_DEPTH+c) / (float(SizeX)/nx * float(SizeY)/ny));
373
374   Body = newBody;
375   SizeX = nx;
376   SizeY = ny;
377 }
378
379 void Picture::Cut(int x, int y, int w, int h, Picture &src)
380 {
381   SizeX = w;
382   SizeY = h;
383   Body.resize(SizeX*SizeY*PIC_DEPTH);
384   Copy(0, 0, x, y, w, h, src);
385 }
386
387 void Picture::Copy(int xd, int yd, int xs, int ys, int w, int h, Picture &src)
388 {
389   int i, j, c;
390
391 #ifdef DEBUG
392   if((xd<0) || (xd+w>SizeX) || (yd<0) || (yd+h > SizeY))
393     {
394       cerr<<"Parameters error in Picture::Copy()\n";
395       abort();
396     }
397
398   if((xs<0) || (xs+w>src.SizeX) || (ys<0) || (ys+h > src.SizeY)) 
399     {
400       cerr<<"Parameters error in Picture::Copy()\n";
401       abort();
402     }
403 #endif
404
405   for(i=0; i<w; i++) for(j=0; j<h; j++)
406     for(c=0; c<PIC_DEPTH; c++)
407       Body.set(((yd+j)*SizeX+(xd+i))*PIC_DEPTH+c, src.Body.get(((ys+j)*src.SizeX+(xs+i))*PIC_DEPTH+c));
408 }
409
410 int Picture::operator == (Picture &src)
411 {
412   int i, j, c, r;
413   if((SizeX == src.SizeX) && (SizeY == src.SizeY))
414     {
415       r = -1;
416       for(i=0; (i<SizeX) && r; i++) for(j=0; (j<SizeY) && r; j++)
417         for(c=0; (c<PIC_DEPTH) && r; c++)
418           r = Body.get((j*SizeX+i)*PIC_DEPTH+c) ==
419             src.Body.get((j*SizeX+i)*PIC_DEPTH+c);
420
421       return r;
422     }
423   else return 0;
424 }
425
426 void Picture::operator = (Picture &src)
427 {
428   int i;
429   Free();
430   SizeX = src.SizeX;
431   SizeY = src.SizeY;
432   Body.resize(SizeX*SizeY*PIC_DEPTH);
433   for(i=0; i<SizeX*SizeY*PIC_DEPTH; i++) Body.set(i, src.Body.get(i));
434 }
435
436 float Picture::DistanceL2(Picture *p)
437 {
438   int x, y, c;
439   float d, s;
440   if((SizeX == p->SizeX) && (SizeY == p->SizeY))
441     {
442       s = 0;
443       for(x=0; x<SizeX; x++)
444         for(y=0; y<SizeY; y++)
445           for(c=0; c<PIC_DEPTH; c++)
446             {
447               d = Body.get(PIC_DEPTH*(x+y*SizeX)+c) - p->Body.get(PIC_DEPTH*(x+y*SizeX)+c);
448               s += d*d;
449             };
450       return sqrt(s);
451     }
452   else
453     {
454       cerr<<"Norme L2 entre des images de tailles differentes\n";
455       abort();
456     }
457 };
458
459 /*---------------------------------------------------------------------------*/