SilentEye 0.4.1

modules/seformatjpegold/seformatjpeg/groupedimage.cpp

Go to the documentation of this file.
00001 //  This file is part of SilentEye.
00002 //
00003 //  SilentEye is free software: you can redistribute it and/or modify
00004 //  it under the terms of the GNU General Public License as published by
00005 //  the Free Software Foundation, either version 3 of the License, or
00006 //  (at your option) any later version.
00007 //
00008 //  SilentEye is distributed in the hope that it will be useful,
00009 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 //  GNU General Public License for more details.
00012 //
00013 //  You should have received a copy of the GNU General Public License
00014 //  along with SilentEye. If not, see <http://www.gnu.org/licenses/>.
00015 
00016 #include "groupedimage.h"
00017 #include <moduleexception.h>
00018 #include <QDebug>
00019 
00020 #include <math.h>
00021 #include <algorithm>
00022 
00023 using namespace SilentEyeFramework;
00024 
00025 namespace SEFormatJPEG {
00026 
00027     PixelGroup::PixelGroup(QObject* parent) : QObject(parent)
00028     {
00029         setObjectName("PixelGroup");
00030         m_logger = new Logger(this);
00031 
00032         m_pixels.resize(PIXEL_GROUP_SIZE*PIXEL_GROUP_SIZE);
00033         m_miv = -1;
00034     }
00035 
00036     PixelGroup::~PixelGroup() {
00037         if (!m_logger.isNull())
00038         {
00039             delete m_logger;
00040         }
00041         
00042         /*for(int i=0; i< m_pixels.size(); i++)
00043         {
00044             if (!m_pixels[i].isNull())
00045             {
00046                 delete m_pixels[i];
00047             }
00048         }*/
00049     }
00050 
00051     QPointer<YCbCr> PixelGroup::pixel(quint8 x, quint8 y)
00052     {
00053         int index = (y * PIXEL_GROUP_SIZE) + x;
00054         
00055         if (index >= PIXEL_GROUP_SIZE*PIXEL_GROUP_SIZE)
00056         {
00057             m_logger->warning("cannot get pixel: position is out of range (x:" + QString::number(x)
00058                               + ",y:"+ QString::number(y) + ")");
00059             return QPointer<YCbCr>();
00060         }
00061         else 
00062         {
00063             return m_pixels[index];
00064         }
00065     }
00066     
00067     void PixelGroup::setPixel(quint8 x, quint8 y, QPointer<YCbCr> pixel)
00068     {
00069         int index = (y * PIXEL_GROUP_SIZE) + x;
00070         
00071         if (index >= PIXEL_GROUP_SIZE*PIXEL_GROUP_SIZE)
00072         {
00073             m_logger->warning("cannot set pixel: position is out of range (x:"
00074                               + QString::number(x) + ",y:"+ QString::number(y) + ")");
00075         }
00076         else
00077         {
00078             m_pixels[index] = pixel;
00079             computeMIV();
00080         }
00081     }
00082     
00083     float PixelGroup::miv() const
00084     {
00085         return m_miv;
00086     }
00087 
00088     void PixelGroup::updateMivTo(float destMiv)
00089     {
00090         if (destMiv == m_miv)
00091         {
00092             return;
00093         }
00094         else if (destMiv < 0 || destMiv > 255)
00095         {
00096             m_logger->warning("Ignore MIV update> dest: " + QString::number(destMiv) + ",current: " + QString::number(m_miv));
00097             return;
00098         }
00099 
00100         qint8 tries = 0;
00101         double distance = destMiv - m_miv;
00102         do
00103         {
00104             for (int y=0; y<height(); y++)
00105             {
00106                 for (int x=0; x<width(); x++)
00107                 {
00108                     int qx = (x < width()/2.0) ? x+1 : width() - x;
00109                     int qy = (y < height()/2.0) ? y+1 : height() - y;
00110                     int q = std::min(qx, qy);
00111                     updatePixelMiv(pixel(x, y), (q/(width()/4.0)) * distance);
00112                 }
00113             }
00114 
00115             computeMIV();
00116             tries++;
00117 
00118             distance = destMiv - m_miv;
00119 
00120         } while (abs(distance) > 0.1 && tries < 5);
00121 
00122         if (abs(m_miv - destMiv) > 1)
00123         {
00124             m_logger->warning("MIV destination not reached> dest: " + QString::number(destMiv)
00125                               + ",new: " + QString::number(m_miv));
00126         }
00127     }
00128 
00129     void PixelGroup::updatePixelMiv(QPointer<YCbCr> p, double distance)
00130     {
00131         if (!p.isNull() && p->y() != -1)
00132         {
00133             if (p->y() + distance < 0)
00134             {
00135                 p->setY(0);
00136             }
00137             else if (p->y() + distance > 255)
00138             {
00139                 p->setY(255);
00140             }
00141             else
00142             {
00143                 p->setY(p->y() + distance);
00144             }
00145         }
00146 
00147     }
00148 
00149     void PixelGroup::computeMIV()
00150     {
00151         int cpt = 0;
00152         double sum = 0;
00153 
00154         for (int i=0; i<PIXEL_GROUP_SIZE*PIXEL_GROUP_SIZE; i++)
00155         {
00156             QPointer<YCbCr> p = m_pixels[i];
00157             if (!p.isNull() && p->y() >=0 && p->y() <= 255)
00158             {
00159                 sum = sum + p->y();
00160                 cpt = cpt + 1;
00161             }
00162         }
00163 
00164         if (cpt > 0)
00165         {
00166             m_miv = sum / cpt;
00167             //m_miv = round(sum / cpt);
00168         }
00169         else
00170         {
00171             m_miv = -1;
00172         }
00173     }
00174     
00175     QString PixelGroup::toString() const
00176     {
00177         QString str = "";
00178         for (int i=0; i<PIXEL_GROUP_SIZE*PIXEL_GROUP_SIZE; i++)
00179         {
00180             str += "[" + QString::number(i) + "|";
00181             QPointer<YCbCr> p = m_pixels[i];
00182             if (!p.isNull())
00183             {
00184                 str += p->toString();
00185             } else {
00186                 str += "null";
00187             }
00188             str += "]";
00189         }
00190         return str + "(" + QString::number(m_miv) + ")";
00191     }
00192 
00193     GroupedImage::GroupedImage(QImage& image, quint8 k, QObject* parent) : QObject(parent)
00194     {
00195         setObjectName("GroupedImage");
00196         m_logger = new Logger(this);
00197         
00198         m_initialWidth = image.width();
00199         m_initialHeight = image.height();
00200         m_initialFormat = image.format();
00201         
00202         if (m_initialWidth % PixelGroup::width() != 0)
00203             m_width = (int) floor((double)m_initialWidth / PixelGroup::width()) + 1;
00204         else
00205             m_width = m_initialWidth / PixelGroup::width();
00206 
00207         if (m_initialHeight % PixelGroup::height() != 0)
00208             m_height = (int) floor((double)m_initialHeight / PixelGroup::height()) + 1;
00209         else
00210             m_height = m_initialHeight / PixelGroup::height();
00211 
00212         
00213         m_pg.resize(m_width*m_height);
00214         
00215         compacteAndGroupImage(image, k);
00216     }
00217     
00218     GroupedImage::~GroupedImage()
00219     {
00220         /*for (int i=0; i<m_pg.size(); i++)
00221         {
00222             if (!m_pg[i].isNull())
00223             {
00224                 delete m_pg[i];
00225             }
00226         }*/
00227     }
00228 
00229     quint16 GroupedImage::width()
00230     {
00231         return m_width;
00232     }
00233     
00234     quint16 GroupedImage::height()
00235     {
00236         return m_height;
00237     }
00238     
00239     quint16 GroupedImage::initialWidth()
00240     {
00241         return m_initialWidth;
00242     }
00243     
00244     quint16 GroupedImage::initialHeight()
00245     {
00246         return m_initialHeight;
00247     }
00248 
00249     QPointer<PixelGroup> GroupedImage::pixelGroup(quint16 x, quint16 y)
00250     {
00251         return m_pg[x+(y*m_width)];
00252     }
00253 
00254     void GroupedImage::compacteAndGroupImage(QImage& image, quint8 k) {
00255 
00256         m_logger->debug("Grouping image...");
00257         for (int y = 0; y < m_initialHeight; y += PixelGroup::height())
00258         {
00259             for (int x = 0; x < m_initialWidth; x += PixelGroup::width())
00260             {
00261                 QPointer<PixelGroup> currentPixelGroup = new PixelGroup(this);
00262                 for (int pgY = 0; pgY < PixelGroup::height(); pgY++)
00263                 {
00264                     for (int pgX = 0; pgX < PixelGroup::width(); pgX++)
00265                     {
00266                         QPointer<YCbCr> ycbcr;
00267                         if (x + pgX >= m_initialWidth || y + pgY >= m_initialHeight)
00268                         {
00269                             /*m_logger->debug("Out of bound: "
00270                                             + QString::number(x + pgX)
00271                                             + ":"
00272                                             + QString::number(y + pgY));*/
00273                             ycbcr = new YCbCr(-1, -1, -1, this);
00274                         }
00275                         else
00276                         {
00277                             // convert color to YCbCr and compact luminance
00278                             ycbcr = new YCbCr(image.pixel(x + pgX, y + pgY), this);
00279                             // compact luminance (between +K et 255-K)
00280                             ycbcr->setY((double)(k + (ycbcr->y() * (128-k)/128.0) ));
00281                         }
00282                         currentPixelGroup->setPixel(pgX, pgY, ycbcr);
00283                     }
00284                 }
00285 
00286                 // Compute and set the current pixel group computed to the new image
00287                 int giX = floor(x / (double)PixelGroup::width());
00288                 int giY = floor(y / (double)PixelGroup::height());
00289                 m_pg[giX + (giY * m_width)] = currentPixelGroup;
00290             }
00291         }
00292         m_logger->debug("Grouped image created");
00293     }
00294 
00295     QImage* GroupedImage::toImage()
00296     {
00297         m_logger->debug("Converting grouped image to rgb image...");
00298 
00299         QImage* img = new QImage(m_initialWidth, m_initialHeight, m_initialFormat);
00300         // iterate on each group
00301         for (int i=0; i<m_pg.size(); i++)
00302         {
00303             int x = (i % m_width) * PixelGroup::width();
00304             int y = floor(i / (double)m_width) * PixelGroup::height();
00305 
00306             for (int pgY = 0; pgY < m_pg[i]->height(); pgY++)
00307             {
00308                 for (int pgX = 0; pgX < m_pg[i]->width(); pgX++)
00309                 {
00310                     QPointer<YCbCr> pixel = m_pg[i]->pixel(pgX, pgY);
00311                     // if we are in the image space
00312                     if (!pixel.isNull())
00313                     {
00314                         if (pixel->y() != -1
00315                             && x + pgX < m_initialWidth && y + pgY < m_initialHeight)
00316                         {
00317                             // add current pixel to image
00318                             img->setPixel(x + pgX, y + pgY, pixel->toRGB());
00319                         }
00320                     }
00321                 }
00322             }
00323         }
00324 
00325         m_logger->debug("Grouped image converted.");
00326         
00327         return img;
00328     }
00329 
00330 }