00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <assert.h>
00012 #include <string.h>
00013
00014 #include "OSGImageScaler.h"
00015
00016 OSG_USING_NAMESPACE
00017
00018
00019 #define OSG_FILTER_PI OSG::Real64 (3.1415926535897932384626433832795)
00020 #define OSG_FILTER_2PI OSG::Real64 (2.0 * 3.1415926535897932384626433832795)
00021 #define OSG_FILTER_4PI OSG::Real64 (4.0 * 3.1415926535897932384626433832795)
00022
00023
00024
00025
00026
00027 using namespace osg;
00028 using namespace std;
00029
00030
00031
00032 ImageGenericFilter::ImageGenericFilter(Real64 dWidth) :
00033 m_dWidth(dWidth)
00034 {
00035 }
00036
00037 ImageGenericFilter::~ImageGenericFilter(void)
00038 {
00039 }
00040
00041 Real64 ImageGenericFilter::getWidth(void) const
00042 {
00043 return m_dWidth;
00044 }
00045
00046 void ImageGenericFilter::setWidth(Real64 dWidth)
00047 {
00048 m_dWidth = dWidth;
00049 }
00050
00051
00052
00053 ImageBoxFilter::ImageBoxFilter(Real64 dWidth) :
00054 ImageGenericFilter(dWidth)
00055 {
00056 }
00057
00058 ImageBoxFilter::~ImageBoxFilter(void)
00059 {
00060 }
00061
00062 Real64 ImageBoxFilter::filter (Real64 dVal) const
00063 {
00064 return (fabs(dVal) <= m_dWidth ? 1.0 : 0.0);
00065 }
00066
00067
00068
00069 ImageLinearFilter::ImageLinearFilter(Real64 dWidth) :
00070 ImageGenericFilter(dWidth)
00071 {
00072 }
00073
00074 ImageLinearFilter::~ImageLinearFilter(void)
00075 {
00076 }
00077
00078 Real64 ImageLinearFilter::filter(Real64 dVal) const
00079 {
00080 dVal = fabs(dVal);
00081 return (dVal < m_dWidth ? m_dWidth - dVal : 0.0);
00082 }
00083
00084
00085
00086 ImageGaussianFilter::ImageGaussianFilter (Real64 dWidth) :
00087 ImageGenericFilter(dWidth)
00088 {
00089 }
00090
00091 ImageGaussianFilter::~ImageGaussianFilter(void)
00092 {
00093 }
00094
00095 Real64 ImageGaussianFilter::filter(Real64 dVal) const
00096 {
00097 if (fabs (dVal) > m_dWidth)
00098 return 0.0;
00099
00100 return exp (-dVal * dVal / 2.0) / sqrt (OSG_FILTER_2PI);
00101 }
00102
00103
00104
00105 ImageHammingFilter::ImageHammingFilter(Real64 dWidth) :
00106 ImageGenericFilter(dWidth)
00107 {
00108 }
00109
00110 ImageHammingFilter::~ImageHammingFilter(void)
00111 {
00112 }
00113
00114 Real64 ImageHammingFilter::filter(Real64 dVal) const
00115 {
00116 if (fabs (dVal) > m_dWidth)
00117 return 0.0;
00118
00119 Real64 dWindow = 0.54 + 0.46 * cos (OSG_FILTER_2PI * dVal);
00120 Real64 dSinc = (dVal == 0) ? 1.0 : sin (OSG_FILTER_PI * dVal) / (OSG_FILTER_PI * dVal);
00121 return dWindow * dSinc;
00122 }
00123
00124
00125
00126 ImageBlackmanFilter::ImageBlackmanFilter (Real64 dWidth) :
00127 ImageGenericFilter(dWidth)
00128 {
00129 }
00130
00131 ImageBlackmanFilter::~ImageBlackmanFilter(void)
00132 {
00133 }
00134
00135 Real64 ImageBlackmanFilter::filter(Real64 dVal) const
00136 {
00137 if (fabs (dVal) > m_dWidth)
00138 return 0.0;
00139
00140 Real64 dN = 2.0 * m_dWidth + 1.0;
00141 return 0.42 + 0.5 * cos (OSG_FILTER_2PI * dVal / ( dN - 1.0 )) +
00142 0.08 * cos (OSG_FILTER_4PI * dVal / ( dN - 1.0 ));
00143 }
00144
00145
00146
00147 ImageLanczos3Filter::ImageLanczos3Filter(Real64 dWidth) :
00148 ImageGenericFilter(dWidth)
00149 {
00150 }
00151
00152 ImageLanczos3Filter::~ImageLanczos3Filter(void)
00153 {
00154 }
00155
00156 Real64 ImageLanczos3Filter::sinc(Real64 x) const
00157 {
00158 x *= OSG_FILTER_PI;
00159 if(x != 0.0)
00160 return(sin(x) / x);
00161 return 1.0;
00162 }
00163
00164 Real64 ImageLanczos3Filter::filter(Real64 dVal) const
00165 {
00166 if(dVal < 0)
00167 dVal = -dVal;
00168 if(dVal < 3.0)
00169 return(sinc(dVal) * sinc(dVal / 3.0));
00170 return 0.0;
00171 }
00172
00173
00175
00176
00177 struct ValueHandler
00178 {
00179 virtual Real64 getValue(const UInt8 *data,
00180 UInt32 channels,
00181 UInt32 width,UInt32 height,
00182 UInt32 c,
00183 UInt32 x1,UInt32 y1,UInt32 z1,
00184 UInt32 x2,UInt32 y2,UInt32 z2,
00185 Real64 *weightX,
00186 Real64 *weightY,
00187 Real64 *weightZ)=0;
00188 virtual void setValue(Real64 value,UInt8 *data,
00189 UInt32 channels,UInt32 width,UInt32 height,
00190 UInt32 c,UInt32 x,UInt32 y,UInt32 z)=0;
00191
00192 virtual ~ValueHandler(void) {}
00193 };
00194
00195 template <class ValueT>
00196 struct ValueHandlerTempl : public ValueHandler
00197 {
00198 virtual Real64 getValue(const UInt8 *data,
00199 UInt32 channels,
00200 UInt32 width,UInt32 height,
00201 UInt32 c,
00202 UInt32 x1,UInt32 y1,UInt32 z1,
00203 UInt32 x2,UInt32 y2,UInt32 z2,
00204 Real64 *weightX,
00205 Real64 *weightY,
00206 Real64 *weightZ)
00207 {
00208 Real64 result = 0;
00209 UInt32 x,y,z;
00210
00211 for(z = 0 ; z <= (z2-z1) ; ++z)
00212 {
00213 for(y = 0 ; y <= (y2-y1) ; ++y)
00214 {
00215 const ValueT *valueP = reinterpret_cast<const ValueT*>(data) +
00216 (z1 + z) * (height*width*channels) +
00217 (y1 + y) * (width*channels) +
00218 (x1) * (channels) + c;
00219 for(x = 0 ; x <= (x2-x1) ; ++x)
00220 {
00221 result += Real64(*(valueP)) *
00222 (weightX[x] * weightY[y] * weightZ[z]);
00223 valueP += channels;
00224 }
00225 }
00226 }
00227 return result;
00228 }
00229 virtual void setValue(Real64 value,UInt8 *data,
00230 UInt32 channels,UInt32 width,UInt32 height,
00231 UInt32 c,UInt32 x,UInt32 y,UInt32 z)
00232 {
00233
00234 Real64 maxValue = Real64(TypeTraits<ValueT>::getMax());
00235 if(value > maxValue)
00236 {
00237 value = maxValue;
00238 }
00239 else
00240 {
00241 if(value < 0.0)
00242 value = 0.0;
00243 }
00244
00245 ValueT *valueP = reinterpret_cast<ValueT *>(data);
00246 valueP = valueP +
00247 z * (width*height*channels) +
00248 y * (width*channels) +
00249 x * (channels) +
00250 c;
00251
00252 *valueP = ValueT(value);
00253 }
00254 };
00255
00256
00258
00259 ImageScaler::ImageScaler(void)
00260 {
00261 }
00262
00263
00265
00266 ImageScaler::~ImageScaler(void)
00267 {
00268 }
00269
00270
00272
00273 void ImageScaler::calcContributions(UInt32 axis,
00274 Int32 uResSize,
00275 Int32 uSrcSize,
00276 const ImageGenericFilter &filter,
00277 std::vector<Contribution> contrib[3])
00278 {
00279 Real64 dWidth;
00280 Real64 dFScale = 1.0;
00281 Real64 dFilterWidth = filter.getWidth();
00282
00283 Real64 dScale = Real64(uResSize) / Real64(uSrcSize);
00284
00285
00286 contrib[axis].resize(uResSize);
00287
00288 if (dScale < 1.0)
00289 {
00290 dWidth = dFilterWidth / dScale;
00291 dFScale = dScale;
00292 }
00293 else
00294 {
00295 dWidth= dFilterWidth;
00296 }
00297
00298
00299 Int32 iWindowSize = 2 * Int32(ceil(dWidth)) + 1;
00300
00301 for (Int32 u = 0; u < uResSize; u++)
00302 {
00303
00304 Real64 dCenter = Real64(u) / dScale;
00305
00306 Int32 iLeft = osgMax (0, Int32(floor (dCenter - dWidth)));
00307
00308 Int32 iRight = osgMin (Int32(ceil(dCenter + dWidth)), Int32(uSrcSize) - 1);
00309
00310
00311
00312 if (iRight - iLeft + 1 > iWindowSize)
00313 {
00314 if (iLeft < (Int32(uSrcSize) - 1 / 2))
00315 {
00316 iLeft++;
00317 }
00318 else
00319 {
00320 iRight--;
00321 }
00322 }
00323
00324 contrib[axis][u].left = iLeft;
00325 contrib[axis][u].right = iRight;
00326
00327 Real64 dTotalWeight = 0.0;
00328 contrib[axis][u].weights.resize(iRight - iLeft + 1);
00329 for (Int32 iSrc = iLeft; iSrc <= iRight; iSrc++)
00330 {
00331
00332 Real64 weight = dFScale *
00333 filter.filter(dFScale * (dCenter - Real64(iSrc)));
00334 contrib[axis][u].weights[iSrc-iLeft] = weight;
00335
00336 dTotalWeight += weight;
00337 }
00338 if (dTotalWeight > 0.0)
00339 {
00340
00341 for (Int32 iSrc = iLeft; iSrc <= iRight; iSrc++)
00342 {
00343
00344 contrib[axis][u].weights[iSrc-iLeft] /= dTotalWeight;
00345 }
00346
00347 while(contrib[axis][u].weights.front() == 0)
00348 {
00349 contrib[axis][u].left++;
00350 contrib[axis][u].weights.erase(contrib[axis][u].weights.begin());
00351 }
00352 while(contrib[axis][u].weights.back() == 0)
00353 {
00354 contrib[axis][u].right--;
00355 contrib[axis][u].weights.erase(contrib[axis][u].weights.end() - 1);
00356 }
00357 #if 0
00358 printf("%d %d %d,%d\n",axis,u,contrib[axis][u].left,contrib[axis][u].right);
00359 for (Int32 iSrc = 0; iSrc < contrib[axis][u].weights.size(); iSrc++)
00360 {
00361 printf("%lf ",contrib[axis][u].weights[iSrc]);
00362 }
00363 printf("\n");
00364 #endif
00365 }
00366 }
00367 }
00368
00369
00371
00372 bool ImageScaler::scale(ImagePtr &srcImg,
00373 ImagePtr &dstImg,
00374 Int32 width,
00375 Int32 height,
00376 Int32 depth,
00377 const ImageGenericFilter &filter)
00378 {
00379 ValueHandler *valueHandler = NULL;
00380 Int32 channels = srcImg->getComponents();
00381 std::vector<Contribution> contrib[3];
00382
00383 beginEditCP(dstImg);
00384
00385 switch(srcImg->getDataType())
00386 {
00387 case Image::OSG_UINT8_IMAGEDATA:
00388 valueHandler = new ValueHandlerTempl<UInt8>();
00389 break;
00390 case Image::OSG_UINT16_IMAGEDATA:
00391 valueHandler = new ValueHandlerTempl<UInt16>();
00392 break;
00393 case Image::OSG_UINT32_IMAGEDATA:
00394 valueHandler = new ValueHandlerTempl<UInt32>();
00395 break;
00396 case Image::OSG_FLOAT16_IMAGEDATA:
00397 valueHandler = new ValueHandlerTempl<Real16>();
00398 break;
00399 case Image::OSG_FLOAT32_IMAGEDATA:
00400 valueHandler = new ValueHandlerTempl<Real32>();
00401 break;
00402 default:
00403 SWARNING << "PixelType not scalable" << std::endl;
00404 return false;
00405 };
00406
00407
00408 calcContributions(0,width, srcImg->getWidth() ,filter,contrib);
00409 calcContributions(1,height,srcImg->getHeight(),filter,contrib);
00410 calcContributions(2,depth, srcImg->getDepth() ,filter,contrib);
00411
00412 if(!dstImg->set(static_cast<Image::PixelFormat>(srcImg->getPixelFormat()),
00413 width,
00414 height,
00415 depth,
00416
00417 1,
00418 srcImg->getFrameCount(),
00419 srcImg->getFrameDelay(),
00420 NULL,
00421 srcImg->getDataType(),
00422 true,
00423 srcImg->getSideCount()))
00424 {
00425 SWARNING << "Unable to set image format" << std::endl;
00426 return false;
00427 }
00428
00429 UInt32 srcImgWidth = srcImg->getWidth();
00430 UInt32 srcImgHeight = srcImg->getHeight();
00431 Real64 *weightX;
00432 Real64 *weightY;
00433 Real64 *weightZ;
00434 UInt32 frames = srcImg->getFrameCount();
00435 UInt32 sides = srcImg->getSideCount();
00436
00437
00438
00439
00440 Real64 value;
00441 UInt32 x,y,z,c,f,s;
00442 UInt32 x1,x2,y1,y2,z1,z2;
00443 for(s = 0 ; s < sides ; ++s)
00444 {
00445 for(f = 0 ; f < frames ; ++f)
00446 {
00447 UInt8 *dstImgData = dstImg->editData(0,f,s);
00448 const UInt8 *srcImgData = srcImg->getData(0,f,s);
00449 for(z = 0 ; z < depth ; ++z)
00450 {
00451 z1 = contrib[2][z].left;
00452 z2 = contrib[2][z].right;
00453 weightZ = &contrib[2][z].weights[0];
00454 for(y = 0 ; y < height ; ++y)
00455 {
00456 y1 = contrib[1][y].left;
00457 y2 = contrib[1][y].right;
00458 weightY = &contrib[1][y].weights[0];
00459 for(x = 0 ; x < width ; ++x)
00460 {
00461 x1 = contrib[0][x].left;
00462 x2 = contrib[0][x].right;
00463
00464 weightX = &contrib[0][x].weights[0];
00465 for(c = 0 ; c < channels ; ++c)
00466 {
00467 value = valueHandler->getValue(srcImgData,
00468 channels,
00469 srcImgWidth,
00470 srcImgHeight,
00471 c,
00472 x1,y1,z1,
00473 x2,y2,z2,
00474 weightX,weightY,weightZ);
00475
00476 valueHandler->setValue(value,
00477 dstImgData,
00478 channels,width,height,
00479 c,x,y,z);
00480 }
00481 }
00482 }
00483 }
00484 }
00485 }
00486
00487 if(valueHandler != NULL)
00488 delete valueHandler;
00489
00490
00491 if(srcImg->getMipMapCount() > 1)
00492 dstImg->createMipmap(-1);
00493
00494 endEditCP(dstImg);
00495
00496 return true;
00497 }