From 414ff7e24f04f408560ee48a175ddb27119ac899 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sacha=20Percot-T=C3=A9tu?= <zakinster@zakinster.com>
Date: Wed, 19 Sep 2012 18:14:35 +0200
Subject: [PATCH] Added the Pyramid algorithms and operations

---
 app/Algorithms/Pyramid.cpp              | 711 ++++++++++++++++++++++++
 app/Algorithms/Pyramid.h                |  73 +++
 app/Operations/InversePyramidDialog.cpp |  54 ++
 app/Operations/InversePyramidDialog.h   |  46 ++
 app/Operations/InversePyramidDialog.ui  | 166 ++++++
 app/Operations/InversePyramidOp.cpp     |  70 +++
 app/Operations/InversePyramidOp.h       |  35 ++
 app/Operations/PyramidDialog.cpp        |  62 +++
 app/Operations/PyramidDialog.h          |  47 ++
 app/Operations/PyramidDialog.ui         | 219 ++++++++
 app/Operations/PyramidOp.cpp            |  86 +++
 app/Operations/PyramidOp.h              |  35 ++
 12 files changed, 1604 insertions(+)
 create mode 100644 app/Algorithms/Pyramid.cpp
 create mode 100644 app/Algorithms/Pyramid.h
 create mode 100644 app/Operations/InversePyramidDialog.cpp
 create mode 100644 app/Operations/InversePyramidDialog.h
 create mode 100644 app/Operations/InversePyramidDialog.ui
 create mode 100644 app/Operations/InversePyramidOp.cpp
 create mode 100644 app/Operations/InversePyramidOp.h
 create mode 100644 app/Operations/PyramidDialog.cpp
 create mode 100644 app/Operations/PyramidDialog.h
 create mode 100644 app/Operations/PyramidDialog.ui
 create mode 100644 app/Operations/PyramidOp.cpp
 create mode 100644 app/Operations/PyramidOp.h

