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