+/*-----------------------------------------------------------------------------
+ Code written by Francois Fleuret, using GCC & Emacs
+ Jun-Nov 1995
+ Contact <francois.fleuret@inria.fr>
+-----------------------------------------------------------------------------*/
+
+#include "pictures.h"
+
+/*---------------------------------------------------------------------------*/
+
+Picture::Picture()
+{}
+
+Picture::Picture(int SX, int SY)
+{
+ SizeX = SX;
+ SizeY = SY;
+ Body.resize(SizeX*SizeY*PIC_DEPTH);
+ Clear();
+}
+
+Picture::Picture(Picture &v)
+{
+ int i;
+ SizeX = v.SizeX;
+ SizeY = v.SizeY;
+ Body.resize(SizeX*SizeY*PIC_DEPTH);
+ for(i=0; i<SizeX*SizeY*PIC_DEPTH; i++) Body.set(i, v.Body.get(i));
+}
+
+Picture::~Picture() {}
+
+void Picture::Blur(int s)
+{
+ int nSizeX, nSizeY, x, y, xx, yy, c;
+ float sum;
+ Array<float> newBody;
+
+ nSizeX = SizeX - 2*s;
+ nSizeY = SizeY - 2*s;
+ newBody.resize(nSizeX*nSizeY*PIC_DEPTH);
+
+ for(x=0; x<nSizeX; x++)
+ for(y=0; y<nSizeY; y++)
+ for(c=0; c<PIC_DEPTH; c++)
+ {
+ sum = 0;
+ for(xx=x; (xx<x+2*s+1) || (xx<SizeX); xx++)
+ for(yy=y; (yy<y+2*s+1) || (yy<SizeY); yy++)
+ sum += Body.get(PIC_DEPTH*(xx+yy*SizeX)+c);
+ newBody.set(PIC_DEPTH*(x+y*nSizeX)+c, sum/((2*s+1)*(2*s+1)));
+ };
+
+ Body.absorb(newBody);
+ SizeX = nSizeX;
+ SizeY = nSizeY;
+};
+
+// renvoie la n-ieme composante du pixel (x, y)
+float Picture::GetComponent(int x, int y, int n)
+{
+ return Body.get(PIC_DEPTH*(x+y*SizeX)+n);
+}
+
+// Modifie la n-ieme composante du pixel (x, y)
+void Picture::SetComponent(int x, int y, int n, float v)
+{
+ Body.set(PIC_DEPTH*(x+y*SizeX)+n, v);
+}
+
+// Efface "graphiquement" l'image (i.e. met du noir partout)
+void Picture::Clear()
+{
+ Fill(0);
+}
+
+void Picture::Fill(float v)
+{
+ int k;
+ for(k=0; k<SizeX*SizeY*PIC_DEPTH; k++) Body.set(k, v);
+}
+
+void Picture::Reformat(int x, int y)
+{
+ SizeX = x; SizeY = y;
+ Body.resize(SizeX*SizeY*PIC_DEPTH);
+}
+
+// Detruit l'image (i.e. libere la memoire et met la size a 0)
+void Picture::Free()
+{
+ SizeX = 0; SizeY = 0;
+ Body.kill();
+}
+
+void Picture::Reverse()
+{
+ int k;
+ for(k=0; k<SizeX*SizeY*PIC_DEPTH; k++) Body.set(k, 1 - Body.get(k));
+};
+
+void Picture::ToBN()
+{
+ int x, y, c;
+ float v;
+ for(x = 0; x<SizeX; x++)
+ for(y = 0; y<SizeY; y++)
+ if(GetComponent(x, y, PIC_BLUE) < 0.999)
+ {
+ v = 0;
+ for(c=0; c<PIC_DEPTH; c++) v += GetComponent(x, y, c);
+ v /= PIC_DEPTH;
+ for(c=0; c<PIC_DEPTH; c++) SetComponent(x, y, c, v);
+ };
+};
+
+void Picture::AddBorders(int w, float r, float g, float b)
+{
+ int nSizeX, nSizeY, x, y, d;
+ Array<float> nBody;
+
+ nSizeX = SizeX + 2*w;
+ nSizeY = SizeY + 2*w;
+
+ nBody.resize(nSizeX*nSizeY*PIC_DEPTH);
+
+ for(d = 0; d<nSizeX*nSizeY; d++)
+ {
+ nBody.set(d*PIC_DEPTH + PIC_RED, r);
+ nBody.set(d*PIC_DEPTH + PIC_GREEN, g);
+ nBody.set(d*PIC_DEPTH + PIC_BLUE, b);
+ }
+
+ for(x = 0; x<SizeX; x++)
+ for(y = 0; y<SizeY; y++)
+ for(d = 0; d<PIC_DEPTH; d++)
+ nBody.set(PIC_DEPTH*((x+w)+(y+w)*nSizeX)+d,
+ Body.get(PIC_DEPTH*(x+y*SizeX)+d));
+
+ Body.absorb(nBody);
+ SizeX = nSizeX;
+ SizeY = nSizeY;
+};
+
+#define ATTEND_MODEP 0
+#define ATTEND_XY 1
+#define ATTEND_SCALE 2
+#define LOAD_PIXELS 3
+
+#define MODE_UNKNOWN -1
+#define MODE_P5 5
+#define MODE_P6 6
+
+void Picture::LoadPpm(char *file_name)
+{
+ char buffer[BUFFER_SIZE];
+ int mode, modeP;
+ FILE *from;
+ int x, y, c, s, k;
+ unsigned char ch, *cht;
+
+ Free();
+
+ from = fopen(file_name, "r");
+
+ modeP = MODE_UNKNOWN;
+ s = -1;
+ mode = ATTEND_MODEP;
+ if(from != NULL)
+ {
+ do
+ {
+ k = 0;
+ do
+ {
+ fscanf(from, "%c", &ch);
+ if(ch != '\n') buffer[k++] = ch;
+ else buffer[k++] = '\0';
+ }
+ while(ch != '\n');
+ if(strlen(buffer)>0) if(buffer[0] != '#')
+ {
+ switch(mode)
+ {
+ case ATTEND_MODEP:
+ if(strcmp("P5", buffer) == 0)
+ {
+ modeP = MODE_P5;
+ mode = ATTEND_XY;
+ }
+ else if(strcmp("P6", buffer) == 0)
+ {
+ modeP = MODE_P6;
+ mode = ATTEND_XY;
+ }
+ else cerr<<"Picture::LoadPpm ERROR, not P5 or P6 format\n";
+ break;
+ case ATTEND_XY:
+ x = -1; y = -1;
+ sscanf(buffer, "%d %d", &x, &y);
+ if((x>0) && (y>0))
+ {
+ SizeX = x;
+ SizeY = y;
+ Body.resize(SizeX*SizeY*PIC_DEPTH);
+ }
+ else cerr<<"Picture::LoadPpm ERROR, incoherent size\n";
+ mode = ATTEND_SCALE;
+ break;
+ case ATTEND_SCALE:
+ s = -1;
+ sscanf(buffer, "%d", &s);
+ mode = LOAD_PIXELS;
+ break;
+ };
+ };
+ }
+ while(mode != LOAD_PIXELS);
+
+ if((Body.size != 0) && (s>0))
+ {
+ cht = new unsigned char[SizeX*PIC_DEPTH];
+ if(cht != NULL)
+ {
+ switch(modeP)
+ {
+ case MODE_P5:
+ for(y=0; y<SizeY; y++)
+ {
+ fread(cht, sizeof(unsigned char), SizeX, from);
+ for(x=0; x<SizeX; x++)
+ for(c=0; c<PIC_DEPTH; c++)
+ SetComponent(x, y, c, float(cht[x])/s);
+ };
+ break;
+ case MODE_P6:
+ for(y=0; y<SizeY; y++)
+ {
+ fread(cht, sizeof(unsigned char), SizeX*PIC_DEPTH, from);
+ for(x=0; x<SizeX; x++)
+ for(c=0; c<PIC_DEPTH; c++)
+ SetComponent(x, y, c,
+ float(cht[x*PIC_DEPTH+c])/s);
+ };
+ break;
+ default:
+ cerr<<"Unknown format in LoadPpm\n";
+ break;
+ };
+ };
+ delete cht;
+ }
+ else cerr<<"Creation error : memory allocation failed\n";
+
+ fclose(from);
+ }
+ else cerr<<"Picture::LoadPpm fopen ERROR\n";
+}
+
+void Picture::SavePpm(char *file_name)
+{
+ FILE *to;
+ int x, y, c;
+ unsigned char ch;
+
+ to = fopen(file_name, "w");
+ if(to != NULL)
+ {
+ fprintf(to, "P6\n");
+ fprintf(to, "# Created with Pictures::SavePpm, Contact <francois.fleuret@inria.fr> for infos.\n");
+ fprintf(to, "%d %d\n", SizeX, SizeY);
+ fprintf(to, "255\n");
+
+ if(Body.size != 0)
+ for(y=0; y<SizeY; y++)
+ for(x=0; x<SizeX; x++)
+ for(c=0; c<PIC_DEPTH; c++)
+ {
+ ch = (unsigned char) (255*GetComponent(x, y, c));
+ fwrite(&ch, sizeof(ch), 1, to);
+ }
+ }
+ else cerr<<"Picture::SavePpm fopen ERROR\n";
+}
+
+void Picture::ReSize(int nx, int ny)
+{
+ Array<float> newBody;
+ int x, y, c, dx, dy, tt1, ss1, tt2, ss2;
+ float s1, s2, t1, t2, sx, sy;
+ dx = SizeX/nx;
+ dy = SizeY/ny;
+
+ newBody.resize(nx*ny*PIC_DEPTH);
+
+ for(x=0; x<nx; x++) for(y=0; y<ny; y++)
+ for(c=0; c<PIC_DEPTH; c++)
+ newBody.set((y*nx+x)*PIC_DEPTH+c, 0);
+
+ for(x=0; x<SizeX; x++) for(y=0; y<SizeY; y++)
+ {
+ t1 = float(x)*nx/SizeX;
+ t2 = float(x+0.9999)*nx/SizeX;
+ s1 = float(y)*ny/SizeY;
+ s2 = float(y+0.9999)*ny/SizeY;
+
+ tt1 = int(t1); tt2 = int(t2); ss1 = int(s1); ss2 = int(s2);
+
+#ifdef DEBUG
+ if((ss1 < 0) || (ss1 >= ny) || (ss2 < 0) || (ss2 >= ny) ||
+ (tt1 < 0) || (tt1 >= nx) || (tt2 < 0) || (tt2 >= nx))
+ {
+ cerr<<"ss1 out of boudaries in Picture::ReSize()\n";
+ }
+ abort();
+#endif
+
+ sx = (tt2 - t1)*SizeX/nx;
+ sy = (ss2 - s1)*SizeY/nx;
+
+ if(tt1 == tt2)
+ {
+ if(ss1 == ss2)
+ for(c=0; c<PIC_DEPTH; c++)
+ newBody.set((ss1*nx+tt1)*PIC_DEPTH+c,
+ newBody.get((ss1*nx+tt1)*PIC_DEPTH+c) + GetComponent(x, y, c));
+ else
+ {
+ for(c=0; c<PIC_DEPTH; c++)
+ {
+ newBody.set((ss1*nx+tt1)*PIC_DEPTH+c,
+ newBody.get((ss1*nx+tt1)*PIC_DEPTH+c) + sy*GetComponent(x, y, c));
+ newBody.set((ss2*nx+tt1)*PIC_DEPTH+c,
+ newBody.get((ss2*nx+tt1)*PIC_DEPTH+c) + (1-sy)*GetComponent(x, y, c));
+ };
+ };
+ }
+ else
+ {
+ if(ss1 == ss2)
+ {
+ for(c=0; c<PIC_DEPTH; c++)
+ {
+ newBody.set((ss1*nx+tt1)*PIC_DEPTH+c,
+ newBody.get((ss1*nx+tt1)*PIC_DEPTH+c) + sx*GetComponent(x, y, c));
+ newBody.set((ss1*nx+tt2)*PIC_DEPTH+c,
+ newBody.get((ss1*nx+tt2)*PIC_DEPTH+c) + (1-sx)*GetComponent(x, y, c));
+ };
+ }
+ else
+ {
+ for(c=0; c<PIC_DEPTH; c++)
+ {
+ newBody.set((ss1*nx+tt1)*PIC_DEPTH+c,
+ newBody.get((ss1*nx+tt1)*PIC_DEPTH+c) + sx*sy*GetComponent(x, y, c));
+
+ newBody.set((ss2*nx+tt1)*PIC_DEPTH+c,
+ newBody.get((ss2*nx+tt1)*PIC_DEPTH+c) + sx*(1-sy)*GetComponent(x, y, c));
+
+ newBody.set((ss1*nx+tt2)*PIC_DEPTH+c,
+ newBody.get((ss1*nx+tt2)*PIC_DEPTH+c) + (1-sx)*sy*GetComponent(x, y, c));
+
+ newBody.set((ss2*nx+tt2)*PIC_DEPTH+c,
+ newBody.get((ss2*nx+tt2)*PIC_DEPTH+c) + (1-sx)*(1-sy)*GetComponent(x, y, c));
+ };
+ };
+ };
+ };
+
+ for(x=0; x<nx; x++) for(y=0; y<ny; y++)
+ for(c=0; c<PIC_DEPTH; c++)
+ newBody.set((y*nx+x)*PIC_DEPTH+c, newBody.get((y*nx+x)*PIC_DEPTH+c) / (float(SizeX)/nx * float(SizeY)/ny));
+
+ Body = newBody;
+ SizeX = nx;
+ SizeY = ny;
+}
+
+void Picture::Cut(int x, int y, int w, int h, Picture &src)
+{
+ SizeX = w;
+ SizeY = h;
+ Body.resize(SizeX*SizeY*PIC_DEPTH);
+ Copy(0, 0, x, y, w, h, src);
+}
+
+void Picture::Copy(int xd, int yd, int xs, int ys, int w, int h, Picture &src)
+{
+ int i, j, c;
+
+#ifdef DEBUG
+ if((xd<0) || (xd+w>SizeX) || (yd<0) || (yd+h > SizeY))
+ {
+ cerr<<"Parameters error in Picture::Copy()\n";
+ abort();
+ }
+
+ if((xs<0) || (xs+w>src.SizeX) || (ys<0) || (ys+h > src.SizeY))
+ {
+ cerr<<"Parameters error in Picture::Copy()\n";
+ abort();
+ }
+#endif
+
+ for(i=0; i<w; i++) for(j=0; j<h; j++)
+ for(c=0; c<PIC_DEPTH; c++)
+ Body.set(((yd+j)*SizeX+(xd+i))*PIC_DEPTH+c, src.Body.get(((ys+j)*src.SizeX+(xs+i))*PIC_DEPTH+c));
+}
+
+int Picture::operator == (Picture &src)
+{
+ int i, j, c, r;
+ if((SizeX == src.SizeX) && (SizeY == src.SizeY))
+ {
+ r = -1;
+ for(i=0; (i<SizeX) && r; i++) for(j=0; (j<SizeY) && r; j++)
+ for(c=0; (c<PIC_DEPTH) && r; c++)
+ r = Body.get((j*SizeX+i)*PIC_DEPTH+c) ==
+ src.Body.get((j*SizeX+i)*PIC_DEPTH+c);
+
+ return r;
+ }
+ else return 0;
+}
+
+void Picture::operator = (Picture &src)
+{
+ int i;
+ Free();
+ SizeX = src.SizeX;
+ SizeY = src.SizeY;
+ Body.resize(SizeX*SizeY*PIC_DEPTH);
+ for(i=0; i<SizeX*SizeY*PIC_DEPTH; i++) Body.set(i, src.Body.get(i));
+}
+
+float Picture::DistanceL2(Picture *p)
+{
+ int x, y, c;
+ float d, s;
+ if((SizeX == p->SizeX) && (SizeY == p->SizeY))
+ {
+ s = 0;
+ for(x=0; x<SizeX; x++)
+ for(y=0; y<SizeY; y++)
+ for(c=0; c<PIC_DEPTH; c++)
+ {
+ d = Body.get(PIC_DEPTH*(x+y*SizeX)+c) - p->Body.get(PIC_DEPTH*(x+y*SizeX)+c);
+ s += d*d;
+ };
+ return sqrt(s);
+ }
+ else
+ {
+ cerr<<"Norme L2 entre des images de tailles differentes\n";
+ abort();
+ }
+};
+
+/*---------------------------------------------------------------------------*/