yuvcm.cpp

00001
00002 /**************************************************************************
00003  *  colormap.cpp - colormap
00004  *
00005  *  Created: Sat Mar 29 18:11:38 2008
00006  *  Copyright  2005-2008  Tim Niemueller  [www.niemueller.de]
00007  *
00008  ***************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023
00024 #include <fvutils/colormap/yuvcm.h>
00025
00026 #include <fvutils/colormap/cmfile.h>
00027 #include <fvutils/colormap/cmfile_yuvblock.h>
00028 #include <fvutils/ipc/shm_lut.h>
00029 #include <core/exceptions/software.h>
00030
00031 #include <cstdlib>
00032 #include <cstring>
00033
00034 using namespace fawkes;
00035 
00036 /** @class YuvColormap <fvutils/colormap/colormap.h>
00037  * YUV Colormap.
00038  * This class is the implementation of a 3D YUV colormap. The U/V planes are always
00039  * sampled in full. In general for colormaps we assume that in many cases the luminance
00040  * can be ignored completely. This allows for small datasets with speedy access and
00041  * sufficient discriminatory power. However, in some situations this is not enough.
00042  * In that case you can give a depth for the Y value. The Y axis is then separated
00043  * in the given number of ranges, each range is a stacked complete U/V plane.
00044  * Note, only depth values where depth = 2^n, n from natural numbers holds will provide
00045  * with equal ranges. Other values will lead to one bigger range, being the one with
00046  * the highest Y values which will be filled with the whole rest.
00047  *
00048  * You can see such a colormap as a colormap that consists of UV planes that represent
00049  * a certain Y range stacked on top of each other.
00050  *
00051  * @author Tim Niemueller
00052  */
00053 
00054 /** Constructor.
00055  * @param depth Y resolution depth
00056  * @param width U depth
00057  * @param height V depth
00058  */
00059 YuvColormap::YuvColormap(unsigned int depth, unsigned int width, unsigned int height)
00060 {
00061   constructor(depth, width, height);
00062 }
00063
00064 
00065 /** Constructor.
00066  * Creates a colormap in shared memory for the given LUT ID.
00067  * @param shmem_lut_id shared memory LUT ID
00068  * @param depth Y depth
00069  * @param width U depth
00070  * @param height V depth
00071  */
00072 YuvColormap::YuvColormap(const char *shmem_lut_id, unsigned int depth, unsigned int width, unsigned int height)
00073 {
00074   constructor(depth, width, height, shmem_lut_id);
00075 }
00076
00077 
00078 /** Constructor.
00079  * Creates a colormap in shared memory for the given LUT ID.
00080  * @param shmem_lut_id shared memory LUT ID
00081  * @param destroy_on_free true to delete the shared memory segment to delete, false to keep the segment
00082  * @param depth Y depth
00083  * @param width U depth
00084  * @param height V depth
00085  */
00086 YuvColormap::YuvColormap(const char *shmem_lut_id, bool destroy_on_free, unsigned int depth, unsigned int width, unsigned int height)
00087 {
00088   constructor(depth, width, height, shmem_lut_id, destroy_on_free);
00089 }
00090
00091 
00092 /** Constructor.
00093  * Creates a colormap in shared memory for the given LUT ID and copies the data of the
00094  * given existing colormap.
00095  * @param cm existing colormap to copy data from
00096  * @param shmem_lut_id shared memory LUT ID
00097  * @param destroy_on_free true to delete the shared memory segment to delete, false to keep the segment
00098  */
00099 YuvColormap::YuvColormap(YuvColormap *cm, const char *shmem_lut_id, bool destroy_on_free)
00100 {
00101   constructor(cm->depth(), cm->width(), cm->height(), shmem_lut_id, destroy_on_free);
00102   memcpy(__lut, cm->__lut, __lut_size);
00103 }
00104
00105 
00106 /** Internal constructor.
00107  * @param shmem_lut_id shared memory LUT ID
00108  * @param destroy_on_free true to delete the shared memory segment to delete, false to keep the segment
00109  * @param depth Y depth
00110  * @param width U depth
00111  * @param height V depth
00112  */
00113 void
00114 YuvColormap::constructor(unsigned int depth, unsigned int width, unsigned int height,
00115                          const char *shmem_lut_id, bool destroy_on_free)
00116 {
00117   if ( depth > 256 ) {
00118     throw OutOfBoundsException("YuvColormap depth out of bounds", depth, 1, 256);
00119   }
00120   if ( (depth != 1) && (depth != 2) && (depth != 4) && (depth != 8) && (depth != 16) &&
00121        (depth != 32) && (depth != 64) && (depth != 128) && (depth != 256) ) {
00122     throw IllegalArgumentException("Depth must be of the form d=2^n with n from [1,8]");
00123   }
00124
00125   if ( width > 256 ) {
00126     throw OutOfBoundsException("YuvColormap width out of bounds", width, 1, 256);
00127   }
00128   if ( (width != 1) && (width != 2) && (width != 4) && (width != 8) && (width != 16) &&
00129        (width != 32) && (width != 64) && (width != 128) && (width != 256) ) {
00130     throw IllegalArgumentException("Width must be of the form d=2^n with n from [1,8]");
00131   }
00132
00133   if ( height > 256 ) {
00134     throw OutOfBoundsException("YuvColormap height out of bounds", height, 1, 256);
00135   }
00136   if ( (height != 1) && (height != 2) && (height != 4) && (height != 8) && (height != 16) &&
00137        (height != 32) && (height != 64) && (height != 128) && (height != 256) ) {
00138     throw IllegalArgumentException("Height must be of the form d=2^n with n from [1,8]");
00139   }
00140
00141   __width  = width;
00142   __height = height;
00143   __depth  = depth;
00144   __depth_div  = 256 / __depth;
00145   __width_div  = 256 / __width;
00146   __height_div  = 256 / __height;
00147   __plane_size = __width * __height;
00148
00149   if ( shmem_lut_id != NULL ) {
00150     __shm_lut  = new SharedMemoryLookupTable(shmem_lut_id, __width, __height, __depth, /* bytes p. cell */ 1);
00151     __shm_lut->set_destroy_on_delete( destroy_on_free );
00152     __lut      = __shm_lut->buffer();
00153     __lut_size = __shm_lut->data_size();
00154   } else {
00155     __shm_lut = NULL;
00156     __lut_size = __width * __height * __depth;
00157     __lut = (unsigned char *)malloc( __lut_size );
00158   }
00159   memset(__lut, C_OTHER, __lut_size);
00160 }
00161
00162 
00163 /** Destructor. */
00164 YuvColormap::~YuvColormap()
00165 {
00166   if ( __shm_lut ) {
00167     delete __shm_lut;
00168   } else {
00169     free(__lut);
00170   }
00171   __lut = NULL;
00172   __lut_size = 0;
00173 }
00174
00175
00176 void
00177 YuvColormap::set(unsigned int y, unsigned int u, unsigned int v, color_t c)
00178 {
00179   *(__lut + (y / __depth_div) * __plane_size + (v / __height_div) * __width + (u / __width_div)) = c;
00180 }
00181
00182
00183 void
00184 YuvColormap::reset()
00185 {
00186   memset(__lut, C_OTHER, __lut_size);
00187 }
00188
00189
00190 void
00191 YuvColormap::set(unsigned char *buffer)
00192 {
00193   memcpy(__lut, buffer, __lut_size);
00194 }
00195
00196
00197 size_t
00198 YuvColormap::size()
00199 {
00200   return __lut_size;
00201 }
00202
00203
00204 std::list<ColormapFileBlock *>
00205 YuvColormap::get_blocks()
00206 {
00207   std::list<ColormapFileBlock *> rv;
00208
00209   for (unsigned int i = 0; i < __depth; ++i) {
00210     ColormapFileYuvBlock *yuvb = new ColormapFileYuvBlock(this, i);
00211     rv.push_back(yuvb);
00212   }
00213
00214   return rv;
00215 }
00216
00217
00218 unsigned char *
00219 YuvColormap::get_buffer() const
00220 {
00221   return __lut;
00222 }
00223
00224 
00225 /** Copy single U/V plane.
00226  * This will copy the given U/V plane to the given level in this colormap.
00227  * @param uvplane buffer of U/V plane to copy
00228  * @param level level to copy the plane to
00229  * @exception OutOfBoundsException thrown if level > depth()
00230  */
00231 void
00232 YuvColormap::copy_uvplane(unsigned char *uvplane, unsigned int level)
00233 {
00234   if ( level > __depth ) {
00235     throw OutOfBoundsException("YuvColormap::copy_uvplane(): Invalid level", level, 0, __depth);
00236   }
00237
00238   memcpy(__lut + level * __plane_size, uvplane, __plane_size);
00239 }
00240
00241
00242 Colormap &
00243 YuvColormap::operator+=(const Colormap & cmlt)
00244 {
00245   const YuvColormap *tc = dynamic_cast<const YuvColormap *>(&cmlt);
00246   if ( tc == NULL ) {
00247     throw TypeMismatchException("Only YUV colormaps can be added to a YUV colormap");
00248   }
00249
00250   if ( (__width != tc->__width) || (__height != tc->__height) || (__depth != tc->__depth) ) {
00251     throw TypeMismatchException("YuvColormaps are of different sizes");
00252   }
00253
00254   unsigned char *this_lut = __lut;
00255   unsigned char *other_lut = tc->__lut;
00256
00257   for (unsigned int i = 0; i < __plane_size * __depth; ++i) {
00258     if ( (*this_lut == C_OTHER) || (*this_lut == C_BACKGROUND) ) {
00259       // can be overridden
00260       if ( (*other_lut != C_OTHER) && (*other_lut != C_BACKGROUND) ) {
00261         // there is something that is worth overriding this value
00262         *this_lut = *other_lut;
00263       }
00264     }
00265     ++this_lut;
00266     ++other_lut;
00267   }
00268
00269   return *this;
00270 }
00271
00272 
00273 /** Assign operation.
00274  * Copies all values from the given colormap.
00275  * @param yuvcm colormap which's data to copy to this instance
00276  * @exception TypeMismatchException thrown if depth of colormaps does not match.
00277  * @return reference to this
00278  */
00279 Colormap &
00280 YuvColormap::operator=(const YuvColormap & yuvcm)
00281 {
00282   if ( __depth != yuvcm.__depth ) {
00283     throw TypeMismatchException("Depth of colormaps does not match");
00284   }
00285
00286   memcpy(__lut, yuvcm.__lut, __lut_size);
00287
00288   return *this;
00289 }
00290
00291
00292 Colormap &
00293 YuvColormap::operator+=(const char *filename)
00294 {
00295   ColormapFile cmf;
00296   cmf.read(filename);
00297   Colormap *tcm = cmf.get_colormap();
00298   YuvColormap *tycm = dynamic_cast<YuvColormap *>(tcm);
00299   if ( ! tycm ) {
00300     delete tcm;
00301     throw TypeMismatchException("File does not contain a YUV colormap");
00302   }
00303   *this += *tycm;
00304   delete tcm;
00305   return *this;
00306 }
00307
00308
00309 unsigned int
00310 YuvColormap::width() const
00311 {
00312   return __width;
00313 }
00314
00315
00316 unsigned int
00317 YuvColormap::height() const
00318 {
00319   return __height;
00320 }
00321
00322
00323 unsigned int
00324 YuvColormap::depth() const
00325 {
00326   return __depth;
00327 }
00328
00329
00330 unsigned int
00331 YuvColormap::deepness() const
00332 {
00333   return 256;
00334 }
00335
00336 
00337 /** Get U/V plane size.
00338  * @return size of a single U/V plane
00339  */
00340 unsigned int
00341 YuvColormap::plane_size() const
00342 {
00343   return __plane_size;
00344 }