diff --git a/app/Algorithms/Pyramid.cpp b/app/Algorithms/Pyramid.cpp
new file mode 100644
index 0000000..d865a26
--- /dev/null
+++ b/app/Algorithms/Pyramid.cpp
@@ -0,0 +1,711 @@
+/*
+ * Copyright 2011-2012 INSA Rennes
+ *
+ * This file is part of EIImage.
+ *
+ * EIImage is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * EIImage is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with EIImage.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "Pyramid.h"
+#include <Algorithm/Filtering.h>
+#include <cstdio>
+#include <cstring>
+using namespace std;
+using namespace imagein;
+using namespace Pyramid;
+
+const uint8_t tp6_filter_file_data[] = {0x74, 0x72, 0x69, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x61, 0x69, 0x72, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x80, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x67, 0x61, 0x75, 0x73, 0x73, 0x69, 0x65, 0x6e, 0x00, 0x00, 0xf8, 0x45, 0x26, 0x00, 0xf8, 0x45, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcd, 0xcc, 0xcc, 0x3e, 0x00, 0x00, 0x80, 0x3e, 0xcd, 0xcc, 0x4c, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x74, 0x72, 0x69, 0x6d, 0x6f, 0x64, 0x61, 0x6c, 0x00, 0x00, 0x00, 0x45, 0x26, 0x00, 0xf8, 0x45, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x99, 0x19, 0x3f, 0x00, 0x00, 0x80, 0x3e, 0xcd, 0xcc, 0x4c, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x72, 0x65, 0x63, 0x74, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x61, 0x69, 0x72, 0x65, 0x00, 0x00, 0x00, 0xf8, 0x45, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x47, 0xe1, 0x3d, 0xae, 0x47, 0xe1, 0x3d, 0xae, 0x47, 0xe1, 0x3d, 0xae, 0x47, 0xe1, 0x3d, 0xae, 0x47, 0xe1, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x71, 0x6d, 0x66, 0x00, 0x58, 0xec, 0x00, 0x00, 0xf8, 0x45, 0x26, 0x00, 0x00, 0x00, 0xf8, 0x45, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x88, 0x10, 0x3f, 0x16, 0xde, 0x95, 0x3e, 0x9c, 0xf9, 0x55, 0xbd, 0xae, 0xf0, 0x2e, 0xbd, 0x2f, 0x6e, 0xa3, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00};
+
+Pyramid::Filters::Filters()
+{
+    num_filters=(int)sizeof(tp6_filter_file_data)/sizeof(filtre);
+    filters = reinterpret_cast<const filtre*>(tp6_filter_file_data);
+}
+
+Pyramid::Filters::~Filters()
+{
+    if( filters != NULL ) {
+//        delete[] filters;
+    }
+}
+
+bool Pyramid::Filters::getFromPos( int pos, filtre &to_fill ) {
+  bool found = false;
+    if( pos >= 0 && pos < num_filters ) {
+      found = true;
+        copy_filter( filters[pos], to_fill );
+    }
+    return found;
+}
+
+bool Filters::getFromName( const char *name, filtre &to_fill ) {
+  bool found = false;
+    if( strcmp( name, "default - gaussien" ) == 0 ) {
+      found = true;
+        getDefault( to_fill );
+    }
+    else {
+        int counter = 0;
+        for( counter=0; counter< num_filters && !found; counter++ ) {
+            if( strcmp( name, filters[counter].nom_f ) == 0 ) {
+                found = true;
+                copy_filter( filters[counter], to_fill );
+            }
+        }
+    }
+    return found;
+}
+
+int Filters::size() {
+  return num_filters;
+}
+
+void Filters::copy_filter(const filtre &source, filtre &dest ) {
+    int counter;
+    for( counter=0; counter< 30; counter++ ) {
+      dest.nom_f[counter] = source.nom_f[counter];
+    }
+    for( counter=0; counter< 10; counter++ ) {
+      dest.coeff_f[counter] = source.coeff_f[counter];
+    }
+    dest.taille_f = source.taille_f;
+}
+
+void Filters::getDefault( filtre &to_fill ) {
+  strcpy( to_fill.nom_f, "default - gaussien" );
+    to_fill.taille_f =  (float)2;
+    to_fill.coeff_f[0] =  (float)0.4;
+    to_fill.coeff_f[1] =  (float)0.25;
+    to_fill.coeff_f[2] =  (float)0.05;
+}
+
+/*---------------------------------------------------------------------------
+    Cration de l'tage suivant de la pyramide Gaussienne
+---------------------------------------------------------------------------*/
+void Pyramid::etage_suiv_g(const uint8_t *srcTab, uint8_t *dstTab, int srcWidth, int srcHeight, filtre &utile)
+{
+    cout << "etage_suiv_g " << srcWidth << " " << srcHeight << " " << endl;
+    cout << "src = " << (uintptr_t)srcTab << " dst = " << (uintptr_t)dstTab << endl;
+    int dstWidth = srcWidth / 2, dstHeight = srcHeight / 2;
+    uint8_t* intermed = new uint8_t[dstWidth * srcHeight];
+    for(int j = 0; j < srcHeight; ++j)
+    {
+        for(int i = 0; i < dstWidth; ++i)
+        {
+            intermed[i + j * dstWidth] = filt_point_1d_lg(srcTab, srcWidth, 2 * i, j, utile);
+//            intermed[i + j * dstWidth] = srcTab[2*i + j * srcWidth];
+        }
+    }
+    for(int i = 0; i < dstWidth; ++i)
+    {
+        for(int j = 0; j < dstHeight; ++j)
+        {
+            dstTab[i + j * dstWidth] = filt_point_1d_cl(intermed, srcHeight, dstWidth, i, j * 2, utile);
+//            dstTab[i + j * dstWidth] = intermed[i + 2 * j * dstWidth];
+        }
+    }
+    delete intermed;
+}
+
+/*---------------------------------------------------------------------------
+    Cration d'une pyramide Gaussienne jusqu'au nime tage
+---------------------------------------------------------------------------*/
+void Pyramid::pyram_g_n(uint8_t *rep, int nStage, long nbc, long nbl, const uint8_t *itab, filtre &utile)
+{
+    cout << "pyram_g_n " << nStage << " " << nbc << " " << nbl << endl;
+    int taille_c=nbc;
+    int taille_l=nbl;
+    const int size = nbc * nbl;
+    for(int i = 0; i < size; ++i)
+    {
+        rep[i] = itab[i];
+    }
+
+    int j = 0;
+    for(int fin = nStage; fin > 0 ; --fin)
+    {
+        etage_suiv_g((rep+j),(rep+j+taille_c*taille_l),taille_c,taille_l,utile);
+        j=j+taille_c*taille_l;
+        taille_l=taille_l/2;
+        taille_c=taille_c/2;
+    }
+}
+
+/*---------------------------------------------------------------------------
+    Cration d'une pyramide Laplacienne jusqu'au nime tage
+---------------------------------------------------------------------------*/
+void Pyramid::pyram_l_n (uint8_t *rep,int n, long nbc, long nbl, const uint8_t *itab, filtre &utile)
+{
+    int i;
+    int j=0;
+    int fin=n;
+    int taille_c=nbc;
+    int taille_l=nbl;
+    uint8_t* pyra1 = new uint8_t[nbc*nbc*2];
+
+    pyram_g_n(pyra1,fin, nbc, nbl, itab, utile);
+    do
+    {
+        agrandir((pyra1+j+taille_c*taille_l),(rep+j),taille_c/2,taille_l/2,utile);
+
+        for(i=j;i<j+taille_c*taille_l;i++)
+        {
+            /* this overflow is important ! */
+            int n = 0;
+            n = n + pyra1[i];
+            n = n - rep[i];
+            if(n < -127) n = -127;
+            if(n > 128) n = 128;
+//            if(n > 255) n = 255;
+//            if(n < 0) n = 0;
+            rep[i] = n;
+        }
+
+        j=j+taille_c*taille_l;
+        taille_c=taille_c/2;
+        taille_l=taille_l/2;
+        fin--;
+    }while(fin>0);
+    for(i=j;i<j+taille_c*taille_l;i++)
+    {
+        *(rep+i)=*(pyra1+i);
+    }
+    delete[] pyra1;
+}
+
+
+/*---------------------------------------------------------------------------
+    Cration d'une pyramide Gaussienne avec entre en conversationnel
+    des diffrentes proprits de cette pyramide
+---------------------------------------------------------------------------*/
+Image *Pyramid::pyram_g(const GrayscaleImage *im, int etage_f, filtre &utile, string &to_print)
+{
+    if(!( im != NULL )) {
+        throw "Error in Pyramid::pyram_g:\nim = NULL";
+    }
+    if(!( im->getWidth() == im->getHeight() )) {
+        throw  "Error in Pyramid::pyram_g:\nim->getWidth() != im->getHeight()";
+    }
+    if( !isPowerOf2(im->getWidth()) ) {
+        throw  "Error in Pyramid::pyram_g:\nimage dimensions not a power of 2";
+    }
+    long nbl = im->getHeight();
+    long nbc = im->getWidth();
+    const uint8_t* itab = im->begin();
+
+//    uint8_t* rep = new uint8_t[nbc * nbl * 2];
+    GrayscaleImage* resImg = new GrayscaleImage(im->getWidth(), im->getHeight() * 2);
+    uint8_t* rep = resImg->begin();
+    cout << "rep = " << (uintptr_t)rep << endl;
+    int temp_etage_max = etage_max( im );
+    if( etage_f > temp_etage_max ) etage_f = temp_etage_max;
+    if( etage_f < 1 ) etage_f = 1;
+
+    pyram_g_n(rep,etage_f,nbc,nbl,itab,utile);
+    to_print = entropie_p(rep,etage_f,nbc,nbl);
+    reconstruction(rep,etage_f,nbc,nbl);
+
+    return resImg;
+}
+/*---------------------------------------------------------------------------
+    Cration d'un tage de la  pyramide Gaussienne
+---------------------------------------------------------------------------*/
+Image *Pyramid::n_pyram_g(const Image *im, int etage_f, filtre &utile )
+{
+    if(!( im != NULL )) {
+        throw "Error in Pyramid::pyram_g:\nim = NULL";
+    }
+    if(!( im->getWidth() == im->getHeight() )) {
+        throw  "Error in Pyramid::pyram_g:\nim->getWidth() != im->getHeight()";
+    }
+    if( !isPowerOf2(im->getWidth()) ) {
+        throw  "Error in Pyramid::pyram_g:\nimage dimensions not a power of 2";
+    }
+
+    int i;
+    int k=0;
+    int taille_c,taille_l;
+    long nbl = im->getHeight();
+    long nbc = im->getWidth();
+    const uint8_t* itab = im->begin();
+
+    taille_c=nbc;
+    taille_l=nbl;
+    int temp_etage_max = etage_max(im);
+    if( etage_f > temp_etage_max ) etage_f = temp_etage_max;
+    if( etage_f < 1 ) etage_f = 1;
+
+    for(i=0;i<etage_f;i++)
+    {
+        k=k+taille_c*taille_l;
+        taille_c=taille_c/2;
+        taille_l=taille_l/2;
+    }
+    GrayscaleImage* resImg = new GrayscaleImage(taille_c, taille_l);
+    uint8_t* rep = resImg->begin();
+    uint8_t* tab = new uint8_t[(nbc * nbc) / 2 * 3];
+    pyram_g_n(tab,etage_f,nbc,nbl,itab,utile);
+    for(i=0;i<taille_c*taille_l;i++)
+    {
+        rep[i] = tab[i+k];
+    }
+    delete[] tab;
+    return resImg;
+}
+/*---------------------------------------------------------------------------
+    Cration d'une pyramide Laplacienne avec entre en conversationnel
+    des diffrentes proprits de cette pyramide
+---------------------------------------------------------------------------*/
+Image *Pyramid::pyram_l (const Image *im, int etage_f, filtre &utile, string &to_print)
+{
+    if(!( im != NULL )) {
+        throw "Error in Pyramid::pyram_g:\nim = NULL";
+    }
+    if(!( im->getWidth() == im->getHeight() )) {
+        throw  "Error in Pyramid::pyram_g:\nim->getWidth() != im->getHeight()";
+    }
+    if( !isPowerOf2(im->getWidth()) ) {
+        throw  "Error in Pyramid::pyram_g:\nimage dimensions not a power of 2";
+    }
+    long nbl = im->getHeight();
+    long nbc = im->getWidth();
+    const uint8_t* itab = im->begin();
+
+//    uint8_t* rep = new uint8_t[nbc * nbl * 2];
+    GrayscaleImage* resImg = new GrayscaleImage(im->getWidth(), im->getHeight() * 2);
+    uint8_t* rep = resImg->begin();
+    int temp_etage_max = etage_max( im );
+    if( etage_f > temp_etage_max ) etage_f = temp_etage_max;
+    if( etage_f < 1 ) etage_f = 1;
+
+    pyram_l_n(rep,etage_f,nbc,nbl,itab,utile);
+    to_print = entropie_p(rep,etage_f,nbc,nbl);
+    reconstruction(rep,etage_f,nbc,nbl);
+
+    return resImg;
+
+}
+/*---------------------------------------------------------------------------
+    Cration d'un tage de la  pyramide Laplacienne
+---------------------------------------------------------------------------*/
+Image *Pyramid::n_pyram_l(const Image *im, int etage_f, filtre &utile)
+{
+    if(!( im != NULL )) {
+        throw "Error in Pyramid::pyram_g:\nim = NULL";
+    }
+    if(!( im->getWidth() == im->getHeight() )) {
+        throw  "Error in Pyramid::pyram_g:\nim->getWidth() != im->getHeight()";
+    }
+    if( !isPowerOf2(im->getWidth()) ) {
+        throw  "Error in Pyramid::pyram_g:\nimage dimensions not a power of 2";
+    }
+
+    int i;
+    int k=0;
+    int taille_c,taille_l;
+    long nbl = im->getHeight();
+    long nbc = im->getWidth();
+    const uint8_t* itab = im->begin();
+
+    taille_c=nbc;
+    taille_l=nbl;
+    int temp_etage_max = etage_max(im) - 1;
+    if( etage_f > temp_etage_max ) etage_f = temp_etage_max;
+    if( etage_f < 0 ) etage_f = 0;
+
+    for(i=0;i<etage_f;i++)
+    {
+        k=k+taille_c*taille_l;
+        taille_c=taille_c/2;
+        taille_l=taille_l/2;
+    }
+    GrayscaleImage* resImg = new GrayscaleImage(taille_c, taille_l);
+    uint8_t* rep = resImg->begin();
+    uint8_t* tab = new uint8_t[(nbc * nbc) / 2 * 3];
+    pyram_g_n(tab,etage_f,nbc,nbl,itab,utile);
+    pyram_l_n(tab,etage_f+1,nbc,nbl,itab,utile);
+    for(i=0;i<taille_c*taille_l;i++)
+    {
+        rep[i] = tab[i+k];
+    }
+    delete[] tab;
+    return resImg;
+}
+
+
+
+/*---------------------------------------------------------------------------
+    Filtrage d'un point de l'image suivant une ligne
+---------------------------------------------------------------------------*/
+uint8_t Pyramid::filt_point_1d_lg(const uint8_t *tab,int cl, int x, int y, filtre &utile)
+{
+    float partiel=0.;
+    int i;
+    int j;
+    j=utile.taille_f;
+    if(x-j<0)
+    {
+        for(i=-j;i<=j;i++)
+        {
+            if(x+i<0)
+                partiel += *(tab+y*cl+x-i)*utile.coeff_f[-i];
+            else if(i<0)
+                partiel += *(tab+y*cl+x+i)*utile.coeff_f[-i];
+            else
+                partiel += *(tab+y*cl+x+i)*utile.coeff_f[i];
+        }
+    }else if(x+j<cl)
+    {
+        for(i=-j;i<=j;i++)
+        {
+            if(i<0)
+                partiel += *(tab+y*cl+x+i)*utile.coeff_f[-i];
+            else
+                partiel += *(tab+y*cl+x+i)*utile.coeff_f[i];
+        }
+    }
+    else
+    {
+        for(i=-j;i<=j;i++)
+        {
+            if(i<0)
+                partiel += *(tab+y*cl+x+i)*utile.coeff_f[-i];
+            else if(i+x<cl)
+                partiel += *(tab+y*cl+x+i)*utile.coeff_f[i];
+            else
+                partiel += *(tab+y*cl+x-i)*utile.coeff_f[i];
+        }
+    }
+    return((uint8_t)partiel);
+}
+
+/*---------------------------------------------------------------------------
+    Filtrage d'un point de l'image suivant une colonne
+---------------------------------------------------------------------------*/
+uint8_t Pyramid::filt_point_1d_cl(const uint8_t *tab,int lg,int cl, int x, int y, filtre &utile)
+{
+    float partiel=0.;
+    int i;
+    int j=utile.taille_f;
+    if(y-j<0)
+    {
+        for(i=-j;i<=j;i++)
+        {
+            if(y+i<0)
+                partiel += *(tab+x+(y-i)*cl)*utile.coeff_f[-i];
+            else if(i<0)
+                partiel += *(tab+x+(y+i)*cl)*utile.coeff_f[-i];
+            else
+                partiel += *(tab+x+(y+i)*cl)*utile.coeff_f[i];
+        }
+    }else if(y+j<lg)
+    {
+        for(i=-j;i<=j;i++)
+        {
+            if(i<0)
+                partiel += *(tab+x+(y+i)*cl)*utile.coeff_f[-i];
+            else
+                partiel += *(tab+x+(y+i)*cl)*utile.coeff_f[i];
+        }
+    }
+    else
+    {
+        for(i=-j;i<=j;i++)
+        {
+            if(i<0)
+                partiel += *(tab+x+(y+i)*cl)*utile.coeff_f[-i];
+            else if(i+y<cl)
+                partiel += *(tab+x+(y+i)*cl)*utile.coeff_f[i];
+            else
+                partiel += *(tab+x+(y-i)*cl)*utile.coeff_f[i];
+        }
+    }
+    return((uint8_t)partiel);
+}
+/*---------------------------------------------------------------------------
+    Filtrage d'une ligne
+---------------------------------------------------------------------------*/
+void Pyramid::filt_ligne(uint8_t *ligne,int taille_c, filtre &utile)
+{
+    int i;
+    uint8_t *intermed;
+    intermed=(uint8_t*)calloc(taille_c,sizeof(uint8_t));
+    for(i=0;i<taille_c;i++)
+    {
+        *(intermed+i)=filt_point_1d_lg(ligne,taille_c,i,0,utile);
+    }
+    for(i=0;i<taille_c;i++)
+    {
+        *(ligne+i)=*(intermed+i);
+    }
+    free(intermed);
+}
+/*---------------------------------------------------------------------------
+    Filtrage d'une image suivant les colonnes
+---------------------------------------------------------------------------*/
+void Pyramid::filt_tab_cl(uint8_t *tab,int taille_c,int taille_l, filtre &utile)
+{
+    int i,j;
+    uint8_t *intermed;
+    intermed=(uint8_t*)calloc(taille_c*taille_l,sizeof(uint8_t));
+    for(j=0;j<taille_l;j++)
+    {
+        for(i=0;i<taille_c;i++)
+        {
+            *(intermed+i+j*taille_c)=filt_point_1d_cl(tab,taille_l,taille_c,i,j,utile);
+        }
+    }
+    for(j=0;j<taille_l;j++)
+    {
+        for(i=0;i<taille_c;i++)
+        {
+            *(tab+i+j*taille_c)= *(intermed+i+j*taille_c) * 4;
+        }
+    }
+    free(intermed);
+}
+
+/*---------------------------------------------------------------------------
+    Agrandissement d'une image (avec filtrage)
+---------------------------------------------------------------------------*/
+void Pyramid::agrandir(uint8_t *petit,uint8_t *grand,int taille_c,int taille_l, filtre &utile)
+{
+    int i,j;
+    uint8_t *intermed;
+    intermed=(uint8_t*)calloc(taille_c*taille_l*2,sizeof(uint8_t));
+    for(j=0;j<taille_l;j++)
+    {
+        for(i=0;i<taille_c;i++)
+        {
+            *(intermed+i*2+j*taille_c*2)=*(petit+i+j*taille_c);
+            *(intermed+i*2+j*taille_c*2+1)=0;
+        }
+    }
+    for(j=0;j<taille_l;j++)
+    {
+        filt_ligne((intermed+j*taille_c*2),taille_c*2,utile);
+    }
+    for(j=0;j<taille_l;j++)
+    {
+        for(i=0;i<taille_c*2;i++)
+        {
+            *(grand+i+(j*2)*taille_c*2)=*(intermed+i+j*taille_c*2);
+            *(grand+i+(j*2+1)*taille_c*2)=0;
+        }
+    }
+    filt_tab_cl(grand,taille_c*2,taille_l*2,utile);
+    free(intermed);
+}
+
+/*---------------------------------------------------------------------------
+    Rarangement de la pyramide
+---------------------------------------------------------------------------*/
+
+void Pyramid::reconstruction(uint8_t *pyra,int n, long nbc, long nbl)
+{
+    int i,j,k;
+    int q=0;
+    int p=0;
+    int fin=n;
+    int taille_c=nbc;
+    int taille_l=nbl;
+    uint8_t *intermed;
+    intermed=(uint8_t*)calloc(nbc*nbl,sizeof(uint8_t));
+    do
+    {
+        q=q+taille_c*taille_l;
+        taille_c=taille_c/2;
+        taille_l=taille_l/2;
+        k=0;
+        for(j=p;j<p+taille_l;j++)
+        {
+            for(i=0;i<taille_c;i++)
+            {
+                *(intermed+j*nbc+i)=*(pyra+k+q);
+                k++;
+            }
+        }
+        p=p+taille_l;
+        fin--;
+    }while(fin>0);
+    for(i=0;i<nbc*nbl;i++)
+    {
+        *(pyra+nbc*nbl+i)=*(intermed+i);
+    }
+   free(intermed);
+}
+
+int Pyramid::etage_max(const Image *im)
+{
+    int i;
+    int taille_c=im->getWidth();
+    int taille_l=im->getHeight();
+    for(i=0;taille_c||taille_l>1;i++)
+    {
+        taille_c=taille_c/2;
+        taille_l=taille_l/2;
+    }
+    i--;
+    return(i);
+}
+
+/*----------------------------------------------------------------------
+    Calcul de l'entropie d'une image donne en paramtre,
+    la fonction retourne la valeur de l'entropie.
+----------------------------------------------------------------------*/
+float Pyramid::entropie2(const uint8_t *tab,int taille_c,int taille_l)
+{
+    int i,j;
+    float pi[256],h=0;
+    int size;
+
+    size=taille_c*taille_l;
+
+/**********************************************************************/
+/*                    module de traitement                            */
+/**********************************************************************/
+
+/* initialisation  0 du tableau pi contenant l'histogramme */
+    for(i=0 ; i<256 ; i++)
+      pi[i] = 0;
+
+/* calcul de l'histogramme de l'image */
+    for(i=0 ; i<taille_l ; i++)
+      for(j=0 ; j<taille_c ; j++)
+         pi[*(tab+ i*taille_c +j)]++;
+
+/* calcul de l'entropie de l'image */
+    for(i=0 ; i<256 ; i++)
+    {
+      if(pi[i] != 0)
+      {
+         pi[i] /= size;
+         h -= (double)pi[i] * log((double)pi[i])/log((double)2.0);
+      }
+    }
+    return(h);
+}
+
+/*----------------------------------------------------------------------
+ Calcul et affichage de l'entropie des diffrents tages d'une pyramide
+----------------------------------------------------------------------*/
+string Pyramid::entropie_p(const uint8_t *pyra,int etage_f,int nbc,int nbl)
+{
+    int i;
+    int j=0;
+    float h;
+    int taille_c=nbc;
+    int taille_l=nbl;
+    char buffer[255];
+    string returnval;
+    for(i=0;i<=etage_f;i++)
+    {
+        h=entropie2((pyra+j),taille_c,taille_l);
+        j=j+taille_c*taille_l;
+        taille_c=taille_c/2;
+        taille_l=taille_l/2;
+        sprintf(buffer, "L'entropie de l'tage %d est %1f\n",i,h);
+        returnval = returnval + buffer;
+    }
+   return returnval;
+}
+
+
+Image *Pyramid::rebuild_interface( const Image *pyramid, int etage_f, int pyramid_to, filtre &utile ) {
+    // rebuilds from an image that was saved
+    // etage_f = stage that the original image was built to
+    char buffer[255];
+    if(!pyramid) {
+        throw "Error in TP6Pyramid::rebuild_interface:\npyramid = NULL";
+    }
+    if(pyramid->getWidth() * 2 != pyramid->getHeight()) {
+        sprintf( buffer, "Error in TP6Pyramid::rebuild_interface:\npyramid->getWidth = %d, pyramid->getHeight = %d", pyramid->getWidth(), pyramid->getHeight() );
+        throw buffer;
+    }
+    if(!(isPowerOf2(pyramid->getWidth()))) {
+        throw "Error in TP6Pyramid::rebuild_interface:\npyramid->getWidth not a power of 2";
+    }
+    if( etage_f <= 0 || (1 << etage_f) > pyramid->getWidth() ) {
+        throw "Error in TP6Pyramid::rebuild_interface:\nInvalid etage_f specified";
+    }
+    if(pyramid_to < 0 || pyramid_to >= etage_f) {
+        throw "Error in TP6Pyramid::rebuild_interface:\nInvalid pyramid_to specified";
+    }
+    long nbc = pyramid->getWidth();
+    long nbl = pyramid->getWidth();
+    int i;
+    int j=0;
+    int taille_c=nbc;
+    int taille_l=nbl;
+    Image *returnval = NULL;
+    int taille;
+    int q=0;
+    int etage_rec;
+    const uint8_t *pyra1 = pyramid->begin();
+    uint8_t* intermed = new uint8_t[nbc * nbc / 2 * 3];
+    uint8_t* rep = new uint8_t[nbc * nbc / 2 * 3];
+
+    // Copy info into rep in a packed format
+    long current_offset = 0;
+    long current_rep_offset = 0;
+    for(int n = 0; n <= etage_f; ++n) {
+        for(int j=0; j< taille_l; j++ ) {
+            for(int i=0; i< taille_c; i++ ) {
+                rep[current_rep_offset + j * taille_c + i] = pyra1[current_offset + j * pyramid->getWidth() + i];
+            }
+        }
+        current_offset = current_offset + taille_l * nbc;
+        current_rep_offset = current_rep_offset + taille_l * taille_c;
+        taille_l = taille_l / 2;
+        taille_c = taille_c / 2;
+    }
+
+/* reconstruction de l'image  partir de sa pyramide laplacienne en s'arretant
+     un niveau etage_rec choisi par l'utilisateur
+    La pyramide est contenue dans la zone mmoire pointe par rep */
+    etage_rec = pyramid_to;
+    taille=nbc;
+
+    for(i=0;i<etage_f;i++)
+    {
+        q=q+taille*taille;
+        taille=taille/2;
+    }
+    for(i=q;i<q+taille*taille;i++)
+    {
+        *(intermed+i)=*(rep+i);
+    }
+    for(i=etage_f;i>etage_rec;i--)
+    {
+        agrandir((intermed+q),(intermed+q-taille*taille*4),taille,taille,utile);
+        taille=taille*2;
+        q=q-taille*taille;
+        for(j=q;j<q+taille*taille;j++)
+        {
+            int value = rep[j];
+            if(value > 128) value = value - 256;
+            value = value + intermed[j];
+            if(value < 0) value = 0;
+            if(value > 255) value = 255;
+            intermed[j] = value;
+        }
+    }
+    //printf("Entrez le nom du fichier de l'image reconstruite :");
+    //scanf("%s",nom);
+    //ecrire_image((intermed+q),nom,taille,taille);
+    returnval = new GrayscaleImage(taille, taille, intermed+q);
+    free(intermed);
+    free(rep);
+    return returnval;
+}
diff --git a/app/Algorithms/Pyramid.h b/app/Algorithms/Pyramid.h
new file mode 100644
index 0000000..4ff5433
--- /dev/null
+++ b/app/Algorithms/Pyramid.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011-2012 INSA Rennes
+ *
+ * This file is part of EIImage.
+ *
+ * EIImage is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * EIImage is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with EIImage.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PYRAMID_H
+#define PYRAMID_H
+
+#include <Image.h>
+#include <GrayscaleImage.h>
+#include <string>
+
+namespace Pyramid
+{
+    inline bool isPowerOf2(int n) {
+        return ( ( n > 0 ) && ( (n & (n - 1) ) == 0) );
+    }
+
+    struct filtre {
+                char nom_f[30];
+                float coeff_f[10];
+          int taille_f;
+    };
+
+    class Filters
+    {
+    public:
+        Filters();
+        virtual ~Filters();
+        bool getFromPos( int pos, filtre &to_fill );
+        bool getFromName( const char *name, filtre &to_fill );
+        void getDefault( filtre &to_fill );
+        int size();
+    private:
+        const filtre *filters;
+        int num_filters;
+        void copy_filter( const filtre &source, filtre &dest );
+    };
+
+    void etage_suiv_g(const uint8_t *srcTab, uint8_t *dstTab, int srcWidth, int srcHeight, filtre &utile);
+    void pyram_g_n(uint8_t *rep, int nStage, long nbc, long nbl, const uint8_t *itab, filtre &utile);
+    void pyram_l_n (uint8_t *rep,int n, long nbc, long nbl, const uint8_t *itab, filtre &utile);
+    imagein::Image *pyram_g(const imagein::GrayscaleImage *im, int etage_f, filtre &utile, std::string &to_print);
+    imagein::Image *n_pyram_g(const imagein::Image *im, int etage_f, filtre &utile );
+    imagein::Image *pyram_l (const imagein::Image *im, int etage_f, filtre &utile, std::string &to_print);
+    imagein::Image *n_pyram_l(const imagein::Image *im, int etage_f, filtre &utile);
+    uint8_t filt_point_1d_lg(const uint8_t *tab,int cl, int x, int y, filtre &utile);
+    uint8_t filt_point_1d_cl(const uint8_t *tab,int lg,int cl, int x, int y, filtre &utile);
+    void filt_ligne(uint8_t *ligne,int taille_c, filtre &utile);
+    void filt_tab_cl(uint8_t *tab,int taille_c,int taille_l, filtre &utile);
+    void agrandir(uint8_t *petit,uint8_t *grand,int taille_c,int taille_l, filtre &utile);
+    void reconstruction(uint8_t *pyra,int n, long nbc, long nbl);
+    int etage_max(const imagein::Image *im);
+    float entropie2(const uint8_t *tab,int taille_c,int taille_l);
+    std::string entropie_p(const uint8_t *pyra,int etage_f,int nbc,int nbl);
+    imagein::Image* rebuild_interface(const imagein::Image *to_rebuild, int etage_f, int to_rebuild_to, filtre &utile );
+}
+
+#endif // PYRAMID_H
diff --git a/app/Operations/InversePyramidDialog.cpp b/app/Operations/InversePyramidDialog.cpp
new file mode 100644
index 0000000..b8f4712
--- /dev/null
+++ b/app/Operations/InversePyramidDialog.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2011-2012 INSA Rennes
+ *
+ * This file is part of EIImage.
+ *
+ * EIImage is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * EIImage is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with EIImage.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "InversePyramidDialog.h"
+#include "ui_InversePyramidDialog.h"
+
+InversePyramidDialog::InversePyramidDialog(QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::InversePyramidDialog)
+{
+    ui->setupUi(this);
+}
+
+InversePyramidDialog::~InversePyramidDialog()
+{
+    delete ui;
+}
+
+Pyramid::filtre InversePyramidDialog::getFilter() const {
+    Pyramid::Filters filters;
+    Pyramid::filtre filter;
+    switch(ui->filterBox->currentIndex()) {
+        case 1: filters.getFromName("gaussien", filter); break;
+        case 2: filters.getFromName("trimodal", filter); break;
+        case 3: filters.getFromName("rectangulaire", filter); break;
+        case 4: filters.getFromName("qmf", filter); break;
+        default: filters.getFromName("triangulaire", filter); break;
+    }
+    return filter;
+}
+
+int InversePyramidDialog::getNbStep() const {
+    return ui->nbStepBox->value();
+}
+
+int InversePyramidDialog::getStep() const {
+    return ui->stepBox->value();
+}
diff --git a/app/Operations/InversePyramidDialog.h b/app/Operations/InversePyramidDialog.h
new file mode 100644
index 0000000..3a29ec3
--- /dev/null
+++ b/app/Operations/InversePyramidDialog.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011-2012 INSA Rennes
+ *
+ * This file is part of EIImage.
+ *
+ * EIImage is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * EIImage is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with EIImage.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INVERSEPYRAMIDDIALOG_H
+#define INVERSEPYRAMIDDIALOG_H
+
+#include <QDialog>
+#include "../Algorithms/Pyramid.h"
+
+namespace Ui {
+class InversePyramidDialog;
+}
+
+class InversePyramidDialog : public QDialog
+{
+    Q_OBJECT
+    
+public:
+    explicit InversePyramidDialog(QWidget *parent = 0);
+    ~InversePyramidDialog();
+    Pyramid::filtre getFilter() const;
+    int getNbStep() const;
+    int getStep() const;
+
+    
+private:
+    Ui::InversePyramidDialog *ui;
+};
+
+#endif // INVERSEPYRAMIDDIALOG_H
diff --git a/app/Operations/InversePyramidDialog.ui b/app/Operations/InversePyramidDialog.ui
new file mode 100644
index 0000000..6338a5c
--- /dev/null
+++ b/app/Operations/InversePyramidDialog.ui
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>InversePyramidDialog</class>
+ <widget class="QDialog" name="InversePyramidDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>245</width>
+    <height>213</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Filter : </string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QComboBox" name="filterBox">
+     <item>
+      <property name="text">
+       <string>triangular</string>
+      </property>
+     </item>
+     <item>
+      <property name="text">
+       <string>gaussian</string>
+      </property>
+     </item>
+     <item>
+      <property name="text">
+       <string>trimodal</string>
+      </property>
+     </item>
+     <item>
+      <property name="text">
+       <string>rectangular</string>
+      </property>
+     </item>
+     <item>
+      <property name="text">
+       <string>qmf</string>
+      </property>
+     </item>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QLabel" name="nbStepLabel">
+     <property name="text">
+      <string>Number of steps in the pyramid : </string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QSpinBox" name="nbStepBox">
+     <property name="minimum">
+      <number>1</number>
+     </property>
+     <property name="maximum">
+      <number>9</number>
+     </property>
+     <property name="value">
+      <number>9</number>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_2">
+     <property name="text">
+      <string>Step to reconstruct :</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QSpinBox" name="stepBox">
+     <property name="minimum">
+      <number>0</number>
+     </property>
+     <property name="maximum">
+      <number>8</number>
+     </property>
+     <property name="value">
+      <number>0</number>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox_2">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox_2</sender>
+   <signal>accepted()</signal>
+   <receiver>InversePyramidDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>122</x>
+     <y>191</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>122</x>
+     <y>106</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox_2</sender>
+   <signal>rejected()</signal>
+   <receiver>InversePyramidDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>122</x>
+     <y>191</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>122</x>
+     <y>106</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/app/Operations/InversePyramidOp.cpp b/app/Operations/InversePyramidOp.cpp
new file mode 100644
index 0000000..f0930c3
--- /dev/null
+++ b/app/Operations/InversePyramidOp.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011-2012 INSA Rennes
+ *
+ * This file is part of EIImage.
+ *
+ * EIImage is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * EIImage is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with EIImage.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "InversePyramidOp.h"
+#include <QApplication>
+#include <QMessageBox>
+#include "../Algorithms/Pyramid.h"
+#include "InversePyramidDialog.h"
+#include <GrayscaleImage.h>
+#include <Converter.h>
+
+using namespace std;
+using namespace imagein;
+
+InversePyramidOp::InversePyramidOp() : Operation(qApp->translate("Operations", "Reconstruct pyramid").toStdString())
+{
+}
+
+bool InversePyramidOp::needCurrentImg() const {
+    return true;
+}
+
+void InversePyramidOp::operator()(const imagein::Image* img, const std::map<const imagein::Image*, std::string>&) {
+    if(2 * img->getWidth() != img->getHeight()) {
+        QMessageBox::warning(NULL, qApp->translate("Operations", "The operation can't be applied on this image"),
+                             qApp->translate("Operations", "The image width must be twice the image height."));
+        return;
+    }
+    if(!Pyramid::isPowerOf2(img->getWidth())) {
+        QMessageBox::warning(NULL, qApp->translate("Operations", "The operation can't be applied on this image"),
+                             qApp->translate("Operations", "The image dimensions must be power of 2."));
+        return;
+    }
+
+    InversePyramidDialog* dialog = new InversePyramidDialog(QApplication::activeWindow());
+    QDialog::DialogCode code = static_cast<QDialog::DialogCode>(dialog->exec());
+
+    if(code!=QDialog::Accepted) return;
+
+    GrayscaleImage* image = Converter<GrayscaleImage>::convert(*img);
+    Image* resImg = NULL;
+    string s;
+    Pyramid::filtre filter = dialog->getFilter();
+    try {
+        resImg = Pyramid::rebuild_interface(image, dialog->getNbStep(), dialog->getStep(), filter);
+    }
+    catch(const char*e) {
+        QMessageBox::critical(NULL, "Error", QString(e));
+        return;
+    }
+    outImage(resImg, "Pyramid");
+    outText(s);
+
+}
diff --git a/app/Operations/InversePyramidOp.h b/app/Operations/InversePyramidOp.h
new file mode 100644
index 0000000..2c56a1b
--- /dev/null
+++ b/app/Operations/InversePyramidOp.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011-2012 INSA Rennes
+ *
+ * This file is part of EIImage.
+ *
+ * EIImage is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * EIImage is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with EIImage.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INVERSEPYRAMID_H
+#define INVERSEPYRAMID_H
+
+#include <Operation.h>
+
+class InversePyramidOp : public Operation
+{
+public:
+    InversePyramidOp();
+
+    void operator()(const imagein::Image*, const std::map<const imagein::Image*, std::string>&);
+
+    bool needCurrentImg() const;
+};
+
+#endif // INVERSEPYRAMID_H
diff --git a/app/Operations/PyramidDialog.cpp b/app/Operations/PyramidDialog.cpp
new file mode 100644
index 0000000..185f65d
--- /dev/null
+++ b/app/Operations/PyramidDialog.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011-2012 INSA Rennes
+ *
+ * This file is part of EIImage.
+ *
+ * EIImage is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * EIImage is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with EIImage.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "PyramidDialog.h"
+#include "ui_PyramidDialog.h"
+
+PyramidDialog::PyramidDialog(QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::PyramidDialog)
+{
+    ui->setupUi(this);
+}
+
+PyramidDialog::~PyramidDialog()
+{
+    delete ui;
+}
+
+Pyramid::filtre PyramidDialog::getFilter() const {
+    Pyramid::Filters filters;
+    Pyramid::filtre filter;
+    switch(ui->filterBox->currentIndex()) {
+        case 1: filters.getFromName("gaussien", filter); break;
+        case 2: filters.getFromName("trimodal", filter); break;
+        case 3: filters.getFromName("rectangulaire", filter); break;
+        case 4: filters.getFromName("qmf", filter); break;
+        default: filters.getFromName("triangulaire", filter); break;
+    }
+    return filter;
+}
+
+int PyramidDialog::getNbStep() {
+    return ui->stepBox->value();
+}
+
+bool PyramidDialog::isGaussian() const {
+    return ui->gaussianButton->isChecked();
+}
+
+bool PyramidDialog::onlyOneStep() const {
+    return ui->oneStepBox->isChecked();
+}
+
+int PyramidDialog::onlyStep() const {
+    return ui->onlyStepBox->value();
+}
diff --git a/app/Operations/PyramidDialog.h b/app/Operations/PyramidDialog.h
new file mode 100644
index 0000000..9065a0f
--- /dev/null
+++ b/app/Operations/PyramidDialog.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2011-2012 INSA Rennes
+ *
+ * This file is part of EIImage.
+ *
+ * EIImage is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * EIImage is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with EIImage.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PYRAMIDDIALOG_H
+#define PYRAMIDDIALOG_H
+
+#include <QDialog>
+#include "../Algorithms/Pyramid.h"
+
+namespace Ui {
+class PyramidDialog;
+}
+
+class PyramidDialog : public QDialog
+{
+    Q_OBJECT
+    
+public:
+    explicit PyramidDialog(QWidget *parent = 0);
+    ~PyramidDialog();
+    Pyramid::filtre getFilter() const;
+    int getNbStep();
+    bool isGaussian() const;
+    bool onlyOneStep() const;
+    int onlyStep() const;
+    
+private:
+    Ui::PyramidDialog *ui;
+};
+
+#endif // PYRAMIDDIALOG_H
diff --git a/app/Operations/PyramidDialog.ui b/app/Operations/PyramidDialog.ui
new file mode 100644
index 0000000..d0c85b4
--- /dev/null
+++ b/app/Operations/PyramidDialog.ui
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PyramidDialog</class>
+ <widget class="QDialog" name="PyramidDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>259</width>
+    <height>231</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QGroupBox" name="groupBox">
+     <property name="title">
+      <string>Type of pyramid</string>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <item>
+       <widget class="QRadioButton" name="gaussianButton">
+        <property name="text">
+         <string>gaussian</string>
+        </property>
+        <property name="checked">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="laplacianButton">
+        <property name="text">
+         <string>laplacian</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <layout class="QFormLayout" name="formLayout">
+     <item row="0" column="0">
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Filter : </string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QComboBox" name="filterBox">
+       <item>
+        <property name="text">
+         <string>triangular</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>gaussian</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>trimodal</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>rectangular</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>qmf</string>
+        </property>
+       </item>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="nbStepLabel">
+       <property name="text">
+        <string>Number of steps : </string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QSpinBox" name="stepBox">
+       <property name="minimum">
+        <number>1</number>
+       </property>
+       <property name="maximum">
+        <number>9</number>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QCheckBox" name="oneStepBox">
+       <property name="text">
+        <string>Create only one step :</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QSpinBox" name="onlyStepBox">
+       <property name="enabled">
+        <bool>false</bool>
+       </property>
+       <property name="minimum">
+        <number>1</number>
+       </property>
+       <property name="maximum">
+        <number>9</number>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>PyramidDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>PyramidDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>oneStepBox</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>onlyStepBox</receiver>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>96</x>
+     <y>164</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>218</x>
+     <y>164</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>oneStepBox</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>nbStepLabel</receiver>
+   <slot>setDisabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>96</x>
+     <y>164</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>70</x>
+     <y>120</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>oneStepBox</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>stepBox</receiver>
+   <slot>setDisabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>96</x>
+     <y>164</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>193</x>
+     <y>120</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/app/Operations/PyramidOp.cpp b/app/Operations/PyramidOp.cpp
new file mode 100644
index 0000000..eb52b7c
--- /dev/null
+++ b/app/Operations/PyramidOp.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2011-2012 INSA Rennes
+ *
+ * This file is part of EIImage.
+ *
+ * EIImage is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * EIImage is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with EIImage.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "PyramidOp.h"
+
+#include <QApplication>
+#include "../Algorithms/Pyramid.h"
+#include "PyramidDialog.h"
+#include <Converter.h>
+#include <GrayscaleImage.h>
+#include <QMessageBox>
+
+using namespace std;
+using namespace imagein;
+
+PyramidOp::PyramidOp() : Operation(qApp->translate("Operations", "Create pyramid").toStdString())
+{
+}
+
+bool PyramidOp::needCurrentImg() const {
+    return true;
+}
+
+void PyramidOp::operator()(const imagein::Image* img, const std::map<const imagein::Image*, std::string>&) {
+
+    if(img->getWidth() != img->getHeight()) {
+        QMessageBox::warning(NULL, qApp->translate("Operations", "The operation can't be applied on this image"),
+                             qApp->translate("Operations", "The image width must equal the image height."));
+        return;
+    }
+    if(!Pyramid::isPowerOf2(img->getWidth())) {
+        QMessageBox::warning(NULL, qApp->translate("Operations", "The operation can't be applied on this image"),
+                             qApp->translate("Operations", "The image dimensions must be power of 2."));
+        return;
+    }
+
+    PyramidDialog* dialog = new PyramidDialog(QApplication::activeWindow());
+    QDialog::DialogCode code = static_cast<QDialog::DialogCode>(dialog->exec());
+
+    if(code!=QDialog::Accepted) return;
+
+    GrayscaleImage* image = Converter<GrayscaleImage>::convert(*img);
+    Image* resImg = NULL;
+    string s;
+    Pyramid::filtre filtre = dialog->getFilter();
+    try {
+        if(dialog->onlyOneStep()) {
+            if(dialog->isGaussian()) {
+                resImg = Pyramid::n_pyram_g(image, dialog->onlyStep(), filtre);
+            }
+            else {
+                resImg = Pyramid::n_pyram_l(image, dialog->onlyStep(), filtre);
+            }
+        }
+        else {
+            if(dialog->isGaussian()) {
+                resImg = Pyramid::pyram_g(image, dialog->getNbStep(), filtre, s);
+            }
+            else {
+                resImg = Pyramid::pyram_l(image, dialog->getNbStep(), filtre, s);
+            }
+        }
+    }
+    catch(const char*e) {
+        QMessageBox::critical(NULL, "Error", QString(e));
+        return;
+    }
+    outImage(resImg, "Pyramid");
+    outText(s);
+}
diff --git a/app/Operations/PyramidOp.h b/app/Operations/PyramidOp.h
new file mode 100644
index 0000000..88dbe6a
--- /dev/null
+++ b/app/Operations/PyramidOp.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011-2012 INSA Rennes
+ *
+ * This file is part of EIImage.
+ *
+ * EIImage is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * EIImage is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with EIImage.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PYRAMIDOP_H
+#define PYRAMIDOP_H
+
+#include <Operation.h>
+
+class PyramidOp : public Operation
+{
+public:
+    PyramidOp();
+
+    void operator()(const imagein::Image*, const std::map<const imagein::Image*, std::string>&);
+
+    bool needCurrentImg() const;
+};
+
+#endif // PYRAMIDOP_H
-- 
GitLab