FaceGen 3 SDKs Reference
Loading...
Searching...
No Matches
fimImgOps.hpp
1//
2// Copyright (c) Singular Inversions Inc. 2001.
3//
4// Authors: Andrew Beatty
5// Created: June 12, 2001.
6
7#ifndef FIM_IMGOPS_HPP
8#define FIM_IMGOPS_HPP
9
10#include "matrixCTA.hpp"
11#include "fimImg.hpp"
12#include "fimImgTransMap.hpp"
13#include "FgSerial.hpp"
14#include "FgMatrixC.hpp"
15
16namespace Fg {
17
18void
19fimCutResizeRcs(
20 FutVect2FC lo,
21 FutVect2FC hi,
22 uint w,
23 uint h,
24 const FimImgRgbaUbC & src,
25 FimImgRgbaUbC & dst);
26
27// Samples outside boundary have zero alpha (pre-weighted):
28FimRgbaFC
29fimInterpFloatOics(
30 const FimImgRgbaUbC & img,
31 float x,
32 float y);
33
34FimRgbaFC
35fimInterpFloatOics(
36 const FimImgRgbaFC & img,
37 float x,
38 float y);
39
40void
41fimShrink2(
42 const FimImgRgbaUbC & src,
43 FimImgRgbaUbC & dst);
44
45void
46fimShrink2(
47 const FimImgRgbaFC & src,
48 FimImgRgbaFC & dst);
49
50void
51fgImgShrinkInt(const FimImgRgbaUbC& src,FimImgRgbaUbC& dst,uint factor);
52
53void
54fimZwrGammaAffine(
55 float gamma,
56 float black,
57 float gain,
58 const FimImgRgbaFC & src,
59 FimImgRgbaFC & dst);
60
61void
62fimMirrorDetailDiff(
63 FimImgRgbaFC & img);
64
65// ****************************************************************************
66// ****************************************************************************
67
68template<class T,class U>
69U fimLoopUnary(
70
71 U opArgs,
72 FimImgT<T> &img)
73{
74 FGASSERT(img.imageAllocated());
75 uint wid = img.width(),
76 hgt = img.height();
77
78 // FGASSERT(wid == ((wid >> 2) << 2)); // Multiple of 4 width.
79
80 T *ptr = img.imageData();
81 uint step = img.widthStepType();
82
83 if (wid == ((wid >> 2) << 2))
84 {
85 for (uint yy=0; yy<hgt; yy++)
86 {
87 for (uint xx=0; xx<wid; xx+=4)
88 {
89 opArgs.opUnary(ptr[xx]);
90 opArgs.opUnary(ptr[xx+1]);
91 opArgs.opUnary(ptr[xx+2]);
92 opArgs.opUnary(ptr[xx+3]);
93 }
94 ptr += step;
95 }
96 }
97 else
98 {
99 uint wid2 = ((wid >> 2) << 2);
100 for (uint yy=0; yy<hgt; yy++)
101 {
102 for (uint xx=0; xx<wid2 && wid2>=4; xx+=4)
103 {
104 opArgs.opUnary(ptr[xx]);
105 opArgs.opUnary(ptr[xx+1]);
106 opArgs.opUnary(ptr[xx+2]);
107 opArgs.opUnary(ptr[xx+3]);
108 }
109 for (uint xx2=wid2; xx2<wid; ++xx2)
110 {
111 opArgs.opUnary(ptr[xx2]);
112 }
113 ptr += step;
114 }
115 }
116
117 return opArgs;
118}
119
120template<class T1,class T2,class U>
121U fimLoopBinary(
122 U opArgs,
123 FimImgT<T1> & img1,
124 FimImgT<T2> & img2)
125{
126 FGASSERT(img1.imageAllocated());
127 uint wid = img1.width(),
128 hgt = img1.height();
129 img2.resize(wid,hgt);
130
131 T1 * img1ptr = img1.imageData();
132 T2 * img2Ptr = img2.imageData();
133 uint img1step = img1.widthStepType(),
134 img2Step = img2.widthStepType();
135
136 for (uint yy=0; yy<hgt; yy++)
137 {
138 for (uint xx=0; xx<wid; xx++)
139 {
140 opArgs.opBinary(img1ptr[xx],img2Ptr[xx]);
141 }
142 img1ptr += img1step;
143 img2Ptr += img2Step;
144 }
145 return opArgs;
146}
147
148template<class T1,class T2,class U>
149U fimLoopBinary(
150 U opArgs,
151 const FimImgT<T1> & img1,
152 FimImgT<T2> & img2)
153{
154 FGASSERT(img1.imageAllocated());
155 uint wid = img1.width(),
156 hgt = img1.height();
157 img2.resize(wid,hgt);
158
159 const T1 * img1ptr = img1.imageData();
160 T2 * img2Ptr = img2.imageData();
161 uint img1step = img1.widthStepType(),
162 img2Step = img2.widthStepType();
163
164 for (uint yy=0; yy<hgt; yy++)
165 {
166 for (uint xx=0; xx<wid; xx++)
167 {
168 opArgs.opBinary(img1ptr[xx],img2Ptr[xx]);
169 }
170 img1ptr += img1step;
171 img2Ptr += img2Step;
172 }
173 return opArgs;
174}
175
176template<class T1,class T2,class U>
177U fimLoopBinary(
178 U opArgs,
179 const FimImgT<T1> & img1,
180 const FimImgT<T2> & img2)
181{
182 FGASSERT(img1.imageAllocated());
183 uint wid = img1.width(),
184 hgt = img1.height();
185 FGASSERT(img1.width() == img2.width());
186 FGASSERT(img1.height() == img2.height());
187
188 const T1 * img1ptr = img1.imageData();
189 const T2 * img2Ptr = img2.imageData();
190 uint img1step = img1.widthStepType(),
191 img2Step = img2.widthStepType();
192
193 for (uint yy=0; yy<hgt; yy++)
194 {
195 for (uint xx=0; xx<wid; xx++)
196 {
197 opArgs.opBinary(img1ptr[xx],img2Ptr[xx]);
198 }
199 img1ptr += img1step;
200 img2Ptr += img2Step;
201 }
202 return opArgs;
203}
204
205template<class T1,class T2,class T3,class U>
206U fimLoopTernary(
207
208 U opArgs,
209 const FimImgT<T1> & img1,
210 const FimImgT<T2> & img2,
211 FimImgT<T3> & img3)
212{
213 FGASSERT(img1.imageAllocated());
214 FGASSERT(img2.imageAllocated());
215 uint wid = img1.width(),
216 hgt = img1.height();
217 FGASSERT(wid == img2.width());
218 FGASSERT(hgt == img2.height());
219 img3.resize(wid,hgt);
220
221 T1 *img1ptr = (T1 *)img1.imageData();
222 T2 *img2Ptr = (T2 *)img2.imageData();
223 T3 *img3Ptr = (T3 *)img3.imageData();
224 uint img1step = img1.widthStepType(),
225 img2Step = img2.widthStepType(),
226 img3Step = img3.widthStepType();
227
228 for (uint yy=0; yy<hgt; yy++)
229 {
230 for (uint xx=0; xx<wid; xx++)
231 {
232 opArgs.opTernary(img1ptr[xx],img2Ptr[xx],img3Ptr[xx]);
233 }
234 img1ptr += img1step;
235 img2Ptr += img2Step;
236 img3Ptr += img3Step;
237 }
238 return opArgs;
239}
240
241// ****************************************************************************
242// ****************************************************************************
243
244// Note that this function DOES NOT CLAMP.
245template<class T>
247{
248 void opBinary(T const &a,T &b)
249 {
250 b += a;
251 }
252};
253
254template<class T>
255inline void fimAcc(
256
257 const FimImgT<T> &src,
258 FimImgT<T> &dst)
259{
260 fimLoopBinary(FimAccOpS<T>(),src,dst);
261}
262
263// ****************************************************************************
264// ****************************************************************************
265
266// Note that this function DOES NOT CLAMP.
267template<class T>
269{
270 void opTernary(T const &a,T const &b,T &c)
271 {
272 c = a + b;
273 }
274};
275
276template<class T>
277inline void fimAdd(
278
279 FimImgT<T> &src1,
280 FimImgT<T> &src2,
281 FimImgT<T> &dst)
282{
283 dst.resize(src1.width(),src1.height());
284 fimLoopTernary(FimAddOpS<T>(),src1,src2,dst);
285}
286
287// ****************************************************************************
288// ****************************************************************************
289
290// Accumulate alpha-modulated pixels into an accumulation image.
292{
293public:
294 void opBinary(FimRgbaFC &acc,FimRgbaFC &inp)
295 {
296 acc.c[FIMRGBA_R] += (float)inp.c[FIMRGBA_R];
297 acc.c[FIMRGBA_G] += (float)inp.c[FIMRGBA_G];
298 acc.c[FIMRGBA_B] += (float)inp.c[FIMRGBA_B];
299 acc.c[FIMRGBA_A] += (float)inp.c[FIMRGBA_A];
300 }
301};
302
303inline void fimAlphaAcc(
304
305 FimImgRgbaFC &acc, // Accumulator image
306 FimImgRgbaFC &inp) // Input image
307{
308 fimLoopBinary(FimAlphaAccOpT(),acc,inp);
309}
310
311// ****************************************************************************
312// ****************************************************************************
313
314// Note that this function DOES NOT CLAMP.
316{
317 int val;
318
319 FimAddConvertOpS(int v) : val(v) {};
320
321 void opBinary(schar src,uchar &dst)
322 {
323 dst = (uchar)((int)src + val);
324 }
325};
326
327inline void fimAddConvert(
328
329 const FimImgSbC &src,
330 FimImgUbC &dst,
331 int val)
332{
333 dst.resize(src.width(),src.height());
334 fimLoopBinary(FimAddConvertOpS(val),src,dst);
335}
336
338{
339 float val;
340
341 FimAddConvertOpFS(float v) : val(v) {};
342
343 void opBinary(float src,uchar &dst)
344 {
345 dst = (uchar)((float)src + val);
346 }
347};
348
349inline void fimAddConvert(
350
351 const FimImgFC &src,
352 FimImgUbC &dst,
353 float val)
354{
355 dst.resize(src.width(),src.height());
356 fimLoopBinary(FimAddConvertOpFS(val),src,dst);
357}
358
359// ****************************************************************************
360// ****************************************************************************
361
362inline uchar fimOpAffineGamma(uchar a,float gamma,float black,float gain)
363{
364 float ftmp = ((float)a - black) * gain / 255.0f;
365 if (ftmp < 0.0) ftmp = 0.0f;
366 if (ftmp > 1.0) ftmp = 1.0f;
367 ftmp = pow(ftmp,gamma);
368 return (uchar)(ftmp * 255.0f + 0.5f);
369}
370
372{
373 float gamma;
374 float black;
375 float gain;
376
377 FimOpAffineGammaS(float gam,float blk,float gn) :
378 gamma(gam), black(blk), gain(gn) {};
379
380 void opUnary(FimRgbaT<uchar> &a)
381 {
382 a.c[FIMRGBA_R] = fimOpAffineGamma(a.c[FIMRGBA_R],gamma,black,gain);
383 a.c[FIMRGBA_G] = fimOpAffineGamma(a.c[FIMRGBA_B],gamma,black,gain);
384 a.c[FIMRGBA_B] = fimOpAffineGamma(a.c[FIMRGBA_A],gamma,black,gain);
385 }
386};
387
388template<class T>
389void fimAffineGamma(
390
391 float gamma,
392 float black,
393 float gain,
394 FimImgT<T> &src,
395 FimImgT<T> &dst)
396{
397 fimLoopBinary(FimOpAffineGammaS(gamma,black,gain),src,dst);
398}
399
400// ****************************************************************************
401// ****************************************************************************
402
403// Binarize the alpha channel of an RGBA between 127 and 128, correcting the
404// alpha-weghted values.
406{
407 void
408 opUnary(FimRgbaFC & val)
409 {
410 if (val.c[FIMRGBA_A] < 128.0f)
411 {
412 val.c[0] = 0.0f;
413 val.c[1] = 0.0f;
414 val.c[2] = 0.0f;
415 val.c[3] = 0.0f;
416 }
417 else
418 {
419 float alpha = val.c[FIMRGBA_A];
420 val.c[FIMRGBA_R] = val.c[FIMRGBA_R] * 255.0f / alpha;
421 val.c[FIMRGBA_G] = val.c[FIMRGBA_G] * 255.0f / alpha;
422 val.c[FIMRGBA_B] = val.c[FIMRGBA_B] * 255.0f / alpha;
423 val.c[FIMRGBA_A] = 255.0f;
424 }
425 }
426};
427
428inline void
429fimAlphaBinarize(
430 FimImgRgbaFC & img)
431{
432 fimLoopUnary(FimAlphaBinarizeOp(),img);
433}
434
435// ****************************************************************************
436// ****************************************************************************
437
439{
440public:
441 void
442 opUnary(FimRgbaFC & i)
443 {
444 if (i.c[FIMRGBA_A] < 255.0f)
445 {
446 i.c[0] = 0.0f;
447 i.c[1] = 0.0f;
448 i.c[2] = 0.0f;
449 i.c[3] = 0.0f;
450 }
451 }
452};
453
454inline
455void
456fimAlphaThresh(
457 FimImgRgbaFC & img)
458{
459 fimLoopUnary(FimOpAlphaThreshT(),img);
460}
461
462// ****************************************************************************
463// ****************************************************************************
464
465// AND the alpha values of two images into the second image.
467{
468public:
469 void opBinary(FimRgbaUbC &s,FimRgbaUbC &d)
470 {
471 d.c[FIMRGBA_A] = s.c[FIMRGBA_A] & d.c[FIMRGBA_A];
472 }
473};
474
475inline void fimAndAlpha(
476
477 FimImgRgbaUbC &src,
478 FimImgRgbaUbC &dst)
479{
480 dst.resize(src.width(),src.height());
481
482 fimLoopBinary(FimOpAndAlphaT(),src,dst);
483}
484
485// ****************************************************************************
486// ****************************************************************************
487
488// Creates a bilinear oversampled image. The oversample scale factor must
489// be power of 2 greater than or equal to 1.
490
491// Some necessary in-line functions.
492inline FimRgbaUbC fimScaledPixelAdd4(
493 FimRgbaUbC pix1, FimRgbaUbC pix2, FimRgbaUbC pix3, FimRgbaUbC pix4,
494 double scale1, double scale2, double scale3, double scale4)
495{
496 FimRgbaUbC retval;
497 for (int clr=0; clr<FIMRGBA_SIZE; ++clr)
498 {
499 retval.c[clr] = (uchar)(0.5 + (double) pix1.c[clr] * scale1 +
500 (double) pix2.c[clr] * scale2 +
501 (double) pix3.c[clr] * scale3 +
502 (double) pix4.c[clr] * scale4 );
503 }
504 return retval;
505}
506
507inline uchar fimScaledPixelAdd4(
508 uchar pix1, uchar pix2, uchar pix3, uchar pix4,
509 double scale1, double scale2, double scale3, double scale4)
510{
511 return ( (uchar)(0.5 + (double) pix1 * scale1 +
512 (double) pix2 * scale2 +
513 (double) pix3 * scale3 +
514 (double) pix4 * scale4) );
515}
516
517inline schar fimScaledPixelAdd4(
518 schar pix1, schar pix2, schar pix3, schar pix4,
519 double scale1, double scale2, double scale3, double scale4)
520{
521 return ( (schar)((double) pix1 * scale1 +
522 (double) pix2 * scale2 +
523 (double) pix3 * scale3 +
524 (double) pix4 * scale4) );
525}
526
527inline short fimScaledPixelAdd4(
528 short pix1, short pix2, short pix3, short pix4,
529 double scale1, double scale2, double scale3, double scale4)
530{
531 return ( (short)((double) pix1 * scale1 +
532 (double) pix2 * scale2 +
533 (double) pix3 * scale3 +
534 (double) pix4 * scale4) );
535}
536
537inline long fimScaledPixelAdd4(
538 long pix1, long pix2, long pix3, long pix4,
539 double scale1, double scale2, double scale3, double scale4)
540{
541 return ( (long)((double) pix1 * scale1 +
542 (double) pix2 * scale2 +
543 (double) pix3 * scale3 +
544 (double) pix4 * scale4) );
545}
546
547inline float fimScaledPixelAdd4(
548 float pix1, float pix2, float pix3, float pix4,
549 double scale1, double scale2, double scale3, double scale4)
550{
551 return ( (float)((double) pix1 * scale1 +
552 (double) pix2 * scale2 +
553 (double) pix3 * scale3 +
554 (double) pix4 * scale4) );
555}
556
557inline double fimScaledPixelAdd4(
558 double pix1, double pix2, double pix3, double pix4,
559 double scale1, double scale2, double scale3, double scale4)
560{
561 return ( pix1 * scale1 + pix2 * scale2 + pix3 * scale3 + pix4 * scale4 );
562}
563
564// Actual definition of the function.
565template <class T>
566bool fimBilinearOversample(
567 int scale,
568 const FimImgT<T> &src,
569 FimImgT<T> &dst)
570{
571 if (scale == 1)
572 {
573 fimCopy(src,dst);
574 return true;
575 }
576
577 // Error check
578 if (scale < 1)
579 return false;
580 if (fr2Log2Floor(scale) != fr2Log2Ceil(scale))
581 return false;
582
583 // New image size
584 int newWidth = src.width() * scale;
585 int newHeight = src.height() * scale;
586 dst.resize(newWidth,newHeight);
587
588 // Pre-calculate bi-linear interpolation factors
589 int denorm = scale*2;
590 double oneOverDenormSqr = 1.0 / (double)(denorm*denorm);
591 Svec<Mat22D> factors; factors.reserve(scale*scale);
592 for (int rr=0, rfactor=denorm-1, ii=0; rr<scale; ++rr, rfactor-=2) {
593 for (int cc=0, cfactor=denorm-1; cc<scale; ++cc, cfactor-=2, ++ii) {
594 factors.emplace_back(
595 (double)(cfactor*rfactor) * oneOverDenormSqr,
596 (double)((denorm-cfactor)*rfactor) * oneOverDenormSqr,
597 (double)(cfactor*(denorm-rfactor)) * oneOverDenormSqr,
598 (double)((denorm-cfactor)*(denorm-rfactor)) * oneOverDenormSqr);
599 }
600 }
601
602 uint dstRowWidth = dst.widthStepType();
603 uint dstRowWidthBytes = dst.widthStepByte();
604 uint srcRowWidth = src.widthStepType();
605
606 // Now do the bilinear interpolated oversampling (ignoring the boundaries)
607 int halfScale = scale / 2;
608 T const *srcPtr = src.imageData();
609 T *dstPtr = dst.imageData() + halfScale*dstRowWidth;
610
611 for (int dstRow=halfScale, rCount=0; dstRow<newHeight-halfScale; ++dstRow)
612 {
613 T const *srcPtr2 = srcPtr + srcRowWidth;
614 int idx1 = ((dstRow-halfScale) % scale) * scale;
615
616 for (int dstCol=halfScale, srcCol=0, cCount=0;
617 dstCol<newWidth-halfScale; ++dstCol)
618 {
619 int ii = idx1 + ((dstCol-halfScale) % scale);
620
621 dstPtr[dstCol] = fimScaledPixelAdd4(
622 srcPtr[srcCol], srcPtr[srcCol+1],
623 srcPtr2[srcCol], srcPtr2[srcCol+1],
624 factors[ii].rc(0,0), factors[ii].rc(0,1),
625 factors[ii].rc(1,0), factors[ii].rc(1,1));
626
627 ++cCount;
628 if (cCount == scale)
629 {
630 cCount = 0;
631 ++srcCol;
632 }
633 }
634
635 dstPtr += dstRowWidth;
636 ++rCount;
637 if (rCount == scale)
638 {
639 rCount = 0;
640 srcPtr += srcRowWidth;
641 }
642 }
643
644 // Now smear the boundaries.
645 T *dstPtr1 = dst.imageData();
646 T *dstPtr2 = dst.imageData()+dstRowWidth*(newHeight-1);
647 T *dstSrc1 = dst.imageData()+dstRowWidth*halfScale;
648 T *dstSrc2 = dst.imageData()+dstRowWidth*(newHeight-1-halfScale);
649 for (int dstRow=0; dstRow<halfScale; ++dstRow)
650 {
651 memcpy(dstPtr1,dstSrc1,dstRowWidthBytes);
652 memcpy(dstPtr2,dstSrc2,dstRowWidthBytes);
653 dstPtr1 += dstRowWidth;
654 dstPtr2 -= dstRowWidth;
655 }
656 dstPtr1 = dst.imageData();
657 dstPtr2 = dst.imageData()+newWidth-halfScale;
658 dstSrc1 = dst.imageData()+halfScale;
659 dstSrc2 = dst.imageData()+newWidth-1-halfScale;
660 for (int dstRow=0; dstRow<newHeight; ++dstRow)
661 {
662 for (int dstCol=0; dstCol<halfScale; ++dstCol)
663 {
664 dstPtr1[dstCol] = dstSrc1[0];
665 dstPtr2[dstCol] = dstSrc2[0];
666 }
667 dstPtr1 += dstRowWidth;
668 dstPtr2 += dstRowWidth;
669 dstSrc1 += dstRowWidth;
670 dstSrc2 += dstRowWidth;
671 }
672
673 return true;
674}
675
676// ****************************************************************************
677// ****************************************************************************
678
679template<class T,class U>
681{
682public:
683 void
684 opBinary(
685 T const & s,
686 U & d)
687 {futConvert(s,d); }
688};
689
690template<class T,class U>
691void
692fimConvert(
693 const FimImgT<T> & src,
694 FimImgT<U> & dst)
695{
696 dst.resize(src.width(),src.height());
697 fimLoopBinary(FimOpConvertT<T,U>(),src,dst);
698}
699
700// ****************************************************************************
701// ****************************************************************************
702
703template<class T>
704void fimCopy(
705
706 const FimImgT<T> &src,
707 FimImgT<T> &dst)
708{
709 FGASSERT(src.imageAllocated());
710 FGASSERT((src.width() > 0) && (src.height() > 0));
711
712 dst.resize(src.width(),src.height()); // Only re-sizes if not already
713 // of given size.
714 memcpy(dst.imageData(),src.imageData(),src.widthStepByte() * src.height());
715}
716
717// ****************************************************************************
718// ****************************************************************************
719
720void
721fimSmoothF(
722 const FimImgRgbaFC & src,
723 FimImgRgbaFC & dst);
724
725// ****************************************************************************
726// ****************************************************************************
727
728// This function 'cuts out' the rendered region from the original
729// photo, using the thresholded render image alpha channel to
730// define the rendered region. Any alpha above 0 is thresholded
731// to zero in the destination image.
732inline
733void
734fimCopyAlphaMaskThresh(
735 const FimImgRgbaFC & src,
736 const FimImgRgbaFC & alpha, // Mask based on this image.
737 FimImgRgbaFC & dst)
738{
739 FGASSERT(src.height() == alpha.height());
740 dst.resize(src.width(),src.height());
741 for (uint row=0; row<src.height(); ++row)
742 {
743 for (uint col=0; col<src.width(); ++col)
744 {
745 if (alpha[row][col].c[FIMRGBA_A] == 0.0f)
746 {
747 dst[row][col] = src[row][col];
748 }
749 else
750 {
751 float * dstPtr = &(dst[row][col].c[0]);
752 dstPtr[0] = 0.0f;
753 dstPtr[1] = 0.0f;
754 dstPtr[2] = 0.0f;
755 dstPtr[3] = 0.0f;
756 }
757 }
758 }
759}
760
761// ****************************************************************************
762// ****************************************************************************
763
764// Copies a sub-region of an image to another image of the same type.
765template<class T>
766void fimCrop(
767
768 uint xl, // Lower and Upper corners
769 uint yl, // of the crop region.
770 uint xh,
771 uint yh,
772 FimImgT<T> &src,
773 FimImgT<T> &dst)
774{
775 FGASSERT(src.imageAllocated());
776 FGASSERT((xh >= xl) && (yh >= yl));
777 FGASSERT((src.width() > xh) && (src.height() > yh));
778
779 dst.resize(xh-xl+1,yh-yl+1); // Only re-sizes if not already
780 // of given size.
781 T *srcPtr = (T *)src.imageData();
782 T *dstPtr = (T *)dst.imageData();
783 uint srcStep = src.widthStepType(),
784 dstStep = dst.widthStepType(),
785 dstByte = dst.width() * sizeof(T);
786
787 srcPtr += yl * srcStep;
788 for (uint ii=yl; ii<=yh; ii++)
789 {
790 memcpy(dstPtr,&(srcPtr[xl]),dstByte);
791 dstPtr += dstStep;
792 srcPtr += srcStep;
793 }
794}
795
796// ****************************************************************************
797// ****************************************************************************
798// Image dot product of (alpha-weighted) RGB components.
800{
801public:
802 double tot;
803
805 : tot(0.0)
806 {}
807
808 void
809 opBinary(
810 const FimRgbaFC & i1,
811 const FimRgbaFC & i2)
812 {
813 tot += double(i1.c[FIMRGBA_R]) * double(i2.c[FIMRGBA_R]) +
814 double(i1.c[FIMRGBA_G]) * double(i2.c[FIMRGBA_G]) +
815 double(i1.c[FIMRGBA_B]) * double(i2.c[FIMRGBA_B]);
816 }
817};
818
819inline double
820fimDotProduct(
821 const FimImgRgbaFC & i1,
822 const FimImgRgbaFC & i2)
823{
824 FimDotProductOp val;
825 val = fimLoopBinary(val,i1,i2);
826 return val.tot;
827}
828
829// ****************************************************************************
830// ****************************************************************************
831
832template<class T>
834{
835public:
836 T val;
837 FimFillOpT(T &a) : val(a) {};
838 void opUnary(T &pix)
839 {
840 pix = val;
841 };
842};
843
844template<class T>
845inline void fimFill(
846
847 FimImgT<T> &img,
848 T val)
849{
850 fimLoopUnary(FimFillOpT<T>(val),img);
851}
852
853// ****************************************************************************
854// ****************************************************************************
855
856template<class T,class U>
858{
859public:
860 uint channel;
861 FimOpGetChannelT(uint a) : channel(a) {};
862 void opBinary(const FimRgbaT<T> &in,U &out)
863 {
864 futConvert(in.c[channel],out);
865 };
866};
867
868template<class T,class U>
869inline void fimGetChannel(
870
871 uint channel,
872 const FimImgT<FimRgbaT<T> > &src,
873 FimImgT<U> &dst)
874{
875 FGASSERT(channel < 4);
876 dst.resize(src.width(),src.height()); // Only re-sizes if not already
877 // of given size.
878 fimLoopBinary(FimOpGetChannelT<T,U>(channel),src,dst);
879}
880
881// ****************************************************************************
882// ****************************************************************************
883
884template<class T>
886{
887public:
888 T *lut;
889 FimOpLutRgbaT(T *l) : lut(l) {};
890 void opUnary(FimRgbaT<T> &p)
891 {
892 p.c[FIMRGBA_R] = lut[p.c[FIMRGBA_R]]; // Only apply LUT to colour channels.
893 p.c[FIMRGBA_G] = lut[p.c[FIMRGBA_G]];
894 p.c[FIMRGBA_B] = lut[p.c[FIMRGBA_B]];
895 };
896};
897
898template<class T>
899inline void fimLut(
900
901 T lut[],
902 FimImgT<FimRgbaT<T> > &img)
903{
904 FGASSERT(sizeof(T) <= 2); // LUTs must fit in memory
905 fimLoopUnary(FimOpLutRgbaT<T>(lut),img);
906}
907
908// ****************************************************************************
909// ****************************************************************************
910
911template<class T>
913{
914public:
915 T *lut;
916 FimOpLutCopyRgbaT(T *l) : lut(l) {};
917 void opBinary(FimRgbaT<T> &s,FimRgbaT<T> &d)
918 {
919 d.c[FIMRGBA_R] = lut[s.c[FIMRGBA_R]]; // Only apply LUT to colour channels.
920 d.c[FIMRGBA_G] = lut[s.c[FIMRGBA_G]];
921 d.c[FIMRGBA_B] = lut[s.c[FIMRGBA_B]];
922 d.c[FIMRGBA_A] = s.c[FIMRGBA_A];
923 }
924};
925
926template<class T>
927inline void fimLut(
928
929 T lut[],
930 FimImgT<FimRgbaT<T> > &src,
931 FimImgT<FimRgbaT<T> > &dst)
932{
933 FGASSERT(sizeof(T) <= 2); // LUTs must fit in memory
934 fimLoopBinary(FimOpLutCopyRgbaT<T>(lut),src,dst);
935}
936
937// ****************************************************************************
938// ****************************************************************************
939
940template <class T>
942{
943public:
944 T maxv,minv;
945 FimMaxMinOpT(T val) : maxv(val),minv(val) {}; // Must be initialized
946 // with value from first
947 // pixel.
948 void opUnary(FimRgbaT<T> &v)
949 {
950 if (v.c[FIMRGBA_R] > maxv) maxv = v.c[FIMRGBA_R];
951 if (v.c[FIMRGBA_G] > maxv) maxv = v.c[FIMRGBA_G];
952 if (v.c[FIMRGBA_B] > maxv) maxv = v.c[FIMRGBA_B];
953 if (v.c[FIMRGBA_R] < minv) minv = v.c[FIMRGBA_R];
954 if (v.c[FIMRGBA_G] < minv) minv = v.c[FIMRGBA_G];
955 if (v.c[FIMRGBA_B] < minv) minv = v.c[FIMRGBA_B];
956 }
957};
958
959template <class T>
960void fimMaxMin(FimImgT<FimRgbaT<T> >& img,T &maxv,T &minv)
961{
962 FGASSERT((img.width() > 0) && (img.height() > 0));
963
964 FimMaxMinOpT<T> v(img[0][0].c[FIMRGBA_R]);
965 v = fimLoopUnary(v,img);
966 maxv = v.maxv;
967 minv = v.minv;
968 return;
969}
970
971// ****************************************************************************
972// ****************************************************************************
973
975{
976 FimMultAccConvS(int v) : val(v) {};
977 void opBinary(const schar &a,int &b) {b += val * int(a); };
978 int val;
979};
980
981inline void fimMultAccConv(
982
983 int val, // Multiplication factor
984 const FimImgT<schar> &imgInp, // Input image.
985 FimImgT<int> &imgOut) // Accumulated image
986{
987 imgOut.resize(imgInp.width(),imgInp.height());
988 fimLoopBinary(FimMultAccConvS(val),imgInp,imgOut);
989 return;
990}
991
992void fimMultAccConvRoi(
993 int val, // Multiplication factor
994 const FimImgT<schar> &imgInp, // Input image.
995 FimImgT<int> &imgOut, // Accumulated image
996 uint offx, // Output offset
997 uint offy);
998
999// ****************************************************************************
1000// ****************************************************************************
1001
1003{
1004public:
1005 float val;
1006 FimRescaleOpT(float v) : val(v) {};
1007 void opUnary(FimRgbaUbC &p)
1008 {
1009 p.c[FIMRGBA_R] = (uchar)((float)p.c[FIMRGBA_R] * val + 0.5);
1010 p.c[FIMRGBA_G] = (uchar)((float)p.c[FIMRGBA_G] * val + 0.5);
1011 p.c[FIMRGBA_B] = (uchar)((float)p.c[FIMRGBA_B] * val + 0.5);
1012 }
1013};
1014
1015inline float fimRescale(FimImgRgbaUbC& img)
1016{
1017 uchar max,min;
1018 fimMaxMin(img,max,min);
1019 FimRescaleOpT r(255.0f / (float)max);
1020 fimLoopUnary(r,img);
1021 return r.val;
1022}
1023
1024// ****************************************************************************
1025// ****************************************************************************
1026
1027// Returns the sum of the squared differences between two (alpha-weighted) images.
1029{
1030public:
1031 double val;
1032
1033 FimSsdOp()
1034 : val(0.0)
1035 {}
1036
1037 void
1038 opBinary(
1039 const FimRgbaFC & i1,
1040 const FimRgbaFC & i2)
1041 {
1042 val += sqr(double(i2.c[FIMRGBA_R]) - double(i1.c[FIMRGBA_R]));
1043 val += sqr(double(i2.c[FIMRGBA_G]) - double(i1.c[FIMRGBA_G]));
1044 val += sqr(double(i2.c[FIMRGBA_B]) - double(i1.c[FIMRGBA_B]));
1045 }
1046};
1047
1048inline
1049double
1050fimSsd(
1051 const FimImgRgbaFC & i1,
1052 const FimImgRgbaFC & i2)
1053{
1054 FGASSERT(i1.width() == i2.width());
1055 FGASSERT(i1.height() == i2.height());
1056 FimSsdOp val;
1057 val = fimLoopBinary(val,i1,i2);
1058 return val.val;
1059}
1060
1061// ****************************************************************************
1062// ****************************************************************************
1063
1064template <typename T>
1065void fimRotate(
1066
1067 int direction, // 0 for left, 1 for right
1068 const FimImgT<T> &src,
1069 FimImgT<T> &dst)
1070{
1071 uint srcWidth = src.width();
1072 uint srcHeight = src.height();
1073
1074 FGASSERT(srcWidth);
1075 FGASSERT(srcHeight);
1076
1077 if (srcWidth == 0 || srcHeight == 0) return;
1078
1079 uint dstWidth = srcHeight;
1080 uint dstHeight = srcWidth;
1081
1082 dst.resize(dstWidth,dstHeight);
1083
1084 uint dstRowSize = dst.widthStepType();
1085 T *dstPtr = dst.imageData();
1086 uint srcRowSize = src.widthStepType();
1087
1088 if (direction == 0)
1089 {
1090 for (uint dstRow=0; dstRow<dstHeight; ++dstRow)
1091 {
1092 T const *srcPtr = src.imageData() + srcWidth-1 - dstRow;
1093 for (uint dstCol=0; dstCol<dstWidth; ++dstCol)
1094 {
1095 dstPtr[dstCol] = *srcPtr;
1096 srcPtr += srcRowSize;
1097 }
1098 dstPtr += dstRowSize;
1099 }
1100 }
1101 else
1102 {
1103 for (uint dstRow=0; dstRow<dstHeight; ++dstRow)
1104 {
1105 T const *srcPtr = src.imageData() + srcRowSize * (srcHeight-1)
1106 + dstRow;
1107 for (uint dstCol=0; dstCol<dstWidth; ++dstCol)
1108 {
1109 dstPtr[dstCol] = *srcPtr;
1110 srcPtr -= srcRowSize;
1111 }
1112 dstPtr += dstRowSize;
1113 }
1114 }
1115}
1116
1117// ****************************************************************************
1118// ****************************************************************************
1119
1120template<class T,class U>
1122{
1123public:
1124 uint channel;
1125 FimOpSetChannelT(uint a) : channel(a) {};
1126 void opBinary(T const &in,FimRgbaT<U> &out)
1127 {
1128 futConvert(in,out.c[channel]);
1129 }
1130};
1131
1132template<class T,class U>
1133inline void fimSetChannel(
1134
1135 FimRgbaE channel,
1136 const FimImgT<T> &src,
1137 FimImgT<FimRgbaT<U> > &dst)
1138{
1139 FGASSERT(channel < 4);
1140 dst.resize(src.width(),src.height()); // Only re-sizes if not already
1141 // of given size.
1142 fimLoopBinary(FimOpSetChannelT<T,U>(channel),src,dst);
1143}
1144
1145template<class T>
1147{
1148 public:
1149 uint channel;
1150 T val;
1151 FimOpSetChannelValT(uint c, T v) : channel(c), val(v) { }
1152 void opUnary(FimRgbaT<T> &pix)
1153 {
1154 pix.c[channel] = val;
1155 }
1156};
1157
1158template<class T>
1159inline void fimSetChannel(
1160
1161 FimRgbaE channel,
1162 T val,
1163 FimImgT< FimRgbaT<T> > &img)
1164{
1165 FGASSERT(channel < FIMRGBA_SIZE);
1166 fimLoopUnary(FimOpSetChannelValT<T>(channel,val),img);
1167}
1168
1169// ****************************************************************************
1170// ****************************************************************************
1171
1173{
1174 void opTernary(FimRgbaUbC &i1,FimRgbaUbC &i2,FimRgbaSbC &out)
1175 {
1176 out.c[FIMRGBA_R] = fgClampToSchar(int(out.c[FIMRGBA_R]) + int(i1.c[FIMRGBA_R]) - int(i2.c[FIMRGBA_R]));
1177 out.c[FIMRGBA_G] = fgClampToSchar(int(out.c[FIMRGBA_G]) + int(i1.c[FIMRGBA_G]) - int(i2.c[FIMRGBA_G]));
1178 out.c[FIMRGBA_B] = fgClampToSchar(int(out.c[FIMRGBA_B]) + int(i1.c[FIMRGBA_B]) - int(i2.c[FIMRGBA_B]));
1179 out.c[FIMRGBA_A] = 0;
1180 };
1181};
1182
1183inline void fimSubAcc(FimImgRgbaUbC &i1,FimImgRgbaUbC &i2,
1184 FimImgRgbaSbC &out)
1185{
1186 fimLoopTernary(FimSubAccOpS(),i1,i2,out);
1187}
1188
1189// ****************************************************************************
1190// ****************************************************************************
1191
1193{
1194 void
1195 opTernary(
1196 const FimRgbaFC & i1,
1197 const FimRgbaFC & i2,
1198 FimRgbaFC & out)
1199 {
1200 out.c[FIMRGBA_R] = i1.c[FIMRGBA_R] - i2.c[FIMRGBA_R];
1201 out.c[FIMRGBA_G] = i1.c[FIMRGBA_G] - i2.c[FIMRGBA_G];
1202 out.c[FIMRGBA_B] = i1.c[FIMRGBA_B] - i2.c[FIMRGBA_B];
1203 out.c[FIMRGBA_A] = 0.0f;
1204 }
1205};
1206
1207inline
1208void
1209fimSubtract(
1210 const FimImgRgbaFC & i1,
1211 const FimImgRgbaFC & i2,
1212 FimImgRgbaFC & out)
1213{
1214 fimLoopTernary(FimSubtractOpS(),i1,i2,out);
1215}
1216
1217// ****************************************************************************
1218// ****************************************************************************
1219
1220 // Fixed point interpolator for 32-bit 'int'.
1222{
1223public:
1224 ImageInterp(uint sourceWid,uint sourceHgt,uint destRatio) :
1225 wid(sourceWid), hgt(sourceHgt), ratio(destRatio) {};
1226 void setPoint(uint destX,uint destY)
1227 {
1228 uint yy = ((destY << 4) + 8) / ratio,
1229 xx = ((destX << 4) + 8) / ratio;
1230 int xhi = int((xx+8) & 0xFFFFFFF0), xlo = xhi - 16,
1231 yhi = int((yy+8) & 0xFFFFFFF0), ylo = yhi - 16;
1232 xlu = xlo < 0 ? 0 : xlo >> 4;
1233 ylu = ylo < 0 ? 0 : ylo >> 4;
1234 uint xht = xhi >> 4,
1235 yht = yhi >> 4;
1236 xhu = (xht >= wid) ? xlu : xht;
1237 yhu = (yht >= hgt) ? ylu : yht;
1238 xlw = xhi + 8 - xx; xhw = 16 - xlw,
1239 ylw = yhi + 8 - yy; yhw = 16 - ylw;
1240 yindl = wid * ylu;
1241 yindh = wid * yhu;
1242 }
1243 template<typename PixelType>
1244 typename PixelType::pixel_index_type
1245 getVal(const PixelType *srcImg,uint clr)
1246 {
1247 typedef typename PixelType::pixel_index_type pixel_index_t;
1248 uint val = srcImg[yindl+xlu].c[clr] * xlw * ylw +
1249 srcImg[yindl+xhu].c[clr] * xhw * ylw +
1250 srcImg[yindh+xlu].c[clr] * xlw * yhw +
1251 srcImg[yindh+xhu].c[clr] * xhw * yhw;
1252 return pixel_index_t(val >> 8);
1253 }
1254
1255private:
1256 uint wid, hgt;
1257 uint ratio;
1258 uint xlu,xhu,ylu,yhu;
1259 uint xlw,xhw,ylw,yhw;
1260 uint yindl,yindh;
1261};
1262
1263}
1264
1265#endif
T c[FIMRGBA_SIZE]
Definition fimRgba.hpp:38