SMIL  1.0.4
DImageTransform.hpp
1 /*
2  * Copyright (c) 2011-2016, Matthieu FAESSEL and ARMINES
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of Matthieu FAESSEL, or ARMINES nor the
14  * names of its contributors may be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #ifndef _D_IMAGE_TRANSFORM_HPP
31 #define _D_IMAGE_TRANSFORM_HPP
32 
33 #include "DBaseImageOperations.hpp"
34 #include "DLineArith.hpp"
35 
36 namespace smil
37 {
53  /*
54  * #### #### ##### # #
55  * # # # # # # # #
56  * # # # # # #
57  * # # # ##### #
58  * # # # # # #
59  * #### #### # #
60  */
61 
83  template <class T1, class T2>
84  RES_T copy(const Image<T1> &imIn, size_t startX, size_t startY, size_t startZ,
85  size_t sizeX, size_t sizeY, size_t sizeZ, Image<T2> &imOut,
86  size_t outStartX = 0, size_t outStartY = 0, size_t outStartZ = 0)
87  {
88  ASSERT_ALLOCATED(&imIn, &imOut);
89 
90  size_t inW = imIn.getWidth();
91  size_t inH = imIn.getHeight();
92  size_t inD = imIn.getDepth();
93 
94  size_t outW = imOut.getWidth();
95  size_t outH = imOut.getHeight();
96  size_t outD = imOut.getDepth();
97 
98  ASSERT(startX < inW && startY < inH && startZ < inD);
99  ASSERT(outStartX < outW && outStartY < outH && outStartZ < outD);
100 
101  size_t realSx = min(min(sizeX, inW - startX), outW - outStartX);
102  size_t realSy = min(min(sizeY, inH - startY), outH - outStartY);
103  size_t realSz = min(min(sizeZ, inD - startZ), outD - outStartZ);
104 
105  typename Image<T1>::volType slIn = imIn.getSlices() + startZ;
106  typename Image<T2>::volType slOut = imOut.getSlices() + outStartZ;
107 
108  // size_t y;
109 
110  for (size_t z = 0; z < realSz; z++) {
111  typename Image<T1>::sliceType lnIn = *slIn + startY;
112  typename Image<T2>::sliceType lnOut = *slOut + outStartY;
113 
114 #ifdef USE_OPEN_MP
115  int nthreads = Core::getInstance()->getNumberOfThreads();
116 // #pragma omp parallel private(y)
117 #endif // USE_OPEN_MP
118  {
119 #ifdef USE_OPEN_MP
120 #pragma omp for schedule(dynamic, nthreads) nowait
121 #endif // USE_OPEN_MP
122  for (size_t y = 0; y < realSy; y++)
123  copyLine<T1, T2>(lnIn[y] + startX, realSx, lnOut[y] + outStartX);
124  }
125 
126  slIn++;
127  slOut++;
128  }
129 
130  imOut.modified();
131  return RES_OK;
132  }
133 
141  template <class T1, class T2>
142  RES_T copy(const Image<T1> &imIn, size_t startX, size_t startY, size_t sizeX,
143  size_t sizeY, Image<T2> &imOut, size_t outStartX = 0,
144  size_t outStartY = 0, size_t outStartZ = 0)
145  {
146  return copy(imIn, startX, startY, 0, sizeX, sizeY, 1, imOut, outStartX,
147  outStartY, outStartZ);
148  }
149 
159  template <class T1, class T2>
160  RES_T copy(const Image<T1> &imIn, size_t startX, size_t startY, size_t startZ,
161  Image<T2> &imOut, size_t outStartX = 0, size_t outStartY = 0,
162  size_t outStartZ = 0)
163  {
164  return copy(imIn, startX, startY, startZ, imIn.getWidth(), imIn.getHeight(),
165  imIn.getDepth(), imOut, outStartX, outStartY, outStartZ);
166  }
167 
176  template <class T1, class T2>
177  RES_T copy(const Image<T1> &imIn, size_t startX, size_t startY,
178  Image<T2> &imOut, size_t outStartX = 0, size_t outStartY = 0,
179  size_t outStartZ = 0)
180  {
181  return copy(imIn, startX, startY, 0, imIn.getWidth(), imIn.getHeight(), 1,
182  imOut, outStartX, outStartY, outStartZ);
183  }
184 
193  template <class T1, class T2>
194  RES_T copy(const Image<T1> &imIn, Image<T2> &imOut, size_t outStartX,
195  size_t outStartY, size_t outStartZ = 0)
196  {
197  return copy(imIn, 0, 0, 0, imIn.getWidth(), imIn.getHeight(),
198  imIn.getDepth(), imOut, outStartX, outStartY, outStartZ);
199  }
200 
201  // Copy/cast two images with different types but same size (quick way)
213  template <class T1, class T2>
214  RES_T copy(const Image<T1> &imIn, Image<T2> &imOut)
215  {
216  // Swig is (surprisingly;)) lost with overloads of template functions, so we
217  // try to reorient him
218  if (typeid(imIn) == typeid(imOut))
219  return copy(imIn, imOut);
220 
221  ASSERT_ALLOCATED(&imIn, &imOut);
222 
223  if (!haveSameSize(&imIn, &imOut, NULL))
224  return copy<T1, T2>(imIn, 0, 0, 0, imOut, 0, 0, 0);
225 
226  copyLine<T1, T2>(imIn.getPixels(), imIn.getPixelCount(), imOut.getPixels());
227 
228  imOut.modified();
229  return RES_OK;
230  }
231 
241  template <class T>
242  RES_T copy(const Image<T> &imIn, Image<T> &imOut)
243  {
244  ASSERT_ALLOCATED(&imIn, &imOut);
245 
246  imOut.setSize(imIn);
247 
248  return unaryImageFunction<T, fillLine<T>>(imIn, imOut).retVal;
249  }
250 
264  template <class T>
265  RES_T clone(const Image<T> &imIn, Image<T> &imOut)
266  {
267  ASSERT_ALLOCATED(&imIn);
268 
269  ASSERT((imOut.setSize(imIn) == RES_OK));
270  return copy<T>(imIn, imOut);
271  }
272 
273  /*
274  * #### ##### #### #####
275  * # # # # # # # #
276  * # # # # # # #
277  * # ##### # # #####
278  * # # # # # # #
279  * #### # # #### #
280  */
297  template <class T>
298  RES_T crop(const Image<T> &imIn, size_t startX, size_t startY, size_t startZ,
299  size_t sizeX, size_t sizeY, size_t sizeZ, Image<T> &imOut)
300  {
301  ASSERT_ALLOCATED(&imIn);
302 
303  size_t inW = imIn.getWidth();
304  size_t inH = imIn.getHeight();
305  size_t inD = imIn.getDepth();
306 
307  size_t realSx = min(sizeX, inW - startX);
308  size_t realSy = min(sizeY, inH - startY);
309  size_t realSz = min(sizeZ, inD - startZ);
310 
311  imOut.setSize(realSx, realSy, realSz);
312  return copy(imIn, startX, startY, startZ, realSx, realSy, realSz, imOut, 0,
313  0, 0);
314  }
315 
327  template <class T>
328  RES_T crop(Image<T> &imInOut, size_t startX, size_t startY, size_t startZ,
329  size_t sizeX, size_t sizeY, size_t sizeZ)
330  {
331  Image<T> tmpIm(imInOut, true); // clone
332  return crop(tmpIm, startX, startY, startZ, sizeX, sizeY, sizeZ, imInOut);
333  }
334 
335  // 2D overload
348  template <class T>
349  RES_T crop(const Image<T> &imIn, size_t startX, size_t startY, size_t sizeX,
350  size_t sizeY, Image<T> &imOut)
351  {
352  return crop(imIn, startX, startY, 0, sizeX, sizeY, 1, imOut);
353  }
354 
367  template <class T>
368  RES_T crop(Image<T> &imInOut, size_t startX, size_t startY, size_t sizeX,
369  size_t sizeY)
370  {
371  return crop(imInOut, startX, startY, 0, sizeX, sizeY, 1);
372  }
373 
374  /*
375  * ## ##### ##### ##### #### ##### ##### ###### #####
376  * # # # # # # # # # # # # # # # # #
377  * # # # # # # ##### # # # # # # ##### # #
378  * ###### # # # # # # # # ##### # # # #####
379  * # # # # # # # # # # # # # # # # #
380  * # # ##### ##### ##### #### # # ##### ###### # #
381  */
394  template <class T>
395  RES_T addBorder(const Image<T> &imIn, const size_t &bSize, Image<T> &imOut,
396  const T &borderValue = ImDtTypes<T>::max())
397  {
398  ASSERT_ALLOCATED(&imIn)
399 
400  if (&imIn == &imOut) {
401  Image<T> tmpIm(imIn, true); // clone
402  return addBorder(tmpIm, bSize, imOut, borderValue);
403  }
404 
405  ImageFreezer freeze(imOut);
406 
407  size_t s[3];
408  imIn.getSize(s);
409 
410  if (imIn.getDimension() == 3) {
411  imOut.setSize(s[0] + 2 * bSize, s[1] + 2 * bSize, s[2] + 2 * bSize);
412  ASSERT_ALLOCATED(&imOut)
413  fill(imOut, borderValue);
414  copy(imIn, 0, 0, 0, s[0], s[1], s[2], imOut, bSize, bSize, bSize);
415  } else {
416  imOut.setSize(s[0] + 2 * bSize, s[1] + 2 * bSize, 1);
417  ASSERT_ALLOCATED(&imOut)
418  fill(imOut, borderValue);
419  copy(imIn, 0, 0, s[0], s[1], imOut, bSize, bSize);
420  }
421  return RES_OK;
422  }
433  /*
434  * ###### # # #####
435  * # # # # #
436  * ##### # # # #
437  * # # # #####
438  * # # # #
439  * # ###### # #
440  */
445  template <class T> class FlipClassFunc
446  {
447  private:
448  void copyReverse(T *in, size_t width, T *out)
449  {
450  for (size_t i = 0; i < width; i++)
451  out[i] = in[width - 1 - i];
452  }
453 
454  public:
455  RES_T flipIt(Image<T> &imIn, Image<T> &imOut, string direction)
456  {
457  ASSERT_ALLOCATED(&imIn, &imOut);
458  ASSERT_SAME_SIZE(&imIn, &imOut);
459 
460  if (&imIn == &imOut) {
461  Image<T> imTmp = Image<T>(imIn, true);
462  return flipIt(imTmp, imOut, direction);
463  }
464 
465  bool vflip = (direction == "vertical");
466 
467  typename Image<T>::sliceType *slicesIn = imIn.getSlices();
468  typename Image<T>::sliceType *slicesOut = imOut.getSlices();
469 
470  size_t width = imIn.getWidth();
471  size_t height = imIn.getHeight();
472  size_t depth = imIn.getDepth();
473 
474  ImageFreezer freeze(imOut);
475 #ifdef USE_OPEN_MP
476  int nthreads = Core::getInstance()->getNumberOfThreads();
477 #pragma omp parallel for num_threads(nthreads)
478 #endif // USE_OPEN_MP
479  for (size_t k = 0; k < depth; k++) {
480  typename Image<T>::sliceType linesIn;
481  typename Image<T>::sliceType linesOut;
482  linesIn = slicesIn[k];
483  linesOut = slicesOut[k];
484 
485  if (vflip)
486  for (size_t j = 0; j < height; j++)
487  copyLine<T>(linesIn[j], width, linesOut[height - 1 - j]);
488  else
489  for (size_t j = 0; j < height; j++)
490  copyReverse(linesIn[j], width, linesOut[j]);
491  }
492 
493  return RES_OK;
494  }
495  };
507  template <class T> RES_T vertFlip(Image<T> &imIn, Image<T> &imOut)
508  {
509  string direction = "vertical";
510  FlipClassFunc<T> flip;
511  return flip.flipIt(imIn, imOut, "vertical");
512  }
513 
521  template <class T> RES_T vertFlip(Image<T> &im)
522  {
523  return vertFlip(im, im);
524  }
525 
535  template <class T> RES_T horizFlip(Image<T> &imIn, Image<T> &imOut)
536  {
537  string direction = "horizontal";
538  FlipClassFunc<T> flip;
539  return flip.flipIt(imIn, imOut, direction);
540  }
541 
549  template <class T> RES_T horizFlip(Image<T> &im)
550  {
551  return horizFlip(im, im);
552  }
553 
554  /*
555  * ##### #### ##### ## ##### ######
556  * # # # # # # # # #
557  * # # # # # # # # #####
558  * ##### # # # ###### # #
559  * # # # # # # # # #
560  * # # #### # # # # ######
561  */
563  template <class T> class ImageRotateFunct
564  {
565  public:
566  ImageRotateFunct()
567  {
568  }
569 
570  ~ImageRotateFunct()
571  {
572  }
573 
574  RES_T Rotate(Image<T> &imIn, int count, Image<T> &imOut)
575  {
576  count = count % 4;
577 
578  return RotateX90(imIn, count, imOut);
579  }
580 
581  private:
582  RES_T RotateX90(Image<T> &imIn, int count, Image<T> &imOut)
583  {
584  ASSERT_ALLOCATED(&imIn, &imOut);
585 
586  count = count % 4;
587  int angle = count * 90;
588 
589  if (angle == 0) {
590  ImageFreezer freeze(imOut);
591  return copy(imIn, imOut);
592  }
593 
594  off_t w = imIn.getWidth();
595  off_t h = imIn.getHeight();
596  off_t d = imIn.getDepth();
597 
598  /* 90 and 270 degres */
599  if (angle == 90 || angle == 270) {
600  imOut.setSize(h, w, d);
601  } else {
602  imOut.setSize(w, h, d);
603  }
604 
605  ImageFreezer freeze(imOut);
606 
607  typedef typename ImDtTypes<T>::lineType lineType;
608  lineType pixIn = imIn.getPixels();
609  lineType pixOut = imOut.getPixels();
610 
611  switch (angle) {
612  case 90:
613 #ifdef USE_OPEN_MP
614 #pragma omp parallel for
615 #endif // USE_OPEN_MP
616  for (off_t k = 0; k < d; k++) {
617  off_t offset = k * w * h;
618  T *sIn = (T *) (pixIn + offset);
619  T *sOut = (T *) (pixOut + offset);
620  for (off_t j = 0; j < h; j++) {
621  for (off_t i = 0; i < w; i++) {
622  sOut[i * h + (w - 1 - j)] = sIn[j * w + i];
623  }
624  }
625  }
626  break;
627  case 180:
628 #ifdef USE_OPEN_MP
629 #pragma omp parallel for
630 #endif // USE_OPEN_MP
631  for (off_t k = 0; k < d; k++) {
632  off_t offset = k * w * h;
633  T *sIn = (T *) (pixIn + offset);
634  T *sOut = (T *) (pixOut + offset);
635  for (off_t j = 0; j < h; j++) {
636  for (off_t i = 0; i < w; i++) {
637  sOut[(h - 1 - j) * w + (w - 1 - i)] = sIn[j * w + i];
638  }
639  }
640  }
641  break;
642  case 270:
643 #ifdef USE_OPEN_MP
644 #pragma omp parallel for
645 #endif // USE_OPEN_MP
646  for (off_t k = 0; k < d; k++) {
647  off_t offset = k * w * h;
648  T *sIn = (T *) (pixIn + offset);
649  T *sOut = (T *) (pixOut + offset);
650  for (off_t j = 0; j < h; j++) {
651  for (off_t i = 0; i < w; i++) {
652  sOut[(w - 1 - i) * h + j] = sIn[j * w + i];
653  }
654  }
655  }
656  break;
657  default:
658  break;
659  }
660 
661  imOut.modified();
662  return RES_OK;
663  }
664  };
684  template <class T> RES_T rotateX90(Image<T> &imIn, int count, Image<T> &imOut)
685  {
686  ImageRotateFunct<T> imr;
687 
688  if (&imIn == &imOut) {
689  Image<T> imTmp(imIn, true);
690  return imr.Rotate(imTmp, count, imOut);
691  }
692 
693  return imr.Rotate(imIn, count, imOut);
694  }
695 
704  template <class T> RES_T rotateX90(Image<T> &im, int count)
705  {
706  return rotateX90(im, count, im);
707  }
708 
709  /*
710  * ##### ##### ## # # #### # ## ##### ######
711  * # # # # # ## # # # # # # #
712  * # # # # # # # # #### # # # # #####
713  * # ##### ###### # # # # # ###### # #
714  * # # # # # # ## # # # # # # #
715  * # # # # # # # #### ###### # # # ######
716  */
725  template <class T>
726  RES_T translate(const Image<T> &imIn, int dx, int dy, int dz, Image<T> &imOut,
727  T borderValue = ImDtTypes<T>::min())
728  {
729  ASSERT_ALLOCATED(&imIn)
730  ASSERT_SAME_SIZE(&imIn, &imOut)
731 
732  size_t lineLen = imIn.getWidth();
733  typename ImDtTypes<T>::lineType borderBuf =
734  ImDtTypes<T>::createLine(lineLen);
735  fillLine<T>(borderBuf, lineLen, borderValue);
736 
737  size_t height = imIn.getHeight();
738  size_t depth = imIn.getDepth();
739 
740  for (size_t k = 0; k < depth; k++) {
741  typename Image<T>::sliceType lOut = imOut.getSlices()[k];
742 
743  int z = k - dz;
744  for (size_t j = 0; j < height; j++, lOut++) {
745  int y = j - dy;
746 
747  if (z < 0 || z >= (int) depth || y < 0 || y >= (int) height)
748  copyLine<T>(borderBuf, lineLen, *lOut);
749  else
750  shiftLine<T>(imIn.getSlices()[z][y], dx, lineLen, *lOut, borderValue);
751  }
752  }
753 
754  ImDtTypes<T>::deleteLine(borderBuf);
755 
756  imOut.modified();
757 
758  return RES_OK;
759  }
760 
769  template <class T>
770  ResImage<T> translate(const Image<T> &imIn, int dx, int dy, int dz)
771  {
772  ResImage<T> imOut(imIn);
773  translate<T>(imIn, dx, dy, dz, imOut);
774  return imOut;
775  }
776 
787  template <class T>
788  RES_T translate(const Image<T> &imIn, int dx, int dy, Image<T> &imOut,
789  T borderValue = ImDtTypes<T>::min())
790  {
791  return translate<T>(imIn, dx, dy, 0, imOut, borderValue);
792  }
793 
801  template <class T> ResImage<T> translate(const Image<T> &imIn, int dx, int dy)
802  {
803  ResImage<T> imOut(imIn);
804  translate<T>(imIn, dx, dy, 0, imOut);
805  return imOut;
806  }
807 
818  /*
819  * ##### ###### #### # ###### ######
820  * # # # # # # #
821  * # # ##### #### # # #####
822  * ##### # # # # #
823  * # # # # # # # #
824  * # # ###### #### # ###### ######
825  */
829  template <class T> class ImageResizeFunc
830  {
831  public:
832  ImageResizeFunc(string method)
833  {
834  if (method != "linear" && method != "trilinear" && method != "closest")
835  this->method = "trilinear";
836  else
837  this->method = method;
838  }
839 
840  ImageResizeFunc()
841  {
842  method = "trilinear";
843  }
844 
845  ~ImageResizeFunc()
846  {
847  }
848 
849  /*
850  * Public resize members
851  */
852  RES_T resize(Image<T> &imIn, size_t width, size_t height, size_t depth,
853  Image<T> &imOut, string method = "trilinear")
854  {
855  ASSERT_ALLOCATED(&imIn, &imOut)
856  if (&imIn == &imOut) {
857  Image<T> tmpIm(imIn, true);
858  return resize(tmpIm, width, height, depth, imIn);
859  }
860 
861  size_t dz = imIn.getDepth();
862  if (method == "auto") {
863  if (isBinary(imIn))
864  method = "closest";
865  else
866  method = dz > 1 ? "trilinear" : "bilinear";
867  }
868 
869  if (method == "closest") {
870  if (dz > 1)
871  return resize3DClosest(imIn, width, height, depth, imOut);
872  else
873  return resize2DClosest(imIn, width, height, imOut);
874  }
875 
876  if (method == "bilinear" || method == "trilinear") {
877  if (dz > 1)
878  return resizeTrilinear(imIn, width, height, depth, imOut);
879  else
880  return resizeBilinear(imIn, width, height, imOut);
881  }
882  ERR_MSG("* Unknown method " + method);
883  return RES_ERR;
884  }
885 
886  RES_T resize(Image<T> &imIn, size_t width, size_t height, Image<T> &imOut,
887  string method = "trilinear")
888  {
889  ASSERT_ALLOCATED(&imIn, &imOut)
890 
891  size_t depth = imIn.getDepth();
892  return resize(imIn, width, height, depth, imOut, method);
893  }
894 
895  /*
896  * Public scale member
897  */
898  RES_T scale(Image<T> &imIn, double kx, double ky, double kz,
899  Image<T> &imOut, string method = "trilinear")
900  {
901  ASSERT_ALLOCATED(&imIn, &imOut)
902 
903  if (&imIn == &imOut) {
904  Image<T> tmpIm(imIn, true);
905  return scale(tmpIm, kx, ky, kz, imIn);
906  }
907 
908  size_t width = imIn.getWidth();
909  size_t height = imIn.getHeight();
910  size_t depth = imIn.getDepth();
911 
912  if (width > 1)
913  width = max(1L, lround(kx * width));
914  if (height > 1)
915  height = max(1L, lround(ky * height));
916  if (depth > 1)
917  depth = max(1L, lround(kz * depth));
918 
919  return resize(imIn, width, height, depth, imOut, method);
920  }
921 
922  RES_T scale(Image<T> &imIn, size_t kx, size_t ky, Image<T> &imOut,
923  string method = "trilinear")
924  {
925  return scale(imIn, kx, ky, 1., imOut, method);
926  }
927 
928  private:
929  /*
930  * #### # #### #### ###### #### #####
931  * # # # # # # # # #
932  * # # # # #### ##### #### #
933  * # # # # # # # #
934  * # # # # # # # # # # #
935  * #### ###### #### #### ###### #### #
936  */
937  /*
938  * 2D - closest interpolation method - naive loop implementation
939  */
940  RES_T resize2DClosest(Image<T> &imIn, size_t sx, size_t sy, Image<T> &imOut)
941  {
942  size_t width = imIn.getWidth();
943  size_t height = imIn.getHeight();
944  size_t depth = imIn.getDepth();
945 
946  if (depth > 1) {
947  return resize3DClosest(imIn, sx, sy, depth, imOut);
948  }
949 
950  imOut.setSize(sx, sy, 1);
951  ImageFreezer freeze(imOut);
952 
953  double cx = ((double) (width - 1)) / (sx - 1);
954  double cy = ((double) (height - 1)) / (sy - 1);
955 
956  T *pixIn = imIn.getPixels();
957  T *pixOut = imOut.getPixels();
958 
959  for (size_t j = 0; j < sy; j++) {
960 #ifdef USE_OPEN_MP
961  int nthreads = Core::getInstance()->getNumberOfThreads();
962 #pragma omp parallel for num_threads(nthreads)
963 #endif // USE_OPEN_MP
964  for (size_t i = 0; i < sx; i++) {
965  size_t xo = round(cx * i);
966  size_t yo = round(cy * j);
967 
968  xo = min(xo, width - 1);
969  yo = min(yo, height - 1);
970 
971  T v = pixIn[yo * width + xo];
972  pixOut[j * sx + i] = v;
973  }
974  }
975 
976  return RES_OK;
977  }
978 
979  /*
980  * 3D - closest interpolation method - naive loop implementation
981  */
982  RES_T resize3DClosest(Image<T> &imIn, size_t sx, size_t sy, size_t sz,
983  Image<T> &imOut)
984  {
985  size_t width = imIn.getWidth();
986  size_t height = imIn.getHeight();
987  size_t depth = imIn.getDepth();
988 
989  if (depth > 1) {
990  return resize2DClosest(imIn, sx, sy, imOut);
991  }
992  imOut.setSize(sx, sy, sz);
993 
994  ImageFreezer freeze(imOut);
995 
996  double cx = ((double) (width - 1)) / (sx - 1);
997  double cy = ((double) (height - 1)) / (sy - 1);
998  double cz = ((double) (depth - 1)) / (sz - 1);
999 
1000  T *pixIn = imIn.getPixels();
1001  T *pixOut = imOut.getPixels();
1002 
1003  for (size_t k = 0; k < sz; k++) {
1004  for (size_t j = 0; j < sy; j++) {
1005 #ifdef USE_OPEN_MP
1006  int nthreads = Core::getInstance()->getNumberOfThreads();
1007 #pragma omp parallel for num_threads(nthreads)
1008 #endif // USE_OPEN_MP
1009  for (size_t i = 0; i < sx; i++) {
1010  size_t xo = round(cx * i);
1011  size_t yo = round(cy * j);
1012  size_t zo = round(cz * k);
1013 
1014  xo = min(xo, width - 1);
1015  yo = min(yo, height - 1);
1016  zo = min(zo, depth - 1);
1017 
1018  T v = pixIn[(zo * depth + yo) * width + xo];
1019  pixOut[(k * sy + j) * sx + i] = v;
1020  }
1021  }
1022  }
1023  return RES_OK;
1024  }
1025 
1026  /*
1027  * # # # # ###### ## # ##### ######
1028  * # # ## # # # # # # # #
1029  * # # # # # ##### # # # # # #####
1030  * # # # # # # ###### # ##### #
1031  * # # # ## # # # # # # #
1032  * ###### # # # ###### # # # # # ######
1033  */
1034  /*
1035  * 2D - Bilinear interpolation method - naive loop implementation
1036  */
1037  RES_T resizeBilinear(Image<T> &imIn, size_t sx, size_t sy, Image<T> &imOut)
1038  {
1039  off_t width = imIn.getWidth();
1040  off_t height = imIn.getHeight();
1041  off_t depth = imIn.getDepth();
1042 
1043  if (depth > 1) {
1044  return resizeTrilinear(imIn, sx, sy, depth, imOut);
1045  }
1046 
1047  imOut.setSize(sx, sy, 1);
1048  ImageFreezer freeze(imOut);
1049 
1050  double cx = ((double) (width - 1)) / (sx - 1);
1051  double cy = ((double) (height - 1)) / (sy - 1);
1052 
1053  T *pixIn = imIn.getPixels();
1054  T *pixOut = imOut.getPixels();
1055 
1056  for (size_t j = 0; j < sy; j++) {
1057  off_t dy = width;
1058 #ifdef USE_OPEN_MP
1059  int nthreads = Core::getInstance()->getNumberOfThreads();
1060 #pragma omp parallel for num_threads(nthreads)
1061 #endif
1062  for (size_t i = 0; i < sx; i++) {
1063  Point<double> P(cx * i, cy * j, 0);
1064 
1065  off_t xl = (off_t) floor(P.x);
1066  off_t xh = (xl + 1) < width ? xl + 1 : xl;
1067  off_t yl = (off_t) floor(P.y);
1068  off_t yh = (yl + 1) < height ? yl + 1 : yl;
1069 
1070  double cxl = xh > xl ? (P.x - xl) : 1.;
1071  double cxh = 1. - cxl;
1072  double cyl = yh > yl ? (P.y - yl) : 1.;
1073  double cyh = 1. - cyl;
1074 
1075  T vp = pixIn[yl * dy + xl] * cxh * cyh +
1076  pixIn[yl * dy + xh] * cxl * cyh +
1077  pixIn[yh * dy + xl] * cxh * cyl +
1078  pixIn[yh * dy + xh] * cxl * cyl;
1079 
1080  pixOut[j * sx + i] = vp;
1081  }
1082  }
1083  return RES_OK;
1084  }
1085 
1086  /*
1087  * 3D - Trilinear interpolation method - naive loop implementation
1088  */
1089  RES_T resizeTrilinear(Image<T> &imIn, size_t sx, size_t sy, size_t sz,
1090  Image<T> &imOut)
1091  {
1092  off_t width = imIn.getWidth();
1093  off_t height = imIn.getHeight();
1094  off_t depth = imIn.getDepth();
1095 
1096  if (depth == 1) {
1097  return resizeBilinear(imIn, sx, sy, imOut);
1098  }
1099 
1100  imOut.setSize(sx, sy, sz);
1101  ImageFreezer freeze(imOut);
1102 
1103  double cx = ((double) (width - 1)) / (sx - 1);
1104  double cy = ((double) (height - 1)) / (sy - 1);
1105  double cz = ((double) (depth - 1)) / (sz - 1);
1106 
1107  T *pixIn = imIn.getPixels();
1108  T *pixOut = imOut.getPixels();
1109 
1110  for (size_t k = 0; k < sz; k++) {
1111  off_t dz = width * height;
1112  for (size_t j = 0; j < sy; j++) {
1113  off_t dy = width;
1114 #ifdef USE_OPEN_MP
1115  int nthreads = Core::getInstance()->getNumberOfThreads();
1116 #pragma omp parallel for num_threads(nthreads)
1117 #endif
1118  for (size_t i = 0; i < sx; i++) {
1119  Point<double> P(cx * i, cy * j, cz * k);
1120 
1121  off_t xl = floor(P.x);
1122  off_t xh = (xl + 1) < width ? xl + 1 : xl;
1123  off_t yl = floor(P.y);
1124  off_t yh = (yl + 1) < height ? yl + 1 : yl;
1125  off_t zl = floor(P.z);
1126  off_t zh = (zl + 1) < depth ? zl + 1 : zl;
1127 
1128  double cxl = xh > xl ? (P.x - xl) : 1.;
1129  double cxh = 1. - cxl;
1130  double cyl = yh > yl ? (P.y - yl) : 1.;
1131  double cyh = 1. - cyl;
1132  double czl = zh > zl ? (P.z - zl) : 1.;
1133  double czh = 1. - czl;
1134 
1135  T vp = pixIn[zl * dz + yl * dy + xl] * cxh * cyh * czh +
1136  pixIn[zl * dz + yl * dy + xh] * cxl * cyh * czh +
1137  pixIn[zl * dz + yh * dy + xl] * cxh * cyl * czh +
1138  pixIn[zl * dz + yh * dy + xh] * cxl * cyl * czh +
1139  pixIn[zh * dz + yl * dy + xl] * cxh * cyh * czl +
1140  pixIn[zh * dz + yl * dy + xh] * cxl * cyh * czl +
1141  pixIn[zh * dz + yh * dy + xl] * cxh * cyl * czl +
1142  pixIn[zh * dz + yh * dy + xh] * cxl * cyl * czl;
1143 
1144  pixOut[(k * sy + j) * sx + i] = vp;
1145  }
1146  }
1147  }
1148  return RES_OK;
1149  }
1150 
1151  string method;
1152  };
1179  template <typename T>
1180  RES_T resize(Image<T> &imIn, size_t sx, size_t sy, size_t sz,
1181  Image<T> &imOut, string method = "trilinear")
1182  {
1183  ASSERT_ALLOCATED(&imIn, &imOut)
1184  ImageResizeFunc<T> func(method);
1185  return func.resize(imIn, sx, sy, sz, imOut, method);
1186  }
1187 
1201  template <typename T>
1202  RES_T resize(Image<T> &imIn, size_t sx, size_t sy, Image<T> &imOut,
1203  string method = "trilinear")
1204  {
1205  ASSERT_ALLOCATED(&imIn, &imOut)
1206  size_t depth = imOut.getDepth();
1207 
1208  ImageResizeFunc<T> func(method);
1209  return func.resize(imIn, sx, sy, depth, imOut, method);
1210  }
1211 
1226  template <typename T>
1227  RES_T resize(Image<T> &imIn, Image<T> &imOut,
1228  string method = "trilinear")
1229  {
1230  ASSERT_ALLOCATED(&imIn, &imOut)
1231  size_t width = imOut.getWidth();
1232  size_t height = imOut.getHeight();
1233  size_t depth = imOut.getDepth();
1234 
1235  ImageResizeFunc<T> func(method);
1236  return func.resize(imIn, width, height, depth, imOut, method);
1237  }
1238 
1264  template <typename T>
1265  RES_T scale(Image<T> &imIn, double kx, double ky, double kz,
1266  Image<T> &imOut, string method = "trilinear")
1267  {
1268  ASSERT_ALLOCATED(&imIn, &imOut)
1269  ImageResizeFunc<T> func(method);
1270  return func.scale(imIn, kx, ky, kz, imOut, method);
1271  }
1272 
1285  template <typename T>
1286  RES_T scale(Image<T> &imIn, double kx, double ky, Image<T> &imOut,
1287  string method = "trilinear")
1288  {
1289  ASSERT_ALLOCATED(&imIn, &imOut)
1290  ImageResizeFunc<T> func(method);
1291  return func.scale(imIn, kx, ky, 1., imOut, method);
1292  }
1293 
1307  template <typename T>
1308  RES_T scale(Image<T> &imIn, double k, Image<T> &imOut,
1309  string method = "trilinear")
1310  {
1311  ASSERT_ALLOCATED(&imIn, &imOut)
1312  ImageResizeFunc<T> func(method);
1313  return func.scale(imIn, k, k, k, imOut, method);
1314  }
1315 
1316 
1317 #if 0
1326  template <class T>
1327  RES_T resizeClosest(Image<T> &imIn, size_t sx, size_t sy, Image<T> &imOut)
1328  {
1329  ASSERT_ALLOCATED(&imIn)
1330 
1331  if (&imIn == &imOut) {
1332  Image<T> tmpIm(imIn, true); // clone
1333  return resizeClosest(tmpIm, sx, sy, imIn);
1334  }
1335 
1336  ImageFreezer freeze(imOut);
1337 
1338  imOut.setSize(sx, sy);
1339 
1340  ASSERT_ALLOCATED(&imOut)
1341 
1342  size_t w = imIn.getWidth();
1343  size_t h = imIn.getHeight();
1344 
1345  typedef typename Image<T>::lineType lineType;
1346 
1347  lineType pixIn = imIn.getPixels();
1348  lineType pixOut = imOut.getPixels();
1349 
1350  size_t A, B, C, D, maxVal = numeric_limits<T>::max();
1351  size_t x, y, index;
1352 
1353  double x_ratio = ((double) (w)) / sx; // BMI -1 removed
1354  double y_ratio = ((double) (h)) / sy; // BMI -1 removed
1355  double x_diff, y_diff;
1356  int offset = 0;
1357 
1358  for (size_t i = 0; i < sy; i++) {
1359  for (size_t j = 0; j < sx; j++) {
1360  x = (int) (x_ratio * j);
1361  y = (int) (y_ratio * i);
1362  x_diff = (x_ratio * j) - x;
1363  y_diff = (y_ratio * i) - y;
1364  index = y * w + x;
1365 
1366  A = size_t(pixIn[index]) & maxVal;
1367  if (x == w - 1) {
1368  B = size_t(pixIn[index]) & maxVal;
1369  } else {
1370  B = size_t(pixIn[index + 1]) & maxVal;
1371  }
1372  if (y < h - 1) {
1373  C = size_t(pixIn[index + w]) & maxVal;
1374  } else {
1375  C = size_t(pixIn[index]) & maxVal;
1376  }
1377  size_t myindex;
1378  myindex = index;
1379  if (y < h - 1)
1380  myindex += w;
1381  if (x < w - 1)
1382  myindex += 1;
1383  D = size_t(pixIn[myindex]) & maxVal;
1384 
1385  // Y = A(1-w)(1-h) + B(w)(1-h) + C(h)(1-w) + Dwh
1386  if ((x_diff < 0.5) && (y_diff < 0.5)) {
1387  pixOut[offset++] = A;
1388  } else if (x_diff < 0.5) {
1389  pixOut[offset++] = C;
1390  } else if (y_diff < 0.5) {
1391  pixOut[offset++] = B;
1392  } else {
1393  pixOut[offset++] = D;
1394  }
1395  }
1396  }
1397 
1398  return RES_OK;
1399  }
1400 
1405  template <class T> RES_T resizeClosest(Image<T> &imIn, Image<T> &imOut)
1406  {
1407  return resizeClosest(imIn, imOut.getWidth(), imOut.getHeight(), imOut);
1408  }
1409 
1413  template <class T> RES_T resizeClosest(Image<T> &imIn, UINT sx, UINT sy)
1414  {
1415  ASSERT_ALLOCATED(&imIn)
1416  Image<T> tmpIm(imIn, true); // clone
1417  imIn.setSize(sx, sy);
1418  return resizeClosest<T>(tmpIm, imIn);
1419  }
1420 
1428  template <class T>
1429  RES_T resize(Image<T> &imIn, size_t sx, size_t sy, Image<T> &imOut)
1430  {
1431  ASSERT_ALLOCATED(&imIn)
1432 
1433  if (&imIn == &imOut) {
1434  Image<T> tmpIm(imIn, true); // clone
1435  return resize(tmpIm, sx, sy, imIn);
1436  }
1437 
1438  ImageFreezer freeze(imOut);
1439 
1440  imOut.setSize(sx, sy);
1441 
1442  ASSERT_ALLOCATED(&imOut)
1443 
1444  size_t w = imIn.getWidth();
1445  size_t h = imIn.getHeight();
1446 
1447  typedef typename Image<T>::lineType lineType;
1448 
1449  lineType pixIn = imIn.getPixels();
1450  lineType pixOut = imOut.getPixels();
1451 
1452  size_t A, B, C, D, maxVal = numeric_limits<T>::max();
1453  size_t x, y, index;
1454 
1455  double x_ratio = ((double) (w - 1)) / sx;
1456  double y_ratio = ((double) (h - 1)) / sy;
1457  double x_diff, y_diff;
1458  int offset = 0;
1459 
1460  for (size_t i = 0; i < sy; i++) {
1461  for (size_t j = 0; j < sx; j++) {
1462  x = (int) (x_ratio * j);
1463  y = (int) (y_ratio * i);
1464  x_diff = (x_ratio * j) - x;
1465  y_diff = (y_ratio * i) - y;
1466  index = y * w + x;
1467 
1468  A = size_t(pixIn[index]) & maxVal;
1469  B = size_t(pixIn[index + 1]) & maxVal;
1470  C = size_t(pixIn[index + w]) & maxVal;
1471  D = size_t(pixIn[index + w + 1]) & maxVal;
1472 
1473  // Y = A(1-w)(1-h) + B(w)(1-h) + C(h)(1-w) + Dwh
1474  pixOut[offset++] =
1475  T(A * (1. - x_diff) * (1. - y_diff) + B * (x_diff) * (1. - y_diff) +
1476  C * (y_diff) * (1. - x_diff) + D * (x_diff * y_diff));
1477  }
1478  }
1479 
1480  return RES_OK;
1481  }
1482 
1487  template <class T> RES_T resize(Image<T> &imIn, Image<T> &imOut)
1488  {
1489  return resize(imIn, imOut.getWidth(), imOut.getHeight(), imOut);
1490  }
1491 
1495  template <class T> RES_T resize(Image<T> &imIn, UINT sx, UINT sy)
1496 
1497  {
1498  ASSERT_ALLOCATED(&imIn)
1499  Image<T> tmpIm(imIn, true); // clone
1500 
1501  imIn.setSize(sx, sy);
1502  return resize<T>(tmpIm, imIn);
1503  }
1504 
1509  template <class T>
1510  RES_T scale(Image<T> &imIn, double cx, double cy, Image<T> &imOut)
1511  {
1512  return resize<T>(imIn, size_t(imIn.getWidth() * cx),
1513  size_t(imIn.getHeight() * cy), imOut);
1514  }
1515 
1519  template <class T> RES_T scale(Image<T> &imIn, double cx, double cy)
1520  {
1521  ASSERT_ALLOCATED(&imIn)
1522  Image<T> tmpIm(imIn, true); // clone
1523  return resize(tmpIm, cx, cy, imIn);
1524  }
1525 
1530  template <class T>
1531  RES_T scaleClosest(Image<T> &imIn, double cx, double cy, Image<T> &imOut)
1532  {
1533  return resizeClosest<T>(imIn, size_t(imIn.getWidth() * cx),
1534  size_t(imIn.getHeight() * cy), imOut);
1535  }
1536 
1541  template <class T> RES_T scaleClosest(Image<T> &imIn, double cx, double cy)
1542  {
1543  ASSERT_ALLOCATED(&imIn)
1544  Image<T> tmpIm(imIn, true); // clone
1545  return resizeClosest(tmpIm, cx, cy, imIn);
1546  }
1547 #endif
1548 
1551 } // namespace smil
1552 
1553 #endif // _D_IMAGE_TRANSFORM_HPP
size_t getDepth() const
Get image depth (Z)
Definition: DBaseImage.h:90
void getSize(size_t *w, size_t *h, size_t *d) const
Get image size.
Definition: DBaseImage.h:118
size_t getWidth() const
Get image width.
Definition: DBaseImage.h:80
size_t getPixelCount() const
Get the number of pixels.
Definition: DBaseImage.h:160
UINT getDimension() const
Get dimension (2D or 3D)
Definition: DBaseImage.h:102
size_t getHeight() const
Get image height.
Definition: DBaseImage.h:85
Definition: DBaseImage.h:386
volType getSlices() const
Get an array containing the start offset of each slice.
Definition: DImage.hpp:117
lineType getPixels() const
Get the pixels as a 1D array.
Definition: DImage.hpp:105
Definition: DImage.hpp:484
Definition: DBaseImageOperations.hpp:73
RES_T fill(Image< T > &imOut, const T &value)
fill() - Fill an image with a given value.
Definition: DImageArith.hpp:1456
bool isBinary(const Image< T > &imIn)
isBinary() - Test if an image is binary.
Definition: DMeasures.hpp:1402
T maxVal(const Image< T > &imIn, bool onlyNonZero=false)
maxVal() - Max value of an image
Definition: DMeasures.hpp:348
RES_T crop(Image< T > &imInOut, size_t startX, size_t startY, size_t sizeX, size_t sizeY)
crop() - 2D Crop image
Definition: DImageTransform.hpp:368
RES_T copy(const Image< T > &imIn, Image< T > &imOut)
copy() - Copy Image
Definition: DImageTransform.hpp:242
RES_T clone(const Image< T > &imIn, Image< T > &imOut)
clone() - Clone an image
Definition: DImageTransform.hpp:265
RES_T addBorder(const Image< T > &imIn, const size_t &bSize, Image< T > &imOut, const T &borderValue=ImDtTypes< T >::max())
addBorder() - Add a border of size bSize around the original image
Definition: DImageTransform.hpp:395
RES_T resize(Image< T > &imIn, Image< T > &imOut, string method="trilinear")
resize() - 3D image resize
Definition: DImageTransform.hpp:1227
RES_T scale(Image< T > &imIn, double k, Image< T > &imOut, string method="trilinear")
scale() - image scale (resize by a factor)
Definition: DImageTransform.hpp:1308
RES_T rotateX90(Image< T > &im, int count)
rotateX90() - Rotate an image by an angle multiple of 90 degres
Definition: DImageTransform.hpp:704
ResImage< T > translate(const Image< T > &imIn, int dx, int dy)
translate() - 2D Image translation.
Definition: DImageTransform.hpp:801
RES_T vertFlip(Image< T > &im)
vertFlip() : Vertical Flip
Definition: DImageTransform.hpp:521
RES_T horizFlip(Image< T > &im)
horizFlip() : Horizontal Flip
Definition: DImageTransform.hpp:549
Definition: DTypes.hpp:88
Definition: DBaseImageOperations.hxx:39