EtcFilter.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. #include <stdlib.h>
  2. #include <math.h>
  3. #include "EtcFilter.h"
  4. namespace Etc
  5. {
  6. static const double PiConst = 3.14159265358979323846;
  7. inline double sinc(double x)
  8. {
  9. if ( x == 0.0 )
  10. {
  11. return 1.0;
  12. }
  13. return sin(PiConst * x) / (PiConst * x);
  14. }
  15. //inline float sincf( float x )
  16. //{
  17. // x *= F_PI;
  18. // if (x < 0.01f && x > -0.01f)
  19. // {
  20. // return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f);
  21. // }
  22. //
  23. // return sinf(x)/x;
  24. //}
  25. //
  26. //double bessel0(double x)
  27. //{
  28. // const double EPSILON_RATIO = 1E-16;
  29. // double xh, sum, pow, ds;
  30. // int k;
  31. //
  32. // xh = 0.5 * x;
  33. // sum = 1.0;
  34. // pow = 1.0;
  35. // k = 0;
  36. // ds = 1.0;
  37. // while (ds > sum * EPSILON_RATIO)
  38. // {
  39. // ++k;
  40. // pow = pow * (xh / k);
  41. // ds = pow * pow;
  42. // sum = sum + ds;
  43. // }
  44. //
  45. // return sum;
  46. //}
  47. //**--------------------------------------------------------------------------
  48. //** Name: kaiser(double alpha, double half_width, double x)
  49. //** Returns:
  50. //** Description: Alpha controls shape of filter. We are using 4.
  51. //**--------------------------------------------------------------------------
  52. //inline double kaiser(double alpha, double half_width, double x)
  53. //{
  54. // double ratio = (x / half_width);
  55. // return bessel0(alpha * sqrt(1 - ratio * ratio)) / bessel0(alpha);
  56. //}
  57. //
  58. //float Filter_Lanczos4Sinc(float x)
  59. //{
  60. // if (x <= -4.0f || x >= 4.0f) // half-width of 4
  61. // {
  62. // return 0.0;
  63. // }
  64. //
  65. // return sinc(0.875f * x) * sinc(0.25f * x);
  66. //}
  67. //
  68. //double Filter_Kaiser4( double t )
  69. //{
  70. // return kaiser( 4.0, 3.0, t);
  71. //}
  72. //
  73. //double Filter_KaiserOptimal( double t )
  74. //{
  75. // return kaiser( 8.93, 3.0f, t);
  76. //}
  77. double FilterLanczos3( double t )
  78. {
  79. if ( t <= -3.0 || t >= 3.0 )
  80. {
  81. return 0.0;
  82. }
  83. return sinc( t ) * sinc( t / 3.0 );
  84. }
  85. double FilterBox( double t )
  86. {
  87. return ( t > -0.5 && t < 0.5) ? 1.0 : 0.0;
  88. }
  89. double FilterLinear( double t )
  90. {
  91. if (t < 0.0) t = -t;
  92. return (t < 1.0) ? (1.0 - t) : 0.0;
  93. }
  94. //**--------------------------------------------------------------------------
  95. //** Name: CalcContributions( int srcSize,
  96. //** int destSize,
  97. //** double filterSize,
  98. //** bool wrap,
  99. //** double (*FilterProc)(double),
  100. //** FilterWeights contrib[] )
  101. //** Returns: void
  102. //** Description:
  103. //**--------------------------------------------------------------------------
  104. void CalcContributions( int srcSize, int destSize, double filterSize, bool wrap, double (*FilterProc)(double), FilterWeights contrib[] )
  105. {
  106. double scale;
  107. double filterScale;
  108. double center;
  109. double totalWeight;
  110. double weight;
  111. int iRight;
  112. int iLeft;
  113. int iDest;
  114. scale = (double)destSize / srcSize;
  115. if ( scale < 1.0 )
  116. {
  117. filterSize = filterSize / scale;
  118. filterScale = scale;
  119. }
  120. else
  121. {
  122. filterScale = 1.0;
  123. }
  124. if ( filterSize > (double)MaxFilterSize )
  125. {
  126. filterSize = (double)MaxFilterSize;
  127. }
  128. for ( iDest = 0; iDest < destSize; ++iDest )
  129. {
  130. center = (double)iDest / scale;
  131. iLeft = (int)ceil(center - filterSize);
  132. iRight = (int)floor(center + filterSize);
  133. if ( !wrap )
  134. {
  135. if ( iLeft < 0 )
  136. {
  137. iLeft = 0;
  138. }
  139. if ( iRight >= srcSize )
  140. {
  141. iRight = srcSize - 1;
  142. }
  143. }
  144. int numWeights = iRight - iLeft + 1;
  145. contrib[iDest].first = iLeft;
  146. contrib[iDest].numWeights = numWeights;
  147. totalWeight = 0;
  148. double t = ((double)iLeft - center) * filterScale;
  149. for (int i = 0; i < numWeights; i++)
  150. {
  151. weight = (*FilterProc)(t) * filterScale;
  152. totalWeight += weight;
  153. contrib[iDest].weight[i] = weight;
  154. t += filterScale;
  155. }
  156. //**--------------------------------------------------------
  157. //** Normalize weights by dividing by the sum of the weights
  158. //**--------------------------------------------------------
  159. if ( totalWeight > 0.0 )
  160. {
  161. for ( int i = 0; i < numWeights; i++)
  162. {
  163. contrib[iDest].weight[i] /= totalWeight;
  164. }
  165. }
  166. }
  167. }
  168. //**-------------------------------------------------------------------------
  169. //** Name: Filter_TwoPass( RGBCOLOR *pSrcImage,
  170. //** int srcWidth, int srcHeight,
  171. //** RGBCOLOR *pDestImage,
  172. //** int destWidth, int destHeight,
  173. //** double (*FilterProc)(double) )
  174. //** Returns: 0 on failure and 1 on success
  175. //** Description: Filters a 2d image with a two pass filter by averaging the
  176. //** weighted contributions of the pixels within the filter region. The
  177. //** contributions are determined by a weighting function parameter.
  178. //**-------------------------------------------------------------------------
  179. int FilterTwoPass( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
  180. RGBCOLOR *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double (*FilterProc)(double) )
  181. {
  182. FilterWeights *contrib;
  183. RGBCOLOR *pPixel;
  184. RGBCOLOR *pSrcPixel;
  185. RGBCOLOR *pTempImage;
  186. int iRow;
  187. int iCol;
  188. int iSrcCol;
  189. int iSrcRow;
  190. int iWeight;
  191. double dRed;
  192. double dGreen;
  193. double dBlue;
  194. double dAlpha;
  195. double filterSize = 3.0;
  196. int maxDim = (srcWidth>srcHeight)?srcWidth:srcHeight;
  197. contrib = (FilterWeights*)malloc(maxDim * sizeof(FilterWeights));
  198. //**------------------------------------------------------------------------
  199. //** Need to create a temporary image to stuff the horizontally scaled image
  200. //**------------------------------------------------------------------------
  201. pTempImage = (RGBCOLOR *)malloc( destWidth * srcHeight * sizeof(RGBCOLOR) );
  202. if ( pTempImage == NULL )
  203. {
  204. return 0;
  205. }
  206. //**-------------------------------------------------------
  207. //** Horizontally filter the image into the temporary image
  208. //**-------------------------------------------------------
  209. bool bWrapHorizontal = !!(wrapFlags&FILTER_WRAP_X);
  210. CalcContributions( srcWidth, destWidth, filterSize, bWrapHorizontal, FilterProc, contrib );
  211. for ( iRow = 0; iRow < srcHeight; iRow++ )
  212. {
  213. for ( iCol = 0; iCol < destWidth; iCol++ )
  214. {
  215. dRed = 0;
  216. dGreen = 0;
  217. dBlue = 0;
  218. dAlpha = 0;
  219. for ( iWeight = 0; iWeight < contrib[iCol].numWeights; iWeight++ )
  220. {
  221. iSrcCol = iWeight + contrib[iCol].first;
  222. if (bWrapHorizontal)
  223. {
  224. iSrcCol = (iSrcCol < 0) ? (srcWidth + iSrcCol) : (iSrcCol >= srcWidth) ? (iSrcCol - srcWidth) : iSrcCol;
  225. }
  226. pSrcPixel = pSrcImage + (iRow * srcWidth) + iSrcCol;
  227. dRed += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[0];
  228. dGreen += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[1];
  229. dBlue += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[2];
  230. dAlpha += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[3];
  231. }
  232. pPixel = pTempImage + (iRow * destWidth) + iCol;
  233. pPixel->rgba[0] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dRed)));
  234. pPixel->rgba[1] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dGreen)));
  235. pPixel->rgba[2] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dBlue)));
  236. pPixel->rgba[3] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dAlpha)));
  237. }
  238. }
  239. //**-------------------------------------------------------
  240. //** Vertically filter the image into the destination image
  241. //**-------------------------------------------------------
  242. bool bWrapVertical = !!(wrapFlags&FILTER_WRAP_Y);
  243. CalcContributions(srcHeight, destHeight, filterSize, bWrapVertical, FilterProc, contrib);
  244. for ( iCol = 0; iCol < destWidth; iCol++ )
  245. {
  246. for ( iRow = 0; iRow < destHeight; iRow++ )
  247. {
  248. dRed = 0;
  249. dGreen = 0;
  250. dBlue = 0;
  251. dAlpha = 0;
  252. for ( iWeight = 0; iWeight < contrib[iRow].numWeights; iWeight++ )
  253. {
  254. iSrcRow = iWeight + contrib[iRow].first;
  255. if (bWrapVertical)
  256. {
  257. iSrcRow = (iSrcRow < 0) ? (srcHeight + iSrcRow) : (iSrcRow >= srcHeight) ? (iSrcRow - srcHeight) : iSrcRow;
  258. }
  259. pSrcPixel = pTempImage + (iSrcRow * destWidth) + iCol;
  260. dRed += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[0];
  261. dGreen += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[1];
  262. dBlue += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[2];
  263. dAlpha += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[3];
  264. }
  265. pPixel = pDestImage + (iRow * destWidth) + iCol;
  266. pPixel->rgba[0] = (unsigned char)(std::max( 0.0, std::min( 255.0, dRed)));
  267. pPixel->rgba[1] = (unsigned char)(std::max( 0.0, std::min( 255.0, dGreen)));
  268. pPixel->rgba[2] = (unsigned char)(std::max( 0.0, std::min( 255.0, dBlue)));
  269. pPixel->rgba[3] = (unsigned char)(std::max( 0.0, std::min( 255.0, dAlpha)));
  270. }
  271. }
  272. free( pTempImage );
  273. free( contrib );
  274. return 1;
  275. }
  276. //**-------------------------------------------------------------------------
  277. //** Name: FilterResample(RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
  278. //** RGBCOLOR *pDstImage, int dstWidth, int dstHeight)
  279. //** Returns: 1
  280. //** Description: This function runs a 2d box filter over the srouce image
  281. //** to produce the destination image.
  282. //**-------------------------------------------------------------------------
  283. void FilterResample( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
  284. RGBCOLOR *pDstImage, int dstWidth, int dstHeight )
  285. {
  286. int iRow;
  287. int iCol;
  288. int iSampleRow;
  289. int iSampleCol;
  290. int iFirstSampleRow;
  291. int iFirstSampleCol;
  292. int iLastSampleRow;
  293. int iLastSampleCol;
  294. int red;
  295. int green;
  296. int blue;
  297. int alpha;
  298. int samples;
  299. float xScale;
  300. float yScale;
  301. RGBCOLOR *pSrcPixel;
  302. RGBCOLOR *pDstPixel;
  303. xScale = (float)srcWidth / dstWidth;
  304. yScale = (float)srcHeight / dstHeight;
  305. for ( iRow = 0; iRow < dstHeight; iRow++ )
  306. {
  307. for ( iCol = 0; iCol < dstWidth; iCol++ )
  308. {
  309. iFirstSampleRow = (int)(iRow * yScale);
  310. iLastSampleRow = (int)ceil(iFirstSampleRow + yScale - 1);
  311. if ( iLastSampleRow >= srcHeight )
  312. {
  313. iLastSampleRow = srcHeight - 1;
  314. }
  315. iFirstSampleCol = (int)(iCol * xScale);
  316. iLastSampleCol = (int)ceil(iFirstSampleCol + xScale - 1);
  317. if ( iLastSampleCol >= srcWidth )
  318. {
  319. iLastSampleCol = srcWidth - 1;
  320. }
  321. samples = 0;
  322. red = 0;
  323. green = 0;
  324. blue = 0;
  325. alpha = 0;
  326. for ( iSampleRow = iFirstSampleRow; iSampleRow <= iLastSampleRow; iSampleRow++ )
  327. {
  328. for ( iSampleCol = iFirstSampleCol; iSampleCol <= iLastSampleCol; iSampleCol++ )
  329. {
  330. pSrcPixel = pSrcImage + iSampleRow * srcWidth + iSampleCol;
  331. red += pSrcPixel->rgba[0];
  332. green += pSrcPixel->rgba[1];
  333. blue += pSrcPixel->rgba[2];
  334. alpha += pSrcPixel->rgba[3];
  335. samples++;
  336. }
  337. }
  338. pDstPixel = pDstImage + iRow * dstWidth + iCol;
  339. if ( samples > 0 )
  340. {
  341. pDstPixel->rgba[0] = static_cast<uint8_t>(red / samples);
  342. pDstPixel->rgba[1] = static_cast<uint8_t>(green / samples);
  343. pDstPixel->rgba[2] = static_cast<uint8_t>(blue / samples);
  344. pDstPixel->rgba[3] = static_cast<uint8_t>(alpha / samples);
  345. }
  346. else
  347. {
  348. pDstPixel->rgba[0] = static_cast<uint8_t>(red);
  349. pDstPixel->rgba[1] = static_cast<uint8_t>(green);
  350. pDstPixel->rgba[2] = static_cast<uint8_t>(blue);
  351. pDstPixel->rgba[3] = static_cast<uint8_t>(alpha);
  352. }
  353. }
  354. }
  355. }
  356. }