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
00193 template <class ValueT>
00194 struct ValueHandlerTempl : public ValueHandler
00195 {
00196 virtual Real64 getValue(const UInt8 *data,
00197 UInt32 channels,
00198 UInt32 width,UInt32 height,
00199 UInt32 c,
00200 UInt32 x1,UInt32 y1,UInt32 z1,
00201 UInt32 x2,UInt32 y2,UInt32 z2,
00202 Real64 *weightX,
00203 Real64 *weightY,
00204 Real64 *weightZ)
00205 {
00206 Real64 result = 0;
00207 UInt32 x,y,z;
00208
00209 for(z = 0 ; z <= (z2-z1) ; ++z)
00210 {
00211 for(y = 0 ; y <= (y2-y1) ; ++y)
00212 {
00213 ValueT *valueP = (ValueT*)(data) +
00214 (z1 + z) * (height*width*channels) +
00215 (y1 + y) * (width*channels) +
00216 (x1) * (channels) + c;
00217 for(x = 0 ; x <= (x2-x1) ; ++x)
00218 {
00219 result += (Real64)*(valueP) *
00220 (weightX[x] * weightY[y] * weightZ[z]);
00221 valueP += channels;
00222 }
00223 }
00224 }
00225 return result;
00226 }
00227 virtual void setValue(Real64 value,UInt8 *data,
00228 UInt32 channels,UInt32 width,UInt32 height,
00229 UInt32 c,UInt32 x,UInt32 y,UInt32 z)
00230 {
00231
00232 Real64 maxValue = (Real64)TypeTraits<ValueT>::getMax();
00233 if(value > maxValue)
00234 {
00235 value = maxValue;
00236 }
00237 else
00238 {
00239 if(value < 0.0)
00240 value = 0.0;
00241 }
00242
00243 ValueT *valueP = (ValueT*)(data);
00244 valueP = valueP +
00245 z * (width*height*channels) +
00246 y * (width*channels) +
00247 x * (channels) +
00248 c;
00249
00250 *valueP = (ValueT)value;
00251 }
00252 };
00253
00254
00256
00257 ImageScaler::ImageScaler(void)
00258 {
00259 }
00260
00261
00263
00264 ImageScaler::~ImageScaler(void)
00265 {
00266 }
00267
00268
00270
00271 void ImageScaler::calcContributions(UInt32 axis,
00272 Int32 uResSize,
00273 Int32 uSrcSize,
00274 const ImageGenericFilter &filter,
00275 std::vector<Contribution> contrib[3])
00276 {
00277 Real64 dWidth;
00278 Real64 dFScale = 1.0;
00279 Real64 dFilterWidth = filter.getWidth();
00280
00281 Real64 dScale = (Real64)uResSize / (Real64)uSrcSize;
00282
00283
00284 contrib[axis].resize(uResSize);
00285
00286 if (dScale < 1.0)
00287 {
00288 dWidth = dFilterWidth / dScale;
00289 dFScale = dScale;
00290 }
00291 else
00292 {
00293 dWidth= dFilterWidth;
00294 }
00295
00296
00297 Int32 iWindowSize = 2 * (Int32)ceil(dWidth) + 1;
00298
00299 for (Int32 u = 0; u < uResSize; u++)
00300 {
00301
00302 Real64 dCenter = (Real64)u / dScale;
00303
00304 Int32 iLeft = osgMax (0, (Int32)floor (dCenter - dWidth));
00305
00306 Int32 iRight = osgMin ((Int32)ceil (dCenter + dWidth), Int32(uSrcSize) - 1);
00307
00308
00309
00310 if (iRight - iLeft + 1 > iWindowSize)
00311 {
00312 if (iLeft < (Int32(uSrcSize) - 1 / 2))
00313 {
00314 iLeft++;
00315 }
00316 else
00317 {
00318 iRight--;
00319 }
00320 }
00321
00322 contrib[axis][u].left = iLeft;
00323 contrib[axis][u].right = iRight;
00324
00325 Real64 dTotalWeight = 0.0;
00326 contrib[axis][u].weights.resize(iRight - iLeft + 1);
00327 for (Int32 iSrc = iLeft; iSrc <= iRight; iSrc++)
00328 {
00329
00330 Real64 weight = dFScale *
00331 filter.filter(dFScale * (dCenter - (Real64)iSrc));
00332 contrib[axis][u].weights[iSrc-iLeft] = weight;
00333
00334 dTotalWeight += weight;
00335 }
00336 if (dTotalWeight > 0.0)
00337 {
00338
00339 for (Int32 iSrc = iLeft; iSrc <= iRight; iSrc++)
00340 {
00341
00342 contrib[axis][u].weights[iSrc-iLeft] /= dTotalWeight;
00343 }
00344
00345 while(contrib[axis][u].weights.front() == 0)
00346 {
00347 contrib[axis][u].left++;
00348 contrib[axis][u].weights.erase(contrib[axis][u].weights.begin());
00349 }
00350 while(contrib[axis][u].weights.back() == 0)
00351 {
00352 contrib[axis][u].right--;
00353 contrib[axis][u].weights.erase(contrib[axis][u].weights.end() - 1);
00354 }
00355 #if 0
00356 printf("%d %d %d,%d\n",axis,u,contrib[axis][u].left,contrib[axis][u].right);
00357 for (Int32 iSrc = 0; iSrc < contrib[axis][u].weights.size(); iSrc++)
00358 {
00359 printf("%lf ",contrib[axis][u].weights[iSrc]);
00360 }
00361 printf("\n");
00362 #endif
00363 }
00364 }
00365 }
00366
00367
00369
00370 bool ImageScaler::scale(ImagePtr &srcImg,
00371 ImagePtr &dstImg,
00372 Int32 width,
00373 Int32 height,
00374 Int32 depth,
00375 const ImageGenericFilter &filter)
00376 {
00377 ValueHandler *valueHandler = NULL;
00378 Int32 channels = srcImg->getComponents();
00379 std::vector<Contribution> contrib[3];
00380
00381 beginEditCP(dstImg);
00382
00383 switch(srcImg->getDataType())
00384 {
00385 case Image::OSG_UINT8_IMAGEDATA:
00386 valueHandler = new ValueHandlerTempl<UInt8>();
00387 break;
00388 case Image::OSG_UINT16_IMAGEDATA:
00389 valueHandler = new ValueHandlerTempl<UInt16>();
00390 break;
00391 case Image::OSG_UINT32_IMAGEDATA:
00392 valueHandler = new ValueHandlerTempl<UInt32>();
00393 break;
00394 case Image::OSG_FLOAT16_IMAGEDATA:
00395 valueHandler = new ValueHandlerTempl<Real16>();
00396 break;
00397 case Image::OSG_FLOAT32_IMAGEDATA:
00398 valueHandler = new ValueHandlerTempl<Real32>();
00399 break;
00400 default:
00401 SWARNING << "PixelType not scalable" << std::endl;
00402 return false;
00403 };
00404
00405
00406 calcContributions(0,width, srcImg->getWidth() ,filter,contrib);
00407 calcContributions(1,height,srcImg->getHeight(),filter,contrib);
00408 calcContributions(2,depth, srcImg->getDepth() ,filter,contrib);
00409
00410 if(!dstImg->set((Image::PixelFormat)srcImg->getPixelFormat(),
00411 width,
00412 height,
00413 depth,
00414
00415 1,
00416 srcImg->getFrameCount(),
00417 srcImg->getFrameDelay(),
00418 NULL,
00419 srcImg->getDataType(),
00420 true,
00421 srcImg->getSideCount()))
00422 {
00423 SWARNING << "Unable to set image format" << std::endl;
00424 return false;
00425 }
00426
00427 UInt32 srcImgWidth = srcImg->getWidth();
00428 UInt32 srcImgHeight = srcImg->getHeight();
00429 Real64 *weightX;
00430 Real64 *weightY;
00431 Real64 *weightZ;
00432 UInt32 frames = srcImg->getFrameCount();
00433 UInt32 sides = srcImg->getSideCount();
00434
00435
00436
00437
00438 Real64 value;
00439 UInt32 x,y,z,c,f,s;
00440 UInt32 x1,x2,y1,y2,z1,z2;
00441 for(s = 0 ; s < sides ; ++s)
00442 {
00443 for(f = 0 ; f < frames ; ++f)
00444 {
00445 UInt8 *dstImgData = dstImg->getData(0,f,s);
00446 UInt8 *srcImgData = srcImg->getData(0,f,s);
00447 for(z = 0 ; z < depth ; ++z)
00448 {
00449 z1 = contrib[2][z].left;
00450 z2 = contrib[2][z].right;
00451 weightZ = &contrib[2][z].weights[0];
00452 for(y = 0 ; y < height ; ++y)
00453 {
00454 y1 = contrib[1][y].left;
00455 y2 = contrib[1][y].right;
00456 weightY = &contrib[1][y].weights[0];
00457 for(x = 0 ; x < width ; ++x)
00458 {
00459 x1 = contrib[0][x].left;
00460 x2 = contrib[0][x].right;
00461
00462 weightX = &contrib[0][x].weights[0];
00463 for(c = 0 ; c < channels ; ++c)
00464 {
00465 value = valueHandler->getValue(srcImgData,
00466 channels,
00467 srcImgWidth,
00468 srcImgHeight,
00469 c,
00470 x1,y1,z1,
00471 x2,y2,z2,
00472 weightX,weightY,weightZ);
00473
00474 valueHandler->setValue(value,
00475 dstImgData,
00476 channels,width,height,
00477 c,x,y,z);
00478 }
00479 }
00480 }
00481 }
00482 }
00483 }
00484
00485 if(valueHandler != NULL)
00486 delete valueHandler;
00487
00488
00489 if(srcImg->getMipMapCount() > 1)
00490 dstImg->createMipmap(-1);
00491
00492 endEditCP(dstImg);
00493
00494 return true;
00495 }