00001 /* 00002 * 00003 * Copyright (C) 1996-2005, OFFIS 00004 * 00005 * This software and supporting documentation were developed by 00006 * 00007 * Kuratorium OFFIS e.V. 00008 * Healthcare Information and Communication Systems 00009 * Escherweg 2 00010 * D-26121 Oldenburg, Germany 00011 * 00012 * THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND OFFIS MAKES NO WARRANTY 00013 * REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR 00014 * FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES OR 00015 * ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND 00016 * PERFORMANCE OF THE SOFTWARE IS WITH THE USER. 00017 * 00018 * Module: dcmimgle 00019 * 00020 * Author: Joerg Riesmeier 00021 * 00022 * Purpose: DicomScaleTemplates (Header) 00023 * 00024 * Last Update: $Author: meichel $ 00025 * Update Date: $Date: 2005/12/08 16:48:09 $ 00026 * CVS/RCS Revision: $Revision: 1.25 $ 00027 * Status: $State: Exp $ 00028 * 00029 * CVS/RCS Log at end of file 00030 * 00031 */ 00032 00033 00034 #ifndef DISCALET_H 00035 #define DISCALET_H 00036 00037 #include "dcmtk/config/osconfig.h" 00038 #include "dcmtk/dcmdata/dctypes.h" 00039 #include "dcmtk/ofstd/ofconsol.h" 00040 #include "dcmtk/ofstd/ofcast.h" 00041 #include "dcmtk/ofstd/ofstream.h" 00042 00043 #include "dcmtk/dcmimgle/ditranst.h" 00044 #include "dcmtk/dcmimgle/dipxrept.h" 00045 #include "dcmtk/dcmimgle/diutils.h" 00046 00047 00048 /*---------------------* 00049 * macro definitions * 00050 *---------------------*/ 00051 00052 #define SCALE_FACTOR 4096 00053 #define HALFSCALE_FACTOR 2048 00054 00055 00056 /*--------------------* 00057 * helper functions * 00058 *--------------------*/ 00059 00060 // help function to set scaling values 00061 00062 static inline void setScaleValues(Uint16 data[], 00063 const Uint16 min, 00064 const Uint16 max) 00065 { 00066 register Uint16 remainder = max % min; 00067 Uint16 step0 = max / min; 00068 Uint16 step1 = max / min; 00069 if (remainder > OFstatic_cast(Uint16, min / 2)) 00070 { 00071 remainder = min - remainder; 00072 ++step0; 00073 } else 00074 ++step1; 00075 const double count = OFstatic_cast(double, min) / (OFstatic_cast(double, remainder) + 1); 00076 register Uint16 i; 00077 register double c = count; 00078 for (i = 0; i < min; ++i) 00079 { 00080 if ((i >= OFstatic_cast(Uint16, c)) && (remainder > 0)) 00081 { 00082 --remainder; 00083 c += count; 00084 data[i] = step1; 00085 } 00086 else 00087 data[i] = step0; 00088 } 00089 } 00090 00091 00092 /*---------------------* 00093 * class declaration * 00094 *---------------------*/ 00095 00099 template<class T> 00100 class DiScaleTemplate 00101 : public DiTransTemplate<T> 00102 { 00103 00104 public: 00105 00120 DiScaleTemplate(const int planes, 00121 const Uint16 columns, /* resolution of source image */ 00122 const Uint16 rows, 00123 const signed long left_pos, /* origin of clipping area */ 00124 const signed long top_pos, 00125 const Uint16 src_cols, /* extension of clipping area */ 00126 const Uint16 src_rows, 00127 const Uint16 dest_cols, /* extension of destination image */ 00128 const Uint16 dest_rows, 00129 const Uint32 frames, /* number of frames */ 00130 const int bits = 0) 00131 : DiTransTemplate<T>(planes, src_cols, src_rows, dest_cols, dest_rows, frames, bits), 00132 Left(left_pos), 00133 Top(top_pos), 00134 Columns(columns), 00135 Rows(rows) 00136 { 00137 } 00138 00149 DiScaleTemplate(const int planes, 00150 const Uint16 src_cols, /* resolution of source image */ 00151 const Uint16 src_rows, 00152 const Uint16 dest_cols, /* resolution of destination image */ 00153 const Uint16 dest_rows, 00154 const Uint32 frames, /* number of frames */ 00155 const int bits = 0) 00156 : DiTransTemplate<T>(planes, src_cols, src_rows, dest_cols, dest_rows, frames, bits), 00157 Left(0), 00158 Top(0), 00159 Columns(src_cols), 00160 Rows(src_rows) 00161 { 00162 } 00163 00166 virtual ~DiScaleTemplate() 00167 { 00168 } 00169 00177 void scaleData(const T *src[], // combined clipping and scaling UNTESTED for multi-frame images !! 00178 T *dest[], 00179 const int interpolate, 00180 const T value = 0) 00181 { 00182 if ((src != NULL) && (dest != NULL)) 00183 { 00184 #ifdef DEBUG 00185 if (DicomImageClass::checkDebugLevel(DicomImageClass::DL_DebugMessages)) 00186 { 00187 ofConsole.lockCout() << "C/R: " << Columns << " " << Rows << endl 00188 << "L/T: " << Left << " " << Top << endl 00189 << "SX/Y: " << this->Src_X << " " << this->Src_Y << endl 00190 << "DX/Y: " << this->Dest_X << " " << this->Dest_Y << endl; 00191 ofConsole.unlockCout(); 00192 } 00193 #endif 00194 if ((Left + OFstatic_cast(signed long, this->Src_X) <= 0) || (Top + OFstatic_cast(signed long, this->Src_Y) <= 0) || 00195 (Left >= OFstatic_cast(signed long, Columns)) || (Top >= OFstatic_cast(signed long, Rows))) 00196 { // no image to be displayed 00197 #ifdef DEBUG 00198 if (DicomImageClass::checkDebugLevel(DicomImageClass::DL_Informationals)) 00199 { 00200 ofConsole.lockCerr() << "INFO: clipping area is fully outside the image boundaries !" << endl; 00201 ofConsole.unlockCerr(); 00202 } 00203 #endif 00204 fillPixel(dest, value); // ... fill bitmap 00205 } 00206 else if ((this->Src_X == this->Dest_X) && (this->Src_Y == this->Dest_Y)) // no scaling 00207 { 00208 if ((Left == 0) && (Top == 0) && (Columns == this->Src_X) && (Rows == this->Src_Y)) 00209 copyPixel(src, dest); // copying 00210 else if ((Left >= 0) && (OFstatic_cast(Uint16, Left + this->Src_X) <= Columns) && 00211 (Top >= 0) && (OFstatic_cast(Uint16, Top + this->Src_Y) <= Rows)) 00212 clipPixel(src, dest); // clipping 00213 else 00214 clipBorderPixel(src, dest, value); // clipping (with border) 00215 } 00216 else if ((interpolate == 1) && (this->Bits <= MAX_INTERPOLATION_BITS)) // interpolation (pbmplus) 00217 interpolatePixel(src, dest); 00218 else if ((interpolate == 2) && (this->Dest_X >= this->Src_X) && (this->Dest_Y >= this->Src_Y)) // interpolated expansion (c't) 00219 expandPixel(src, dest); 00220 else if ((interpolate == 2) && (this->Src_X >= this->Dest_X) && (this->Src_Y >= this->Dest_Y)) // interpolated reduction (c't) 00221 reducePixel(src, dest); 00222 else if ((this->Dest_X % this->Src_X == 0) && (this->Dest_Y % this->Src_Y == 0)) // replication 00223 replicatePixel(src, dest); 00224 else if ((this->Src_X % this->Dest_X == 0) && (this->Src_Y % this->Dest_Y == 0)) // supression 00225 suppressPixel(src, dest); 00226 else // general scaling 00227 scalePixel(src, dest); 00228 } 00229 } 00230 00231 protected: 00232 00234 const signed long Left; 00236 const signed long Top; 00238 const Uint16 Columns; 00240 const Uint16 Rows; 00241 00242 00243 private: 00244 00251 void clipPixel(const T *src[], 00252 T *dest[]) 00253 { 00254 const unsigned long x_feed = Columns - this->Src_X; 00255 const unsigned long y_feed = OFstatic_cast(unsigned long, Rows - this->Src_Y) * OFstatic_cast(unsigned long, Columns); 00256 register Uint16 x; 00257 register Uint16 y; 00258 register const T *p; 00259 register T *q; 00260 for (int j = 0; j < this->Planes; ++j) 00261 { 00262 p = src[j] + OFstatic_cast(unsigned long, Top) * OFstatic_cast(unsigned long, Columns) + Left; 00263 q = dest[j]; 00264 for (unsigned long f = this->Frames; f != 0; --f) 00265 { 00266 for (y = this->Dest_Y; y != 0; --y) 00267 { 00268 for (x = this->Dest_X; x != 0; --x) 00269 *(q++) = *(p++); 00270 p += x_feed; 00271 } 00272 p += y_feed; 00273 } 00274 } 00275 } 00276 00284 void clipBorderPixel(const T *src[], 00285 T *dest[], 00286 const T value) 00287 { 00288 const Uint16 s_left = (Left > 0) ? OFstatic_cast(Uint16, Left) : 0; 00289 const Uint16 s_top = (Top > 0) ? OFstatic_cast(Uint16, Top) : 0; 00290 const Uint16 d_left = (Left < 0 ? OFstatic_cast(Uint16, -Left) : 0); 00291 const Uint16 d_top = (Top < 0) ? OFstatic_cast(Uint16, -Top) : 0; 00292 const Uint16 d_right = (OFstatic_cast(unsigned long, this->Src_X) + OFstatic_cast(unsigned long, s_left) < 00293 OFstatic_cast(unsigned long, Columns) + OFstatic_cast(unsigned long, d_left)) ? 00294 (this->Src_X - 1) : (Columns + d_left - s_left - 1); 00295 const Uint16 d_bottom = (OFstatic_cast(unsigned long, this->Src_Y) + OFstatic_cast(unsigned long, s_top) < 00296 OFstatic_cast(unsigned long, Rows) + OFstatic_cast(unsigned long, d_top)) ? 00297 (this->Src_Y - 1) : (Rows + d_top - s_top - 1); 00298 const Uint16 x_count = d_right - d_left + 1; 00299 const Uint16 y_count = d_bottom - d_top + 1; 00300 const unsigned long s_start = OFstatic_cast(unsigned long, s_top) * OFstatic_cast(unsigned long, Columns) + s_left; 00301 const unsigned long x_feed = Columns - x_count; 00302 const unsigned long y_feed = OFstatic_cast(unsigned long, Rows - y_count) * Columns; 00303 const unsigned long t_feed = OFstatic_cast(unsigned long, d_top) * OFstatic_cast(unsigned long, this->Src_X); 00304 const unsigned long b_feed = OFstatic_cast(unsigned long, this->Src_Y - d_bottom - 1) * OFstatic_cast(unsigned long, this->Src_X); 00305 00306 /* 00307 * The approach is to divide the destination image in up to four areas outside the source image 00308 * plus one area for the source image. The for and while loops are scanning linearly over the 00309 * destination image and setting the appropriate value depending on the current area. This is 00310 * different from most of the other algorithms in this toolkit where the source image is scanned 00311 * linearly. 00312 */ 00313 register Uint16 x; 00314 register Uint16 y; 00315 register unsigned long i; 00316 register const T *p; 00317 register T *q; 00318 for (int j = 0; j < this->Planes; ++j) 00319 { 00320 p = src[j] + s_start; 00321 q = dest[j]; 00322 for (unsigned long f = this->Frames; f != 0; --f) 00323 { 00324 for (i = t_feed; i != 0; --i) // top 00325 *(q++) = value; 00326 for (y = y_count; y != 0; --y) // middle part: 00327 { 00328 x = 0; 00329 while (x < d_left) // - left 00330 { 00331 *(q++) = value; 00332 ++x; 00333 } 00334 while (x <= d_right) // - middle 00335 { 00336 *(q++) = *(p++); 00337 ++x; 00338 } 00339 while (x < this->Src_X) // - right 00340 { 00341 *(q++) = value; 00342 ++x; 00343 } 00344 p += x_feed; 00345 } 00346 for (i = b_feed; i != 0; --i) // bottom 00347 *(q++) = value; 00348 p += y_feed; 00349 } 00350 } 00351 } 00352 00359 void replicatePixel(const T *src[], 00360 T *dest[]) 00361 { 00362 const Uint16 x_factor = this->Dest_X / this->Src_X; 00363 const Uint16 y_factor = this->Dest_Y / this->Src_Y; 00364 const unsigned long x_feed = Columns; 00365 const unsigned long y_feed = OFstatic_cast(unsigned long, Rows - this->Src_Y) * OFstatic_cast(unsigned long, Columns); 00366 const T *sp; 00367 register Uint16 x; 00368 register Uint16 y; 00369 register Uint16 dx; 00370 register Uint16 dy; 00371 register const T *p; 00372 register T *q; 00373 register T value; 00374 for (int j = 0; j < this->Planes; ++j) 00375 { 00376 sp = src[j] + OFstatic_cast(unsigned long, Top) * OFstatic_cast(unsigned long, Columns) + Left; 00377 q = dest[j]; 00378 for (Uint32 f = this->Frames; f != 0; --f) 00379 { 00380 for (y = this->Src_Y; y != 0; --y) 00381 { 00382 for (dy = y_factor; dy != 0; --dy) 00383 { 00384 for (x = this->Src_X, p = sp; x != 0; --x) 00385 { 00386 value = *(p++); 00387 for (dx = x_factor; dx != 0; --dx) 00388 *(q++) = value; 00389 } 00390 } 00391 sp += x_feed; 00392 } 00393 sp += y_feed; 00394 } 00395 } 00396 } 00397 00404 void suppressPixel(const T *src[], 00405 T *dest[]) 00406 { 00407 const unsigned int x_divisor = this->Src_X / this->Dest_X; 00408 const unsigned long x_feed = OFstatic_cast(unsigned long, this->Src_Y / this->Dest_Y) * OFstatic_cast(unsigned long, Columns) - this->Src_X; 00409 const unsigned long y_feed = OFstatic_cast(unsigned long, Rows - this->Src_Y) * OFstatic_cast(unsigned long, Columns); 00410 register Uint16 x; 00411 register Uint16 y; 00412 register const T *p; 00413 register T *q; 00414 for (int j = 0; j < this->Planes; ++j) 00415 { 00416 p = src[j] + OFstatic_cast(unsigned long, Top) * OFstatic_cast(unsigned long, Columns) + Left; 00417 q = dest[j]; 00418 for (Uint32 f = this->Frames; f != 0; --f) 00419 { 00420 for (y = this->Dest_Y; y != 0; --y) 00421 { 00422 for (x = this->Dest_X; x != 0; --x) 00423 { 00424 *(q++) = *p; 00425 p += x_divisor; 00426 } 00427 p += x_feed; 00428 } 00429 p += y_feed; 00430 } 00431 } 00432 } 00433 00440 void scalePixel(const T *src[], 00441 T *dest[]) 00442 { 00443 const Uint16 xmin = (this->Dest_X < this->Src_X) ? this->Dest_X : this->Src_X; // minimum width 00444 const Uint16 ymin = (this->Dest_Y < this->Src_Y) ? this->Dest_Y : this->Src_Y; // minimum height 00445 Uint16 *x_step = new Uint16[xmin]; 00446 Uint16 *y_step = new Uint16[ymin]; 00447 Uint16 *x_fact = new Uint16[xmin]; 00448 Uint16 *y_fact = new Uint16[ymin]; 00449 00450 /* 00451 * Approach: If one pixel line has to be added or removed it is taken from the middle of the image (1/2). 00452 * For two lines it is at 1/3 and 2/3 of the image and so on. It sounds easy but it was a hard job ;-) 00453 */ 00454 00455 if ((x_step != NULL) && (y_step != NULL) && (x_fact != NULL) && (y_fact != NULL)) 00456 { 00457 register Uint16 x; 00458 register Uint16 y; 00459 if (this->Dest_X < this->Src_X) 00460 setScaleValues(x_step, this->Dest_X, this->Src_X); 00461 else if (this->Dest_X > this->Src_X) 00462 setScaleValues(x_fact, this->Src_X, this->Dest_X); 00463 if (this->Dest_X <= this->Src_X) 00464 OFBitmanipTemplate<Uint16>::setMem(x_fact, 1, xmin); // initialize with default values 00465 if (this->Dest_X >= this->Src_X) 00466 OFBitmanipTemplate<Uint16>::setMem(x_step, 1, xmin); // initialize with default values 00467 x_step[xmin - 1] += Columns - this->Src_X; // skip to next line 00468 if (this->Dest_Y < this->Src_Y) 00469 setScaleValues(y_step, this->Dest_Y, this->Src_Y); 00470 else if (this->Dest_Y > this->Src_Y) 00471 setScaleValues(y_fact, this->Src_Y, this->Dest_Y); 00472 if (this->Dest_Y <= this->Src_Y) 00473 OFBitmanipTemplate<Uint16>::setMem(y_fact, 1, ymin); // initialize with default values 00474 if (this->Dest_Y >= this->Src_Y) 00475 OFBitmanipTemplate<Uint16>::setMem(y_step, 1, ymin); // initialize with default values 00476 y_step[ymin - 1] += Rows - this->Src_Y; // skip to next frame 00477 const T *sp; 00478 register Uint16 dx; 00479 register Uint16 dy; 00480 register const T *p; 00481 register T *q; 00482 register T value; 00483 for (int j = 0; j < this->Planes; ++j) 00484 { 00485 sp = src[j] + OFstatic_cast(unsigned long, Top) * OFstatic_cast(unsigned long, Columns) + Left; 00486 q = dest[j]; 00487 for (Uint32 f = 0; f < this->Frames; ++f) 00488 { 00489 for (y = 0; y < ymin; ++y) 00490 { 00491 for (dy = 0; dy < y_fact[y]; ++dy) 00492 { 00493 for (x = 0, p = sp; x < xmin; ++x) 00494 { 00495 value = *p; 00496 for (dx = 0; dx < x_fact[x]; ++dx) 00497 *(q++) = value; 00498 p += x_step[x]; 00499 } 00500 } 00501 sp += OFstatic_cast(unsigned long, y_step[y]) * OFstatic_cast(unsigned long, Columns); 00502 } 00503 } 00504 } 00505 } 00506 delete[] x_step; 00507 delete[] y_step; 00508 delete[] x_fact; 00509 delete[] y_fact; 00510 } 00511 00512 00518 void interpolatePixel(const T *src[], 00519 T *dest[]) 00520 { 00521 if ((this->Src_X != Columns) || (this->Src_Y != Rows)) 00522 { 00523 if (DicomImageClass::checkDebugLevel(DicomImageClass::DL_Errors)) 00524 { 00525 ofConsole.lockCerr() << "ERROR: interpolated scaling and clipping at the same time not implemented" << endl 00526 << " ... ignoring clipping region !" << endl; 00527 ofConsole.unlockCerr(); 00528 } 00529 this->Src_X = Columns; // temporarily removed 'const' for 'Src_X' in class 'DiTransTemplate' 00530 this->Src_Y = Rows; // ... 'Src_Y' ... 00531 } 00532 00533 /* 00534 * based on scaling algorithm from "Extended Portable Bitmap Toolkit" (pbmplus10dec91) 00535 * (adapted to be used with signed pixel representation and inverse images - mono2) 00536 */ 00537 00538 register Uint16 x; 00539 register Uint16 y; 00540 register const T *p; 00541 register T *q; 00542 T const *sp = NULL; // initialization avoids compiler warning 00543 T const *fp; 00544 T *sq; 00545 00546 const unsigned long sxscale = OFstatic_cast(unsigned long, (OFstatic_cast(double, this->Dest_X) / OFstatic_cast(double, this->Src_X)) * SCALE_FACTOR); 00547 const unsigned long syscale = OFstatic_cast(unsigned long, (OFstatic_cast(double, this->Dest_Y) / OFstatic_cast(double, this->Src_Y)) * SCALE_FACTOR); 00548 DiPixelRepresentationTemplate<T> rep; 00549 const signed long maxvalue = DicomImageClass::maxval(this->Bits - rep.isSigned()); 00550 00551 T *xtemp = new T[this->Src_X]; 00552 signed long *xvalue = new signed long[this->Src_X]; 00553 00554 if ((xtemp == NULL) || (xvalue == NULL)) 00555 { 00556 if (DicomImageClass::checkDebugLevel(DicomImageClass::DL_Errors)) 00557 { 00558 ofConsole.lockCerr() << "ERROR: can't allocate temporary buffers for interpolation scaling !" << endl; 00559 ofConsole.unlockCerr(); 00560 } 00561 00562 const unsigned long count = OFstatic_cast(unsigned long, this->Dest_X) * OFstatic_cast(unsigned long, this->Dest_Y) * this->Frames; 00563 for (int j = 0; j < this->Planes; ++j) 00564 OFBitmanipTemplate<T>::zeroMem(dest[j], count); // delete destination buffer 00565 } 00566 else 00567 { 00568 for (int j = 0; j < this->Planes; ++j) 00569 { 00570 fp = src[j]; 00571 sq = dest[j]; 00572 for (Uint32 f = this->Frames; f != 0; --f) 00573 { 00574 for (x = 0; x < this->Src_X; ++x) 00575 xvalue[x] = HALFSCALE_FACTOR; 00576 register unsigned long yfill = SCALE_FACTOR; 00577 register unsigned long yleft = syscale; 00578 register int yneed = 1; 00579 int ysrc = 0; 00580 for (y = 0; y < this->Dest_Y; ++y) 00581 { 00582 if (this->Src_Y == this->Dest_Y) 00583 { 00584 sp = fp; 00585 for (x = this->Src_X, p = sp, q = xtemp; x != 0; --x) 00586 *(q++) = *(p++); 00587 fp += this->Src_X; 00588 } 00589 else 00590 { 00591 while (yleft < yfill) 00592 { 00593 if (yneed && (ysrc < OFstatic_cast(int, this->Src_Y))) 00594 { 00595 sp = fp; 00596 fp += this->Src_X; 00597 ++ysrc; 00598 } 00599 for (x = 0, p = sp; x < this->Src_X; ++x) 00600 xvalue[x] += yleft * OFstatic_cast(signed long, *(p++)); 00601 yfill -= yleft; 00602 yleft = syscale; 00603 yneed = 1; 00604 } 00605 if (yneed && (ysrc < OFstatic_cast(int, this->Src_Y))) 00606 { 00607 sp = fp; 00608 fp += this->Src_X; 00609 ++ysrc; 00610 yneed = 0; 00611 } 00612 for (x = 0, p = sp, q = xtemp; x < this->Src_X; ++x) 00613 { 00614 register signed long v = xvalue[x] + yfill * OFstatic_cast(signed long, *(p++)); 00615 v /= SCALE_FACTOR; 00616 *(q++) = OFstatic_cast(T, (v > maxvalue) ? maxvalue : v); 00617 xvalue[x] = HALFSCALE_FACTOR; 00618 } 00619 yleft -= yfill; 00620 if (yleft == 0) 00621 { 00622 yleft = syscale; 00623 yneed = 1; 00624 } 00625 yfill = SCALE_FACTOR; 00626 } 00627 if (this->Src_X == this->Dest_X) 00628 { 00629 for (x = this->Dest_X, p = xtemp, q = sq; x != 0; --x) 00630 *(q++) = *(p++); 00631 sq += this->Dest_X; 00632 } 00633 else 00634 { 00635 register signed long v = HALFSCALE_FACTOR; 00636 register unsigned long xfill = SCALE_FACTOR; 00637 register unsigned long xleft; 00638 register int xneed = 0; 00639 q = sq; 00640 for (x = 0, p = xtemp; x < this->Src_X; ++x, ++p) 00641 { 00642 xleft = sxscale; 00643 while (xleft >= xfill) 00644 { 00645 if (xneed) 00646 { 00647 ++q; 00648 v = HALFSCALE_FACTOR; 00649 } 00650 v += xfill * OFstatic_cast(signed long, *p); 00651 v /= SCALE_FACTOR; 00652 *q = OFstatic_cast(T, (v > maxvalue) ? maxvalue : v); 00653 xleft -= xfill; 00654 xfill = SCALE_FACTOR; 00655 xneed = 1; 00656 } 00657 if (xleft > 0) 00658 { 00659 if (xneed) 00660 { 00661 ++q; 00662 v = HALFSCALE_FACTOR; 00663 xneed = 0; 00664 } 00665 v += xleft * OFstatic_cast(signed long, *p); 00666 xfill -= xleft; 00667 } 00668 } 00669 if (xfill > 0) 00670 v += xfill * OFstatic_cast(signed long, *(--p)); 00671 if (!xneed) 00672 { 00673 v /= SCALE_FACTOR; 00674 *q = OFstatic_cast(T, (v > maxvalue) ? maxvalue : v); 00675 } 00676 sq += this->Dest_X; 00677 } 00678 } 00679 } 00680 } 00681 } 00682 delete[] xtemp; 00683 delete[] xvalue; 00684 } 00685 00686 00692 void expandPixel(const T *src[], 00693 T *dest[]) 00694 { 00695 #ifdef DEBUG 00696 if (DicomImageClass::checkDebugLevel(DicomImageClass::DL_Informationals)) 00697 { 00698 ofConsole.lockCerr() << "INFO: expandPixel with interpolated c't algorithm" << endl; 00699 ofConsole.unlockCerr(); 00700 } 00701 #endif 00702 const double x_factor = OFstatic_cast(double, this->Src_X) / OFstatic_cast(double, this->Dest_X); 00703 const double y_factor = OFstatic_cast(double, this->Src_Y) / OFstatic_cast(double, this->Dest_Y); 00704 const unsigned long f_size = OFstatic_cast(unsigned long, Rows) * OFstatic_cast(unsigned long, Columns); 00705 const T *sp; 00706 double bx, ex; 00707 double by, ey; 00708 int bxi, exi; 00709 int byi, eyi; 00710 unsigned long offset; 00711 double value, sum; 00712 double x_part, y_part; 00713 double l_factor, r_factor; 00714 double t_factor, b_factor; 00715 register int xi; 00716 register int yi; 00717 register Uint16 x; 00718 register Uint16 y; 00719 register const T *p; 00720 register T *q; 00721 00722 /* 00723 * based on scaling algorithm from "c't - Magazin fuer Computertechnik" (c't 11/94) 00724 * (adapted to be used with signed pixel representation and inverse images - mono1) 00725 */ 00726 00727 for (int j = 0; j < this->Planes; ++j) 00728 { 00729 sp = src[j] + OFstatic_cast(unsigned long, Top) * OFstatic_cast(unsigned long, Columns) + Left; 00730 q = dest[j]; 00731 for (Uint32 f = 0; f < this->Frames; ++f) 00732 { 00733 for (y = 0; y < this->Dest_Y; ++y) 00734 { 00735 by = y_factor * OFstatic_cast(double, y); 00736 ey = y_factor * (OFstatic_cast(double, y) + 1.0); 00737 byi = OFstatic_cast(int, by); 00738 eyi = OFstatic_cast(int, ey); 00739 if (OFstatic_cast(double, eyi) == ey) 00740 --eyi; 00741 y_part = OFstatic_cast(double, eyi) / y_factor; 00742 b_factor = y_part - OFstatic_cast(double, y); 00743 t_factor = (OFstatic_cast(double, y) + 1.0) - y_part; 00744 for (x = 0; x < this->Dest_X; ++x) 00745 { 00746 value = 0; 00747 bx = x_factor * OFstatic_cast(double, x); 00748 ex = x_factor * (OFstatic_cast(double, x) + 1.0); 00749 bxi = OFstatic_cast(int, bx); 00750 exi = OFstatic_cast(int, ex); 00751 if (OFstatic_cast(double, exi) == ex) 00752 --exi; 00753 x_part = OFstatic_cast(double, exi) / x_factor; 00754 l_factor = x_part - OFstatic_cast(double, x); 00755 r_factor = (OFstatic_cast(double, x) + 1.0) - x_part; 00756 offset = OFstatic_cast(unsigned long, byi - 1) * OFstatic_cast(unsigned long, Columns); 00757 for (yi = byi; yi <= eyi; ++yi) 00758 { 00759 offset += Columns; 00760 p = sp + offset + OFstatic_cast(unsigned long, bxi); 00761 for (xi = bxi; xi <= exi; ++xi) 00762 { 00763 sum = OFstatic_cast(double, *(p++)); 00764 if (bxi != exi) 00765 { 00766 if (xi == bxi) 00767 sum *= l_factor; 00768 else 00769 sum *= r_factor; 00770 } 00771 if (byi != eyi) 00772 { 00773 if (yi == byi) 00774 sum *= b_factor; 00775 else 00776 sum *= t_factor; 00777 } 00778 value += sum; 00779 } 00780 } 00781 *(q++) = OFstatic_cast(T, value + 0.5); 00782 } 00783 } 00784 sp += f_size; // skip to next frame start: UNTESTED 00785 } 00786 } 00787 } 00788 00789 00795 void reducePixel(const T *src[], 00796 T *dest[]) 00797 { 00798 #ifdef DEBUG 00799 if (DicomImageClass::checkDebugLevel(DicomImageClass::DL_Informationals | DicomImageClass::DL_Warnings)) 00800 { 00801 ofConsole.lockCerr() << "INFO: reducePixel with interpolated c't algorithm ... still a little BUGGY !" << endl; 00802 ofConsole.unlockCerr(); 00803 } 00804 #endif 00805 const double x_factor = OFstatic_cast(double, this->Src_X) / OFstatic_cast(double, this->Dest_X); 00806 const double y_factor = OFstatic_cast(double, this->Src_Y) / OFstatic_cast(double, this->Dest_Y); 00807 const double xy_factor = x_factor * y_factor; 00808 const unsigned long f_size = OFstatic_cast(unsigned long, Rows) * OFstatic_cast(unsigned long, Columns); 00809 const T *sp; 00810 double bx, ex; 00811 double by, ey; 00812 int bxi, exi; 00813 int byi, eyi; 00814 unsigned long offset; 00815 double value, sum; 00816 double l_factor, r_factor; 00817 double t_factor, b_factor; 00818 register int xi; 00819 register int yi; 00820 register Uint16 x; 00821 register Uint16 y; 00822 register const T *p; 00823 register T *q; 00824 00825 /* 00826 * based on scaling algorithm from "c't - Magazin fuer Computertechnik" (c't 11/94) 00827 * (adapted to be used with signed pixel representation and inverse images - mono1) 00828 */ 00829 00830 for (int j = 0; j < this->Planes; ++j) 00831 { 00832 sp = src[j] + OFstatic_cast(unsigned long, Top) * OFstatic_cast(unsigned long, Columns) + Left; 00833 q = dest[j]; 00834 for (Uint32 f = 0; f < this->Frames; ++f) 00835 { 00836 for (y = 0; y < this->Dest_Y; ++y) 00837 { 00838 by = y_factor * OFstatic_cast(double, y); 00839 ey = y_factor * (OFstatic_cast(double, y) + 1.0); 00840 byi = OFstatic_cast(int, by); 00841 eyi = OFstatic_cast(int, ey); 00842 if (OFstatic_cast(double, eyi) == ey) 00843 --eyi; 00844 b_factor = 1 + OFstatic_cast(double, byi) - by; 00845 t_factor = ey - OFstatic_cast(double, eyi); 00846 for (x = 0; x < this->Dest_X; ++x) 00847 { 00848 value = 0; 00849 bx = x_factor * OFstatic_cast(double, x); 00850 ex = x_factor * (OFstatic_cast(double, x) + 1.0); 00851 bxi = OFstatic_cast(int, bx); 00852 exi = OFstatic_cast(int, ex); 00853 if (OFstatic_cast(double, exi) == ex) 00854 --exi; 00855 l_factor = 1 + OFstatic_cast(double, bxi) - bx; 00856 r_factor = ex - OFstatic_cast(double, exi); 00857 offset = OFstatic_cast(unsigned long, byi - 1) * OFstatic_cast(unsigned long, Columns); 00858 for (yi = byi; yi <= eyi; ++yi) 00859 { 00860 offset += Columns; 00861 p = sp + offset + OFstatic_cast(unsigned long, bxi); 00862 for (xi = bxi; xi <= exi; ++xi) 00863 { 00864 sum = OFstatic_cast(double, *(p++)) / xy_factor; 00865 if (xi == bxi) 00866 sum *= l_factor; 00867 else if (xi == exi) 00868 sum *= r_factor; 00869 if (yi == byi) 00870 sum *= b_factor; 00871 else if (yi == eyi) 00872 sum *= t_factor; 00873 value += sum; 00874 } 00875 } 00876 *(q++) = OFstatic_cast(T, value + 0.5); 00877 } 00878 } 00879 sp += f_size; // skip to next frame start: UNTESTED 00880 } 00881 } 00882 } 00883 }; 00884 00885 #endif 00886 00887 00888 /* 00889 * 00890 * CVS/RCS Log: 00891 * $Log: discalet.h,v $ 00892 * Revision 1.25 2005/12/08 16:48:09 meichel 00893 * Changed include path schema for all DCMTK header files 00894 * 00895 * Revision 1.24 2004/04/21 10:00:36 meichel 00896 * Minor modifications for compilation with gcc 3.4.0 00897 * 00898 * Revision 1.23 2004/01/05 14:52:20 joergr 00899 * Removed acknowledgements with e-mail addresses from CVS log. 00900 * 00901 * Revision 1.22 2003/12/23 15:53:22 joergr 00902 * Replaced post-increment/decrement operators by pre-increment/decrement 00903 * operators where appropriate (e.g. 'i++' by '++i'). 00904 * 00905 * Revision 1.21 2003/12/09 10:25:06 joergr 00906 * Adapted type casts to new-style typecast operators defined in ofcast.h. 00907 * Removed leading underscore characters from preprocessor symbols (reserved 00908 * symbols). Updated copyright header. 00909 * 00910 * Revision 1.20 2002/12/09 13:32:56 joergr 00911 * Renamed parameter/local variable to avoid name clashes with global 00912 * declaration left and/or right (used for as iostream manipulators). 00913 * 00914 * Revision 1.19 2002/04/16 13:53:12 joergr 00915 * Added configurable support for C++ ANSI standard includes (e.g. streams). 00916 * 00917 * Revision 1.18 2001/06/01 15:49:51 meichel 00918 * Updated copyright header 00919 * 00920 * Revision 1.17 2000/05/03 09:46:29 joergr 00921 * Removed most informational and some warning messages from release built 00922 * (#ifndef DEBUG). 00923 * 00924 * Revision 1.16 2000/04/28 12:32:33 joergr 00925 * DebugLevel - global for the module - now derived from OFGlobal (MF-safe). 00926 * 00927 * Revision 1.15 2000/04/27 13:08:42 joergr 00928 * Dcmimgle library code now consistently uses ofConsole for error output. 00929 * 00930 * Revision 1.14 2000/03/08 16:24:24 meichel 00931 * Updated copyright header. 00932 * 00933 * Revision 1.13 2000/03/07 16:15:13 joergr 00934 * Added explicit type casts to make Sun CC 2.0.1 happy. 00935 * 00936 * Revision 1.12 2000/03/03 14:09:14 meichel 00937 * Implemented library support for redirecting error messages into memory 00938 * instead of printing them to stdout/stderr for GUI applications. 00939 * 00940 * Revision 1.11 1999/11/19 12:37:19 joergr 00941 * Fixed bug in scaling method "reducePixel" (reported by gcc 2.7.2.1). 00942 * 00943 * Revision 1.10 1999/09/17 13:07:20 joergr 00944 * Added/changed/completed DOC++ style comments in the header files. 00945 * Enhanced efficiency of some "for" loops. 00946 * 00947 * Revision 1.9 1999/08/25 16:41:55 joergr 00948 * Added new feature: Allow clipping region to be outside the image 00949 * (overlapping). 00950 * 00951 * Revision 1.8 1999/07/23 14:09:24 joergr 00952 * Added new interpolation algorithm for scaling. 00953 * 00954 * Revision 1.7 1999/04/28 14:55:05 joergr 00955 * Introduced new scheme for the debug level variable: now each level can be 00956 * set separately (there is no "include" relationship). 00957 * 00958 * Revision 1.6 1999/03/24 17:20:24 joergr 00959 * Added/Modified comments and formatting. 00960 * 00961 * Revision 1.5 1999/02/11 16:42:10 joergr 00962 * Removed inline declarations from several methods. 00963 * 00964 * Revision 1.4 1999/02/03 17:35:14 joergr 00965 * Moved global functions maxval() and determineRepresentation() to class 00966 * DicomImageClass (as static methods). 00967 * 00968 * Revision 1.3 1998/12/22 14:39:44 joergr 00969 * Added some preparation to enhance interpolated scaling (clipping and 00970 * scaling) in the future. 00971 * 00972 * Revision 1.2 1998/12/16 16:39:45 joergr 00973 * Implemented combined clipping and scaling for pixel replication and 00974 * suppression. 00975 * 00976 * Revision 1.1 1998/11/27 15:47:11 joergr 00977 * Added copyright message. 00978 * Combined clipping and scaling methods. 00979 * 00980 * Revision 1.4 1998/05/11 14:53:29 joergr 00981 * Added CVS/RCS header to each file. 00982 * 00983 * 00984 */