00001 /* 00002 * 00003 * Copyright (C) 1996-2010, OFFIS e.V. 00004 * All rights reserved. See COPYRIGHT file for details. 00005 * 00006 * This software and supporting documentation were developed by 00007 * 00008 * OFFIS e.V. 00009 * R&D Division Health 00010 * Escherweg 2 00011 * D-26121 Oldenburg, Germany 00012 * 00013 * 00014 * Module: dcmimgle 00015 * 00016 * Author: Joerg Riesmeier 00017 * 00018 * Purpose: DicomMonochromeInputPixelTemplate (Header) 00019 * 00020 * Last Update: $Author: joergr $ 00021 * Update Date: $Date: 2010-10-14 13:16:26 $ 00022 * CVS/RCS Revision: $Revision: 1.40 $ 00023 * Status: $State: Exp $ 00024 * 00025 * CVS/RCS Log at end of file 00026 * 00027 */ 00028 00029 00030 #ifndef DIMOIPXT_H 00031 #define DIMOIPXT_H 00032 00033 #include "dcmtk/config/osconfig.h" 00034 00035 #include "dcmtk/ofstd/ofbmanip.h" 00036 #include "dcmtk/ofstd/ofcast.h" 00037 00038 #include "dcmtk/dcmimgle/dimopxt.h" 00039 #include "dcmtk/dcmimgle/diinpx.h" 00040 00041 00042 /*---------------------* 00043 * class declaration * 00044 *---------------------*/ 00045 00048 template<class T1, class T2, class T3> 00049 class DiMonoInputPixelTemplate 00050 : public DiMonoPixelTemplate<T3> 00051 { 00052 00053 public: 00054 00060 DiMonoInputPixelTemplate(DiInputPixel *pixel, 00061 DiMonoModality *modality) 00062 : DiMonoPixelTemplate<T3>(pixel, modality) 00063 { 00064 /* erase empty part of the buffer (= blacken the background) */ 00065 if ((this->Data != NULL) && (this->InputCount < this->Count)) 00066 OFBitmanipTemplate<T3>::zeroMem(this->Data + this->InputCount, this->Count - this->InputCount); 00067 if ((pixel != NULL) && (this->Count > 0)) 00068 { 00069 // check whether to apply any modality transform 00070 if ((this->Modality != NULL) && this->Modality->hasLookupTable() && (bitsof(T1) <= MAX_TABLE_ENTRY_SIZE)) 00071 { 00072 modlut(pixel); 00073 // ignore modality LUT min/max values since the image does not necessarily have to use all LUT entries 00074 this->determineMinMax(); 00075 } 00076 else if ((this->Modality != NULL) && this->Modality->hasRescaling()) 00077 { 00078 rescale(pixel, this->Modality->getRescaleSlope(), this->Modality->getRescaleIntercept()); 00079 determineMinMax(OFstatic_cast(T3, this->Modality->getMinValue()), OFstatic_cast(T3, this->Modality->getMaxValue())); 00080 } else { 00081 rescale(pixel); // "copy" or reference pixel data 00082 determineMinMax(OFstatic_cast(T3, this->Modality->getMinValue()), OFstatic_cast(T3, this->Modality->getMaxValue())); 00083 } 00084 } 00085 } 00086 00089 virtual ~DiMonoInputPixelTemplate() 00090 { 00091 } 00092 00093 00094 private: 00095 00103 inline int initOptimizationLUT(T3 *&lut, 00104 const unsigned long ocnt) 00105 { 00106 int result = 0; 00107 if ((sizeof(T1) <= 2) && (this->InputCount > 3 * ocnt)) // optimization criteria 00108 { // use LUT for optimization 00109 lut = new T3[ocnt]; 00110 if (lut != NULL) 00111 { 00112 DCMIMGLE_DEBUG("using optimized routine with additional LUT"); 00113 result = 1; 00114 } 00115 } 00116 return result; 00117 } 00118 00123 void modlut(DiInputPixel *input) 00124 { 00125 const T1 *pixel = OFstatic_cast(const T1 *, input->getData()); 00126 if ((pixel != NULL) && (this->Modality != NULL)) 00127 { 00128 const DiLookupTable *mlut = this->Modality->getTableData(); 00129 if (mlut != NULL) 00130 { 00131 const int useInputBuffer = (sizeof(T1) == sizeof(T3)) && (this->Count <= input->getCount()); 00132 if (useInputBuffer) // do not copy pixel data, reference them! 00133 { 00134 DCMIMGLE_DEBUG("re-using input buffer, do not copy pixel data"); 00135 this->Data = OFstatic_cast(T3 *, input->getDataPtr()); 00136 input->removeDataReference(); // avoid double deletion 00137 } else 00138 this->Data = new T3[this->Count]; 00139 if (this->Data != NULL) 00140 { 00141 DCMIMGLE_DEBUG("applying modality tranformation with LUT (" << mlut->getCount() << " entries)"); 00142 register T2 value = 0; 00143 const T2 firstentry = mlut->getFirstEntry(value); // choose signed/unsigned method 00144 const T2 lastentry = mlut->getLastEntry(value); 00145 const T3 firstvalue = OFstatic_cast(T3, mlut->getFirstValue()); 00146 const T3 lastvalue = OFstatic_cast(T3, mlut->getLastValue()); 00147 register const T1 *p = pixel + input->getPixelStart(); 00148 register T3 *q = this->Data; 00149 register unsigned long i; 00150 T3 *lut = NULL; 00151 const unsigned long ocnt = OFstatic_cast(unsigned long, input->getAbsMaxRange()); // number of LUT entries 00152 if (initOptimizationLUT(lut, ocnt)) 00153 { // use LUT for optimization 00154 const T2 absmin = OFstatic_cast(T2, input->getAbsMinimum()); 00155 q = lut; 00156 for (i = 0; i < ocnt; ++i) // calculating LUT entries 00157 { 00158 value = OFstatic_cast(T2, i) + absmin; 00159 if (value <= firstentry) 00160 *(q++) = firstvalue; 00161 else if (value >= lastentry) 00162 *(q++) = lastvalue; 00163 else 00164 *(q++) = OFstatic_cast(T3, mlut->getValue(value)); 00165 } 00166 const T3 *lut0 = lut - OFstatic_cast(T2, absmin); // points to 'zero' entry 00167 q = this->Data; 00168 for (i = this->InputCount; i != 0; --i) // apply LUT 00169 *(q++) = *(lut0 + (*(p++))); 00170 } 00171 if (lut == NULL) // use "normal" transformation 00172 { 00173 for (i = this->InputCount; i != 0; --i) 00174 { 00175 value = OFstatic_cast(T2, *(p++)); 00176 if (value <= firstentry) 00177 *(q++) = firstvalue; 00178 else if (value >= lastentry) 00179 *(q++) = lastvalue; 00180 else 00181 *(q++) = OFstatic_cast(T3, mlut->getValue(value)); 00182 } 00183 } 00184 delete[] lut; 00185 } 00186 } 00187 } 00188 } 00189 00196 void rescale(DiInputPixel *input, 00197 const double slope = 1.0, 00198 const double intercept = 0.0) 00199 { 00200 const T1 *pixel = OFstatic_cast(const T1 *, input->getData()); 00201 if (pixel != NULL) 00202 { 00203 const int useInputBuffer = (sizeof(T1) == sizeof(T3)) && (this->Count <= input->getCount()) && (input->getPixelStart() == 0); 00204 if (useInputBuffer) 00205 { // do not copy pixel data, reference them! 00206 DCMIMGLE_DEBUG("re-using input buffer, do not copy pixel data"); 00207 this->Data = OFstatic_cast(T3 *, input->getDataPtr()); 00208 input->removeDataReference(); // avoid double deletion 00209 } else 00210 this->Data = new T3[this->Count]; 00211 if (this->Data != NULL) 00212 { 00213 register T3 *q = this->Data; 00214 register unsigned long i; 00215 if ((slope == 1.0) && (intercept == 0.0)) 00216 { 00217 if (!useInputBuffer) 00218 { 00219 register const T1 *p = pixel + input->getPixelStart(); 00220 for (i = this->InputCount; i != 0; --i) // copy pixel data: can't use copyMem because T1 isn't always equal to T3 00221 *(q++) = OFstatic_cast(T3, *(p++)); 00222 } 00223 } else { 00224 DCMIMGLE_DEBUG("applying modality transformation with rescale slope = " << slope << ", intercept = " << intercept); 00225 T3 *lut = NULL; 00226 register const T1 *p = pixel + input->getPixelStart(); 00227 const unsigned long ocnt = OFstatic_cast(unsigned long, input->getAbsMaxRange()); // number of LUT entries 00228 if (initOptimizationLUT(lut, ocnt)) 00229 { // use LUT for optimization 00230 const double absmin = input->getAbsMinimum(); 00231 q = lut; 00232 if (slope == 1.0) 00233 { 00234 for (i = 0; i < ocnt; ++i) // calculating LUT entries 00235 *(q++) = OFstatic_cast(T3, OFstatic_cast(double, i) + absmin + intercept); 00236 } else { 00237 if (intercept == 0.0) 00238 { 00239 for (i = 0; i < ocnt; ++i) 00240 *(q++) = OFstatic_cast(T3, (OFstatic_cast(double, i) + absmin) * slope); 00241 } else { 00242 for (i = 0; i < ocnt; ++i) 00243 *(q++) = OFstatic_cast(T3, (OFstatic_cast(double, i) + absmin) * slope + intercept); 00244 } 00245 } 00246 const T3 *lut0 = lut - OFstatic_cast(T2, absmin); // points to 'zero' entry 00247 q = this->Data; 00248 for (i = this->InputCount; i != 0; --i) // apply LUT 00249 *(q++) = *(lut0 + (*(p++))); 00250 } 00251 if (lut == NULL) // use "normal" transformation 00252 { 00253 if (slope == 1.0) 00254 { 00255 for (i = this->InputCount; i != 0; --i) 00256 *(q++) = OFstatic_cast(T3, OFstatic_cast(double, *(p++)) + intercept); 00257 } else { 00258 if (intercept == 0.0) 00259 { 00260 for (i = this->InputCount; i != 0; --i) 00261 *(q++) = OFstatic_cast(T3, OFstatic_cast(double, *(p++)) * slope); 00262 } else { 00263 for (i = this->InputCount; i != 0; --i) 00264 *(q++) = OFstatic_cast(T3, OFstatic_cast(double, *(p++)) * slope + intercept); 00265 } 00266 } 00267 } 00268 delete[] lut; 00269 } 00270 } 00271 } 00272 } 00273 }; 00274 00275 00276 #endif 00277 00278 00279 /* 00280 * 00281 * CVS/RCS Log: 00282 * $Log: dimoipxt.h,v $ 00283 * Revision 1.40 2010-10-14 13:16:26 joergr 00284 * Updated copyright header. Added reference to COPYRIGHT file. 00285 * 00286 * Revision 1.39 2010-03-01 09:08:47 uli 00287 * Removed some unnecessary include directives in the headers. 00288 * 00289 * Revision 1.38 2009-11-25 16:07:12 joergr 00290 * Removed inclusion of header file "ofconsol.h". Revised logging messages. 00291 * 00292 * Revision 1.37 2009-10-28 14:38:16 joergr 00293 * Fixed minor issues in log output. 00294 * 00295 * Revision 1.36 2009-10-28 09:53:40 uli 00296 * Switched to logging mechanism provided by the "new" oflog module. 00297 * 00298 * Revision 1.35 2008-04-09 11:02:08 joergr 00299 * Fixed wrong use of variable in "for" loop which might cause a crash. 00300 * 00301 * Revision 1.34 2006/08/15 16:30:11 meichel 00302 * Updated the code in module dcmimgle to correctly compile when 00303 * all standard C++ classes remain in namespace std. 00304 * 00305 * Revision 1.33 2005/12/08 16:47:51 meichel 00306 * Changed include path schema for all DCMTK header files 00307 * 00308 * Revision 1.32 2004/04/21 10:00:36 meichel 00309 * Minor modifications for compilation with gcc 3.4.0 00310 * 00311 * Revision 1.31 2004/02/06 11:07:50 joergr 00312 * Distinguish more clearly between const and non-const access to pixel data. 00313 * 00314 * Revision 1.30 2004/01/05 14:52:20 joergr 00315 * Removed acknowledgements with e-mail addresses from CVS log. 00316 * 00317 * Revision 1.29 2003/12/23 15:53:22 joergr 00318 * Replaced post-increment/decrement operators by pre-increment/decrement 00319 * operators where appropriate (e.g. 'i++' by '++i'). 00320 * 00321 * Revision 1.28 2003/12/08 19:13:54 joergr 00322 * Adapted type casts to new-style typecast operators defined in ofcast.h. 00323 * Removed leading underscore characters from preprocessor symbols (reserved 00324 * symbols). Updated CVS header. 00325 * 00326 * Revision 1.27 2003/06/12 15:08:34 joergr 00327 * Fixed inconsistent API documentation reported by Doxygen. 00328 * 00329 * Revision 1.26 2003/06/02 17:06:21 joergr 00330 * Fixed bug in optimization criterion which caused dcmimgle to ignore the 00331 * "start frame" parameter in the DicomImage constructors under certain 00332 * circumstances. 00333 * 00334 * Revision 1.25 2002/10/21 10:13:51 joergr 00335 * Corrected wrong calculation of min/max pixel value in cases where the 00336 * stored pixel data exceeds the expected size. 00337 * 00338 * Revision 1.24 2002/06/26 16:05:43 joergr 00339 * Enhanced handling of corrupted pixel data and/or length. 00340 * 00341 * Revision 1.23 2001/11/13 18:10:43 joergr 00342 * Fixed bug occurring when processing monochrome images with an odd number of 00343 * pixels. 00344 * Fixed bug with incorrect calculation of min/max pixel values in images with 00345 * modality LUTs where not all LUT entries are used (previous optimization rule 00346 * was apparently too optimistic). 00347 * 00348 * Revision 1.22 2001/09/28 13:07:12 joergr 00349 * Added further robustness checks. 00350 * 00351 * Revision 1.21 2001/06/01 15:49:45 meichel 00352 * Updated copyright header 00353 * 00354 * Revision 1.20 2000/06/02 12:40:50 joergr 00355 * Removed debug message. 00356 * 00357 * Revision 1.19 2000/05/03 09:46:28 joergr 00358 * Removed most informational and some warning messages from release built 00359 * (#ifndef DEBUG). 00360 * 00361 * Revision 1.18 2000/04/28 12:32:31 joergr 00362 * DebugLevel - global for the module - now derived from OFGlobal (MF-safe). 00363 * 00364 * Revision 1.17 2000/04/27 13:08:39 joergr 00365 * Dcmimgle library code now consistently uses ofConsole for error output. 00366 * 00367 * Revision 1.16 2000/03/08 16:24:19 meichel 00368 * Updated copyright header. 00369 * 00370 * Revision 1.15 2000/03/03 14:09:12 meichel 00371 * Implemented library support for redirecting error messages into memory 00372 * instead of printing them to stdout/stderr for GUI applications. 00373 * 00374 * Revision 1.14 1999/09/17 12:26:00 joergr 00375 * Added/changed/completed DOC++ style comments in the header files. 00376 * iEnhanced efficiency of some "for" loops. 00377 * 00378 * Revision 1.13 1999/07/23 14:04:35 joergr 00379 * Optimized memory usage for converting input pixel data (reference instead 00380 * of copying where possible). 00381 * 00382 * Revision 1.12 1999/05/03 15:43:20 joergr 00383 * Replaced method applyOptimizationLUT by its contents (method body) to avoid 00384 * warnings (and possible errors) on Sun CC 2.0.1 :-/ 00385 * 00386 * Revision 1.11 1999/05/03 11:09:29 joergr 00387 * Minor code purifications to keep Sun CC 2.0.1 quiet. 00388 * 00389 * Revision 1.10 1999/04/29 16:46:45 meichel 00390 * Minor code purifications to keep DEC cxx 6 quiet. 00391 * 00392 * Revision 1.9 1999/04/28 14:50:35 joergr 00393 * Introduced new scheme for the debug level variable: now each level can be 00394 * set separately (there is no "include" relationship). 00395 * 00396 * Revision 1.8 1999/03/24 17:20:10 joergr 00397 * Added/Modified comments and formatting. 00398 * 00399 * Revision 1.7 1999/03/02 12:02:27 joergr 00400 * Corrected bug: when determining minimum and maximum pixel value (external) 00401 * modality LUTs were ignored. 00402 * 00403 * Revision 1.6 1999/02/11 16:37:10 joergr 00404 * Removed inline declarations from several methods. 00405 * 00406 * Revision 1.5 1999/02/03 17:29:19 joergr 00407 * Added optimization LUT to transform pixel data. 00408 * 00409 * Revision 1.4 1999/01/20 15:06:24 joergr 00410 * Replaced invocation of getCount() by member variable Count where possible. 00411 * Added optimization to modality and VOI transformation (using additional 00412 * LUTs). 00413 * 00414 * Revision 1.3 1998/12/22 14:29:39 joergr 00415 * Replaced method copyMem by for-loop copying each item. 00416 * Renamed some variables 00417 * 00418 * Revision 1.2 1998/12/14 17:21:09 joergr 00419 * Added support for signed values as second entry in look-up tables 00420 * (= first value mapped). 00421 * 00422 * Revision 1.1 1998/11/27 15:24:08 joergr 00423 * Added copyright message. 00424 * Added new cases to optimize rescaling. 00425 * Added support for new bit manipulation class. 00426 * Corrected bug in modality LUT transformation method. 00427 * 00428 * Revision 1.5 1998/07/01 08:39:23 joergr 00429 * Minor changes to avoid compiler warnings (gcc 2.8.1 with additional 00430 * options), e.g. add copy constructors. 00431 * 00432 * Revision 1.4 1998/05/11 14:53:21 joergr 00433 * Added CVS/RCS header to each file. 00434 * 00435 * 00436 */