lossy.cpp

00001
00002 /***************************************************************************
00003  *  lossy.cpp - lossy scaler
00004  *
00005  *  Generated: Tue May 16 14:59:30 2006 (Automatica 2006)
00006  *  Copyright  2005-2007  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
00025 #include <fvutils/scalers/lossy.h>
00026 #include <fvutils/color/yuv.h>
00027
00028 #include <cmath>
00029 #include <cstring>
00030 
00031 /** @class LossyScaler <fvutils/scalers/lossy.h>
00032  * Lossy image scaler.
00033  * This scaler just takes the required pixels from the image and throws away
00034  * the rest. No enhancement of the image is done.
00035  * This is only suitable for downscaling. The scale factor must be between
00036  * 0 and 1.
00037  */
00038 
00039 /** Constructor. */
00040 LossyScaler::LossyScaler()
00041 {
00042   orig_width = orig_height = 0;
00043   scal_width = scal_height = 0;
00044   orig_buffer = NULL;
00045   scal_buffer = NULL;
00046
00047   scale_factor = 1.f;
00048 }
00049
00050 
00051 /** Destructor. */
00052 LossyScaler::~LossyScaler()
00053 {
00054 }
00055
00056
00057 void
00058 LossyScaler::set_scale_factor(float factor)
00059 {
00060   if ( (factor <= 0) || (factor > 1) ) {
00061     scale_factor = 1.f;
00062   } else {
00063     scale_factor = factor;
00064   }
00065
00066   if (orig_width != 0) {
00067     scal_width = (unsigned int) ceil(orig_width * scale_factor);
00068     scal_width += (scal_width % 2);
00069   }
00070   if (orig_height != 0) {
00071     scal_height = (unsigned int) ceil(orig_height * scale_factor);
00072     scal_height += (scal_width % 2);
00073   }
00074 }
00075
00076
00077 void
00078 LossyScaler::set_original_dimensions(unsigned int width,
00079                                      unsigned int height)
00080 {
00081   orig_width  = width;
00082   orig_height = height;
00083 }
00084
00085
00086 void
00087 LossyScaler::set_scaled_dimensions(unsigned int width,
00088                                    unsigned int height)
00089 {
00090   scal_width  = width;
00091   scal_height = height;
00092
00093   float scale_factor_width  = 1.0;
00094   float scale_factor_height = 1.0;
00095
00096   if (orig_width != 0) {
00097     scale_factor_width = scal_width / float(orig_width);
00098   }
00099   if (orig_height != 0) {
00100     scale_factor_height = scal_height / float(orig_height);
00101   }
00102
00103   scale_factor = (scale_factor_width < scale_factor_height) ? scale_factor_width : scale_factor_height;
00104
00105   scal_width  = (unsigned int) floor(orig_width * scale_factor);
00106   scal_height = (unsigned int) floor(orig_height * scale_factor);
00107
00108   scal_width  += (scal_width % 2);
00109   scal_height += (scal_height % 2);
00110 }
00111
00112
00113 void
00114 LossyScaler::set_original_buffer(unsigned char *buffer)
00115 {
00116   orig_buffer = buffer;
00117 }
00118
00119
00120 void
00121 LossyScaler::set_scaled_buffer(unsigned char *buffer)
00122 {
00123   scal_buffer = buffer;
00124 }
00125
00126
00127 unsigned int
00128 LossyScaler::needed_scaled_width()
00129 {
00130   return scal_width;
00131 }
00132
00133
00134 unsigned int
00135 LossyScaler::needed_scaled_height()
00136 {
00137   return scal_height;
00138 }
00139
00140
00141 float
00142 LossyScaler::get_scale_factor()
00143 {
00144   return scale_factor;
00145 }
00146
00147 void
00148 LossyScaler::scale()
00149 {
00150   if ( orig_width  == 0 ) return;
00151   if ( orig_height == 0 ) return;
00152   if ( scal_width  == 0 ) return;
00153   if ( scal_height == 0 ) return;
00154   if ( orig_buffer == NULL ) return;
00155   if ( scal_buffer == NULL ) return;
00156   if ( scal_width < needed_scaled_width() ) return;
00157   if ( scal_height < needed_scaled_height() ) return;
00158
00159   float skip = 1 / scale_factor;
00160   unsigned char *oyp = orig_buffer;
00161   unsigned char *oup = YUV422_PLANAR_U_PLANE( orig_buffer, orig_width, orig_height );
00162   unsigned char *ovp = YUV422_PLANAR_V_PLANE( orig_buffer, orig_width, orig_height );
00163
00164   unsigned char *syp = scal_buffer;
00165   unsigned char *sup = YUV422_PLANAR_U_PLANE( scal_buffer, scal_width, scal_height );
00166   unsigned char *svp = YUV422_PLANAR_V_PLANE( scal_buffer, scal_width, scal_height );
00167
00168   memset( syp,   0, scal_width * scal_height );
00169   memset( sup, 128, scal_width * scal_height );
00170
00171   float oh_float = 0.0;
00172   float ow_float = 0.0;
00173
00174   unsigned int oh_pixel;
00175   unsigned int ow_pixel;
00176   unsigned int ow_pixel_next;
00177
00178   for (unsigned int h = 0; h < scal_height; ++h) {
00179     oh_pixel = (unsigned int) rint(oh_float);
00180     ow_float = 0.0;
00181
00182     if (oh_pixel >= orig_height) {
00183       oh_pixel = orig_height - 1;
00184     }
00185     for (unsigned int w = 0; w < scal_width; w += 2) {
00186       ow_pixel = (unsigned int) rint(ow_float);
00187       ow_pixel_next = (unsigned int) rint( ow_float + skip);
00188
00189       if (ow_pixel >= orig_width) {
00190         ow_pixel = orig_width - 1;
00191       }
00192
00193       if (ow_pixel_next >= orig_width) {
00194         ow_pixel_next = orig_width - 1;
00195       }
00196
00197       syp[ h * scal_width + w ] = oyp[ oh_pixel * orig_width + ow_pixel ];
00198       syp[ h * scal_width + w + 1 ] = oyp[ oh_pixel * orig_width + ow_pixel_next ];
00199       sup[ (h * scal_width + w) / 2 ] = (oup[ (oh_pixel * orig_width + ow_pixel) / 2 ] + oup[ (oh_pixel * orig_width + ow_pixel_next) / 2 ]) / 2;
00200       svp[ (h * scal_width + w) / 2 ] = (ovp[ (oh_pixel * orig_width + ow_pixel) / 2 ] + ovp[ (oh_pixel * orig_width + ow_pixel_next) / 2 ]) / 2;
00201
00202       ow_float += 2 * skip;
00203     }
00204     oh_float += skip;
00205   }
00206 }