Basic Image AlgorithmS Library 2.8.0

ImageDistribution.cpp

00001 /*
00002 This file is part of the BIAS library (Basic ImageAlgorithmS).
00003 
00004 Copyright (C) 2003-2009    (see file CONTACT for details)
00005   Multimediale Systeme der Informationsverarbeitung
00006   Institut fuer Informatik
00007   Christian-Albrechts-Universitaet Kiel
00008 
00009 
00010 BIAS is free software; you can redistribute it and/or modify
00011 it under the terms of the GNU Lesser General Public License as published by
00012 the Free Software Foundation; either version 2.1 of the License, or
00013 (at your option) any later version.
00014 
00015 BIAS is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU Lesser General Public License for more details.
00019 
00020 You should have received a copy of the GNU Lesser General Public License
00021 along with BIAS; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 */
00024 
00025 #include "ImageDistribution.hh"
00026 
00027 using namespace std;
00028 using namespace BIAS;
00029 
00030 void ImageDistribution::MapImagesToFixedSize(vector<Image<unsigned char> > &inputImages,
00031                                              Image<unsigned char> &outputImage,
00032                                              vector<Vector2<unsigned int> > &imagePositionsPixel)
00033 {
00034  
00035   vector<Image<unsigned char>*> inputPtrs;
00036   
00037   for(unsigned int i=0; i<inputImages.size(); i++){
00038     inputPtrs.push_back(&inputImages[i]);
00039   }
00040   
00041   MapImagesToFixedSize(inputPtrs, 
00042                        outputImage, 
00043                        imagePositionsPixel);
00044   
00045 }
00046 
00047 void ImageDistribution::MapImagesToFixedSize(const vector<Image<unsigned char>*> &inputImages,
00048                                              Image<unsigned char> &outputImage,
00049                                              vector<Vector2<unsigned int> > &imagePositionsPixel)
00050 {
00051   cout << "mapping to fixed size..." << endl;
00052 
00053   // init output
00054   outputImage.SetZero();
00055   imagePositionsPixel.clear();
00056 
00057   // assertions and early termination
00058   if (inputImages.size() == 0) return;
00059 
00060   BIASASSERT(inputImages[0]->GetWidth() > 0)
00061   BIASASSERT(inputImages[0]->GetHeight() > 0)
00062   BIASASSERT(outputImage.GetWidth() > 0)
00063   BIASASSERT(outputImage.GetHeight() > 0)
00064 
00065   // define some vars for better readability
00066   const unsigned int &numImages = inputImages.size();
00067   const unsigned int &widthIn = inputImages[0]->GetWidth();
00068   const unsigned int &heightIn = inputImages[0]->GetHeight();
00069 
00070   const unsigned int &widthOut = outputImage.GetWidth();
00071   const unsigned int &heightOut = outputImage.GetHeight();
00072 
00073   // compute grid and scale
00074   unsigned int numCols;
00075   unsigned int numRows;
00076   float scale;
00077 
00078   ComputeGridAndScale(numImages, widthIn, heightIn, widthOut, heightOut,
00079                       numCols, numRows, scale);
00080 
00081   // compute image positions
00082   vector<Vector2<unsigned int> > imPosGrid;
00083   vector<vector<int> > imageIndices;
00084 
00085   ComputeImagePositions(numImages, widthIn, heightIn, numRows, numCols, scale,
00086                         imPosGrid, imagePositionsPixel, imageIndices);
00087 
00088   // map the input images
00089   unsigned char* outputImData = outputImage.GetImageData();
00090 
00091   float widthInScaled = float(widthIn) * scale;
00092   float heightInScaled = float(heightIn) * scale;
00093 
00094   for (unsigned int y = 0; y < heightOut; ++y) {
00095     // at the bottom may be unused pixels
00096     if (y >= (numRows * heightInScaled)) { break; }
00097 
00098     // get row in which current pixel lies
00099     const unsigned int row = (unsigned)floor(float(y) / heightInScaled);
00100 
00101     for (unsigned int x = 0; x < widthOut; ++x) {
00102       // at the right-hand side may be unused pixels
00103       if (x >= (numCols * widthInScaled)) { break; }
00104 
00105       // get column in which current pixel lies
00106       const unsigned int col = (unsigned)floor(float(x) / widthInScaled);
00107 
00108       // now search for the image in the current row and column
00109       const int curImageIndex = imageIndices[col][row];
00110 
00111       if (curImageIndex == -1) {
00112         continue;
00113       }
00114 
00115       // compute the array offsets
00116       const unsigned int xImage = (unsigned)rint((x - col * widthInScaled) / scale);
00117       const unsigned int yImage = (unsigned)rint((y - row * heightInScaled) / scale);
00118 
00119       const unsigned int inputOffset
00120           = (yImage
00121              * inputImages[curImageIndex]->GetWidth()
00122              * inputImages[curImageIndex]->GetChannelCount())
00123             + (xImage
00124                * inputImages[curImageIndex]->GetChannelCount());
00125 
00126       const unsigned int outputOffset
00127           = (y
00128              * outputImage.GetWidth()
00129              * outputImage.GetChannelCount())
00130             + (x
00131                * outputImage.GetChannelCount());
00132 
00133       // finally map pixels
00134       const unsigned char* inputImData
00135           = inputImages[curImageIndex]->GetImageData();
00136 
00137       for (unsigned int c = 0; c < outputImage.GetChannelCount(); ++c) {
00138         outputImData[outputOffset + c] = inputImData[inputOffset + c];
00139       }
00140     }
00141   }
00142 }
00143 
00144 
00145 
00146 void ImageDistribution::MapImagesToSquare(vector<Image<unsigned char> > &inputImages,
00147                                           Image<unsigned char> &outputImage,
00148                                           vector<Vector2<unsigned int> > &imagePositionsPixel)
00149 {
00150   vector<Image<unsigned char>*> inputPtrs;
00151   
00152   for(unsigned int i=0; i<inputImages.size(); i++){
00153     inputPtrs.push_back(&inputImages[i]);
00154   }
00155   
00156   MapImagesToSquare(inputPtrs, 
00157                     outputImage, 
00158                     imagePositionsPixel);
00159 }
00160 
00161 void ImageDistribution::MapImagesToSquare(const vector<Image<unsigned char>*> &inputImages,
00162                                           Image<unsigned char> &outputImage,
00163                                           vector<Vector2<unsigned int> > &imagePositionsPixel)
00164 {
00165   cout << "mapping to square (scale is ignored)..." << endl;
00166 
00167   outputImage.SetZero();
00168 
00169   const unsigned int numImages = inputImages.size();
00170   const unsigned int widthIn = inputImages[0]->GetWidth();
00171   const unsigned int heightIn = inputImages[0]->GetHeight();
00172 
00173   // map to unit square and later ignore the scale factor
00174   const unsigned int widthOut = 1;
00175   const unsigned int heightOut = 1;
00176 
00177   // compute grid and scale
00178   unsigned int numCols;
00179   unsigned int numRows;
00180   float scale;
00181 
00182   ComputeGridAndScale(numImages, widthIn, heightIn, widthOut, heightOut,
00183                       numCols, numRows, scale);
00184 
00185   // compute image positions
00186   vector<Vector2<unsigned int> > imPosGrid;
00187   vector<Vector2<unsigned int> > imPosPixel;
00188   vector<vector<int> > imageIndices;
00189 
00190   ComputeImagePositions(numImages, widthIn, heightIn, numRows, numCols, scale,
00191                         imPosGrid, imPosPixel, imageIndices);
00192 
00193   // compute size of output image and resize it
00194   const unsigned int edgeLength = max(numCols * widthIn, numRows * heightIn);
00195 
00196   outputImage.Init(edgeLength, edgeLength, inputImages[0]->GetChannelCount());
00197 
00198   // map the input images
00199   unsigned char* outputImData = outputImage.GetImageData();
00200 
00201   for (size_t imageCount = 0; imageCount < numImages; ++imageCount) {
00202     const unsigned char* inputImData = inputImages[imageCount]->GetImageData();
00203 
00204     const unsigned int xOffset = imPosGrid[imageCount][0] * widthIn;
00205     const unsigned int yOffset = imPosGrid[imageCount][1] * heightIn;
00206 
00207     for (unsigned int y = 0; y < inputImages[imageCount]->GetHeight(); ++y) {
00208       for (unsigned int x = 0; x < inputImages[imageCount]->GetWidth(); ++x) {
00209         const unsigned int inputOffset
00210             = (y
00211                * inputImages[imageCount]->GetWidth()
00212                * inputImages[imageCount]->GetChannelCount())
00213               + (x
00214                  * inputImages[imageCount]->GetChannelCount());
00215 
00216         const unsigned int outputOffset
00217             = ((y + yOffset)
00218                * outputImage.GetWidth()
00219                * outputImage.GetChannelCount())
00220               + ((x + xOffset)
00221                  * outputImage.GetChannelCount());
00222 
00223         for (unsigned int c = 0; c < inputImages[imageCount]->GetChannelCount(); ++c) {
00224           outputImData[outputOffset + c] = inputImData[inputOffset + c];
00225         }
00226       }
00227     }
00228   }
00229 
00230   // recompute image positions with scale 1.0
00231   ComputeImagePositions(numImages, widthIn, heightIn, numRows, numCols, 1.0,
00232                         imPosGrid, imagePositionsPixel, imageIndices);
00233 }
00234 
00235 
00236 void ImageDistribution::ComputeGridAndScale(unsigned int numImages,
00237                                             unsigned int widthIn,
00238                                             unsigned int heightIn,
00239                                             unsigned int widthOut,
00240                                             unsigned int heightOut,
00241                                             unsigned int &numCols,
00242                                             unsigned int &numRows,
00243                                             float &scale)
00244 {
00245   numCols = 0;
00246   numRows = 0;
00247   scale = 0.0;
00248 
00249   // using floats for the computations
00250   const float numImagesF = (float)numImages;
00251   const float widthInF = (float)widthIn;
00252   const float heightInF = (float)heightIn;
00253 
00254   const float widthOutF = (float)widthOut;
00255   const float heightOutF = (float)heightOut;
00256 
00257   // find optimal configuration with highest scaling factor
00258   for (float tmpNumCols = numImagesF; tmpNumCols >= 1.0; --tmpNumCols) {
00259     const float tmpNumRows = ceil(numImagesF / tmpNumCols);
00260 
00261     // minimun of horizontal or vertical scale
00262     const float tmpScale = min(widthOutF / (tmpNumCols * widthInF),
00263                                heightOutF / (tmpNumRows * heightInF));
00264 
00265     if (tmpScale > scale) {
00266       numCols = (unsigned int)tmpNumCols;
00267       numRows = (unsigned int)tmpNumRows;
00268       scale = tmpScale;
00269     }
00270   }
00271 
00272   cout << "taking " << numCols << "x" << numRows << " @ "
00273       << (scale * 100.0) << "%" << endl;
00274 }
00275 
00276 void ImageDistribution::ComputeImagePositions(unsigned int numImages,
00277                                               unsigned int widthIn,
00278                                               unsigned int heightIn,
00279                                               unsigned int numRows,
00280                                               unsigned int numCols,
00281                                               float scale,
00282                                               vector<Vector2<unsigned int> > &imagePositionsGrid,
00283                                               vector<Vector2<unsigned int> > &imagePositionsPixel,
00284                                               vector<vector<int> > &imageIndices)
00285 {
00286   // using floats for the computations
00287   const float numImagesF = (float)numImages;
00288   const float widthInF = (float)widthIn;
00289   const float heightInF = (float)heightIn;
00290 
00291   const float numColsF = (float)numCols;
00292 
00293   // for each grid cell we want to know which image is to be painted inside
00294   imageIndices.clear();
00295 
00296   imageIndices.resize(numCols);
00297   for (unsigned int colCount = 0; colCount < numCols; ++colCount) {
00298     imageIndices[colCount].resize(numRows, -1);
00299   }
00300 
00301   // compute upper left corner for each image in destination area
00302   imagePositionsGrid.clear();
00303   imagePositionsGrid.reserve(size_t(numImagesF));
00304   imagePositionsPixel.clear();
00305   imagePositionsPixel.reserve(size_t(numImagesF));
00306 
00307   for (size_t imageCount = 0; imageCount < size_t(numImagesF); ++imageCount) {
00308     // compute row and column of current image
00309     const unsigned int row = (unsigned int)floor(float(imageCount) / numColsF);
00310     const unsigned int col = (unsigned int)(imageCount - (row * numColsF));
00311 
00312     // save grid as well as pixel position and image index
00313     imagePositionsGrid.push_back(Vector2<unsigned int>(col, row));
00314     imagePositionsPixel.push_back(Vector2<unsigned int>((unsigned)rint(col * widthInF * scale),
00315                                                         (unsigned)rint(row * heightInF * scale)));
00316     imageIndices[col][row] = imageCount;
00317 
00318     cout << "image " << imageCount << " is at "
00319         << imagePositionsGrid[imageCount][0] << "x" << imagePositionsGrid[imageCount][1]
00320         << " ("
00321         << imagePositionsPixel[imageCount][0] << "," << imagePositionsPixel[imageCount][1]
00322         << ")" << endl;
00323   }
00324 }
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends