Fawkes API  Fawkes Development Version
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 namespace firevision {
00037 #if 0 /* just to make Emacs auto-indent happy */
00038 }
00039 #endif
00040 
00041 /** @class YuvColormap <fvutils/colormap/colormap.h>
00042  * YUV Colormap.
00043  * This class is the implementation of a 3D YUV colormap. The U/V planes are always
00044  * sampled in full. In general for colormaps we assume that in many cases the luminance
00045  * can be ignored completely. This allows for small datasets with speedy access and
00046  * sufficient discriminatory power. However, in some situations this is not enough.
00047  * In that case you can give a depth for the Y value. The Y axis is then separated
00048  * in the given number of ranges, each range is a stacked complete U/V plane.
00049  * Note, only depth values where depth = 2^n, n from natural numbers holds will provide
00050  * with equal ranges. Other values will lead to one bigger range, being the one with
00051  * the highest Y values which will be filled with the whole rest.
00052  *
00053  * You can see such a colormap as a colormap that consists of UV planes that represent
00054  * a certain Y range stacked on top of each other.
00055  *
00056  * @author Tim Niemueller
00057  */
00058 
00059 /** Constructor.
00060  * @param depth Y resolution depth
00061  * @param width U depth
00062  * @param height V depth
00063  */
00064 YuvColormap::YuvColormap(unsigned int depth, unsigned int width, unsigned int height)
00065 {
00066   constructor(depth, width, height);
00067 }
00068 
00069 
00070 /** Constructor.
00071  * Creates a colormap in shared memory for the given LUT ID.
00072  * @param shmem_lut_id shared memory LUT ID
00073  * @param depth Y depth
00074  * @param width U depth
00075  * @param height V depth
00076  */
00077 YuvColormap::YuvColormap(const char *shmem_lut_id, unsigned int depth, unsigned int width, unsigned int height)
00078 {
00079   constructor(depth, width, height, shmem_lut_id);
00080 }
00081 
00082 
00083 /** Constructor.
00084  * Creates a colormap in shared memory for the given LUT ID.
00085  * @param shmem_lut_id shared memory LUT ID
00086  * @param destroy_on_free true to delete the shared memory segment to delete, false to keep the segment
00087  * @param depth Y depth
00088  * @param width U depth
00089  * @param height V depth
00090  */
00091 YuvColormap::YuvColormap(const char *shmem_lut_id, bool destroy_on_free, unsigned int depth, unsigned int width, unsigned int height)
00092 {
00093   constructor(depth, width, height, shmem_lut_id, destroy_on_free);
00094 }
00095 
00096 
00097 /** Constructor.
00098  * Creates a colormap in shared memory for the given LUT ID and copies the data of the
00099  * given existing colormap.
00100  * @param cm existing colormap to copy data from
00101  * @param shmem_lut_id shared memory LUT ID
00102  * @param destroy_on_free true to delete the shared memory segment to delete, false to keep the segment
00103  */
00104 YuvColormap::YuvColormap(YuvColormap *cm, const char *shmem_lut_id, bool destroy_on_free)
00105 {
00106   constructor(cm->depth(), cm->width(), cm->height(), shmem_lut_id, destroy_on_free);
00107   memcpy(__lut, cm->__lut, __lut_size);
00108 }
00109 
00110 
00111 /** Internal constructor.
00112  * @param shmem_lut_id shared memory LUT ID
00113  * @param destroy_on_free true to delete the shared memory segment to delete, false to keep the segment
00114  * @param depth Y depth
00115  * @param width U depth
00116  * @param height V depth
00117  */
00118 void
00119 YuvColormap::constructor(unsigned int depth, unsigned int width, unsigned int height,
00120                          const char *shmem_lut_id, bool destroy_on_free)
00121 {
00122   if ( depth > 256 ) {
00123     throw OutOfBoundsException("YuvColormap depth out of bounds", depth, 1, 256);
00124   }
00125   if ( (depth != 1) && (depth != 2) && (depth != 4) && (depth != 8) && (depth != 16) &&
00126        (depth != 32) && (depth != 64) && (depth != 128) && (depth != 256) ) {
00127     throw IllegalArgumentException("Depth must be of the form d=2^n with n from [1,8]");
00128   }
00129 
00130   if ( width > 256 ) {
00131     throw OutOfBoundsException("YuvColormap width out of bounds", width, 1, 256);
00132   }
00133   if ( (width != 1) && (width != 2) && (width != 4) && (width != 8) && (width != 16) &&
00134        (width != 32) && (width != 64) && (width != 128) && (width != 256) ) {
00135     throw IllegalArgumentException("Width must be of the form d=2^n with n from [1,8]");
00136   }
00137 
00138   if ( height > 256 ) {
00139     throw OutOfBoundsException("YuvColormap height out of bounds", height, 1, 256);
00140   }
00141   if ( (height != 1) && (height != 2) && (height != 4) && (height != 8) && (height != 16) &&
00142        (height != 32) && (height != 64) && (height != 128) && (height != 256) ) {
00143     throw IllegalArgumentException("Height must be of the form d=2^n with n from [1,8]");
00144   }
00145 
00146   __width  = width;
00147   __height = height;
00148   __depth  = depth;
00149   __depth_div  = 256 / __depth;
00150   __width_div  = 256 / __width;
00151   __height_div  = 256 / __height;
00152   __plane_size = __width * __height;
00153 
00154   if ( shmem_lut_id != NULL ) {
00155     __shm_lut  = new SharedMemoryLookupTable(shmem_lut_id, __width, __height, __depth, /* bytes p. cell */ 1);
00156     __shm_lut->set_destroy_on_delete( destroy_on_free );
00157     __lut      = __shm_lut->buffer();
00158     __lut_size = __shm_lut->data_size();
00159   } else {
00160     __shm_lut = NULL;
00161     __lut_size = __width * __height * __depth;
00162     __lut = (unsigned char *)malloc( __lut_size );
00163   }
00164   memset(__lut, C_OTHER, __lut_size);
00165 }
00166 
00167 
00168 /** Destructor. */
00169 YuvColormap::~YuvColormap()
00170 {
00171   if ( __shm_lut ) {
00172     delete __shm_lut;
00173   } else {
00174     free(__lut);
00175   }
00176   __lut = NULL;
00177   __lut_size = 0;
00178 }
00179 
00180 
00181 void
00182 YuvColormap::set(unsigned int y, unsigned int u, unsigned int v, color_t c)
00183 {
00184   *(__lut + (y / __depth_div) * __plane_size + (v / __height_div) * __width + (u / __width_div)) = c;
00185 }
00186 
00187 
00188 void
00189 YuvColormap::reset()
00190 {
00191   memset(__lut, C_OTHER, __lut_size);
00192 }
00193 
00194 
00195 void
00196 YuvColormap::set(unsigned char *buffer)
00197 {
00198   memcpy(__lut, buffer, __lut_size);
00199 }
00200 
00201 
00202 size_t
00203 YuvColormap::size()
00204 {
00205   return __lut_size;
00206 }
00207 
00208 
00209 std::list<ColormapFileBlock *>
00210 YuvColormap::get_blocks()
00211 {
00212   std::list<ColormapFileBlock *> rv;
00213 
00214   for (unsigned int i = 0; i < __depth; ++i) {
00215     ColormapFileYuvBlock *yuvb = new ColormapFileYuvBlock(this, i);
00216     rv.push_back(yuvb);
00217   }
00218 
00219   return rv;
00220 }
00221 
00222 
00223 unsigned char *
00224 YuvColormap::get_buffer() const
00225 {
00226   return __lut;
00227 }
00228 
00229 
00230 /** Copy single U/V plane.
00231  * This will copy the given U/V plane to the given level in this colormap.
00232  * @param uvplane buffer of U/V plane to copy
00233  * @param level level to copy the plane to
00234  * @exception OutOfBoundsException thrown if level > depth()
00235  */
00236 void
00237 YuvColormap::copy_uvplane(unsigned char *uvplane, unsigned int level)
00238 {
00239   if ( level > __depth ) {
00240     throw OutOfBoundsException("YuvColormap::copy_uvplane(): Invalid level", level, 0, __depth);
00241   }
00242 
00243   memcpy(__lut + level * __plane_size, uvplane, __plane_size);
00244 }
00245 
00246 
00247 /** Adds the given colormap to this colormap.
00248  * This operator takes the given colormap and compares it to this colormap. If
00249  * this colormap has C_OTHER or C_BACKGROUND the value is compied from the other
00250  * LUT, otherwise the value is kept as is.
00251  * @param cmlt other colormap to add
00252  * @return reference to this
00253  */
00254 Colormap &
00255 YuvColormap::operator+=(const Colormap & cmlt)
00256 {
00257   const YuvColormap *tc = dynamic_cast<const YuvColormap *>(&cmlt);
00258   if ( tc == NULL ) {
00259     throw TypeMismatchException("Only YUV colormaps can be added to a YUV colormap");
00260   }
00261 
00262   if ( (__width != tc->__width) || (__height != tc->__height) || (__depth != tc->__depth) ) {
00263     throw TypeMismatchException("YuvColormaps are of different sizes");
00264   }
00265 
00266   unsigned char *this_lut = __lut;
00267   unsigned char *other_lut = tc->__lut;
00268 
00269   for (unsigned int i = 0; i < __plane_size * __depth; ++i) {
00270     if ( (*this_lut == C_OTHER) || (*this_lut == C_BACKGROUND) ) {
00271       // can be overridden
00272       if ( (*other_lut != C_OTHER) && (*other_lut != C_BACKGROUND) ) {
00273         // there is something that is worth overriding this value
00274         *this_lut = *other_lut;
00275       }
00276     }
00277     ++this_lut;
00278     ++other_lut;
00279   }
00280 
00281   return *this;
00282 }
00283 
00284 
00285 /** Assign operation.
00286  * Copies all values from the given colormap.
00287  * @param yuvcm colormap which's data to copy to this instance
00288  * @exception TypeMismatchException thrown if depth of colormaps does not match.
00289  * @return reference to this
00290  */
00291 Colormap &
00292 YuvColormap::operator=(const YuvColormap & yuvcm)
00293 {
00294   if ( __depth != yuvcm.__depth ) {
00295     throw TypeMismatchException("Depth of colormaps does not match");
00296   }
00297 
00298   memcpy(__lut, yuvcm.__lut, __lut_size);
00299 
00300   return *this;
00301 }
00302 
00303 
00304 Colormap &
00305 YuvColormap::operator+=(const char *filename)
00306 {
00307   ColormapFile cmf;
00308   cmf.read(filename);
00309   Colormap *tcm = cmf.get_colormap();
00310   YuvColormap *tycm = dynamic_cast<YuvColormap *>(tcm);
00311   if ( ! tycm ) {
00312     delete tcm;
00313     throw TypeMismatchException("File does not contain a YUV colormap");
00314   }
00315   *this += *tycm;
00316   delete tcm;
00317   return *this;
00318 }
00319 
00320 
00321 unsigned int
00322 YuvColormap::width() const
00323 {
00324   return __width;
00325 }
00326 
00327 
00328 unsigned int
00329 YuvColormap::height() const
00330 {
00331   return __height;
00332 }
00333 
00334 
00335 unsigned int
00336 YuvColormap::depth() const
00337 {
00338   return __depth;
00339 }
00340 
00341 
00342 unsigned int
00343 YuvColormap::deepness() const
00344 {
00345   return 256;
00346 }
00347 
00348 
00349 /** Get U/V plane size.
00350  * @return size of a single U/V plane
00351  */
00352 unsigned int
00353 YuvColormap::plane_size() const
00354 {
00355   return __plane_size;
00356 }
00357 
00358 } // end namespace firevision