File indexing completed on 2025-04-14 08:09:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 #include "DicomVFileImage.hh"
0027
0028 #include "DicomFileStructure.hh"
0029 #include "DicomROI.hh"
0030 #include "dcmtk/dcmdata/dcdeftag.h"
0031 #include "dcmtk/dcmdata/dcfilefo.h"
0032 #include "dcmtk/dcmdata/dcpixel.h"
0033 #include "dcmtk/dcmdata/dcpixseq.h"
0034 #include "dcmtk/dcmdata/dcpxitem.h"
0035 #include "dcmtk/dcmrt/drtimage.h"
0036
0037 #include "G4GeometryTolerance.hh"
0038
0039 #include <set>
0040
0041
0042 DicomVFileImage::DicomVFileImage()
0043 {
0044 theFileMgr = DicomFileMgr::GetInstance();
0045 }
0046
0047
0048 DicomVFileImage::DicomVFileImage(DcmDataset* dset) : DicomVFile(dset)
0049 {
0050 theFileMgr = DicomFileMgr::GetInstance();
0051 }
0052
0053
0054 void DicomVFileImage::ReadData()
0055 {
0056 std::vector<double> dImagePositionPatient = Read1Data(theDataset, DCM_ImagePositionPatient, 3);
0057 fLocation = dImagePositionPatient[2];
0058 std::vector<double> dSliceThickness = Read1Data(theDataset, DCM_SliceThickness, 1);
0059 std::vector<double> dPixelSpacing = Read1Data(theDataset, DCM_PixelSpacing, 2);
0060
0061 std::vector<double> dRows = Read1Data(theDataset, DCM_Rows, 1);
0062 std::vector<double> dColumns = Read1Data(theDataset, DCM_Columns, 1);
0063 fNoVoxelsY = dRows[0];
0064 fNoVoxelsX = dColumns[0];
0065 fNoVoxelsZ = 1;
0066
0067 fMinX = dImagePositionPatient[0];
0068 fMaxX = dImagePositionPatient[0] + dColumns[0] * dPixelSpacing[0];
0069
0070 fMinY = dImagePositionPatient[1];
0071 fMaxY = dImagePositionPatient[1] + dRows[0] * dPixelSpacing[1];
0072
0073 fMinZ = dImagePositionPatient[2] - dSliceThickness[0] / 2.;
0074 fMaxZ = dImagePositionPatient[2] + dSliceThickness[0] / 2.;
0075 fVoxelDimX = dPixelSpacing[0];
0076 fVoxelDimY = dPixelSpacing[1];
0077 fVoxelDimZ = dSliceThickness[0];
0078
0079 if (DicomFileMgr::verbose >= debugVerb)
0080 G4cout << " DicomVFileImage::ReadData: fNoVoxels " << fNoVoxelsX << " " << fNoVoxelsY << " "
0081 << fNoVoxelsZ << G4endl;
0082 if (DicomFileMgr::verbose >= debugVerb)
0083 G4cout << " DicomVFileImage::ReadData: fMin " << fMinX << " " << fMinY << " " << fMinZ
0084 << G4endl;
0085 if (DicomFileMgr::verbose >= debugVerb)
0086 G4cout << " DicomVFileImage::ReadData: fMax " << fMaxX << " " << fMaxY << " " << fMaxZ
0087 << G4endl;
0088 if (DicomFileMgr::verbose >= debugVerb)
0089 G4cout << " DicomVFileImage::ReadData: fVoxelDim " << fVoxelDimX << " " << fVoxelDimY << " "
0090 << fVoxelDimZ << G4endl;
0091
0092 std::vector<double> dImageOrientationPatient =
0093 Read1Data(theDataset, DCM_ImageOrientationPatient, 6);
0094 fOrientationRows = G4ThreeVector(dImageOrientationPatient[0], dImageOrientationPatient[1],
0095 dImageOrientationPatient[2]);
0096 fOrientationColumns = G4ThreeVector(dImageOrientationPatient[3], dImageOrientationPatient[4],
0097 dImageOrientationPatient[5]);
0098
0099 if (fOrientationRows != G4ThreeVector(1, 0, 0) || fOrientationColumns != G4ThreeVector(0, 1, 0)) {
0100 G4cerr << " OrientationRows " << fOrientationRows << " OrientationColumns "
0101 << fOrientationColumns << G4endl;
0102 G4Exception("DicomVFileImage::ReadData", "DFCT0002", JustWarning,
0103 "OrientationRows must be (1,0,0) and OrientationColumns (0,1,0), please contact "
0104 "GAMOS authors");
0105 }
0106 fBitAllocated = Read1Data(theDataset, DCM_BitsAllocated, 1)[0];
0107 if (DicomFileMgr::verbose >= 4) G4cout << " BIT ALLOCATED " << fBitAllocated << G4endl;
0108
0109 std::vector<double> dRescaleSlope = Read1Data(theDataset, DCM_RescaleSlope, 1);
0110 if (dRescaleSlope.size() == 1) {
0111 fRescaleSlope = dRescaleSlope[0];
0112 }
0113 else {
0114 fRescaleSlope = 1;
0115 }
0116 std::vector<double> dRescaleIntercept = Read1Data(theDataset, DCM_RescaleIntercept, 1);
0117 if (dRescaleIntercept.size() == 1) {
0118 fRescaleIntercept = dRescaleIntercept[0];
0119 }
0120 else {
0121 fRescaleIntercept = 1;
0122 }
0123
0124 ReadPixelData();
0125 }
0126
0127
0128 void DicomVFileImage::ReadPixelData()
0129 {
0130
0131 OFCondition result = EC_Normal;
0132
0133 DcmElement* element = NULL;
0134 result = theDataset->findAndGetElement(DCM_PixelData, element);
0135 if (result.bad() || element == NULL) {
0136 G4Exception("ReadData", "findAndGetElement(DCM_PixelData, ", FatalException,
0137 ("Element PixelData not found: " + G4String(result.text())).c_str());
0138 }
0139 DcmPixelData* dpix = NULL;
0140 dpix = OFstatic_cast(DcmPixelData*, element);
0141
0142
0143
0144 DcmPixelSequence* dseq = NULL;
0145 E_TransferSyntax xferSyntax = EXS_Unknown;
0146 const DcmRepresentationParameter* rep = NULL;
0147
0148 dpix->getOriginalRepresentationKey(xferSyntax, rep);
0149
0150 result = dpix->getEncapsulatedRepresentation(xferSyntax, rep, dseq);
0151 if (result == EC_Normal)
0152 {
0153 G4Exception("DicomVFileImage::ReadData()", "DFCT004", FatalException,
0154 "Compressed pixel data is not supported");
0155
0156 if (DicomFileMgr::verbose >= debugVerb)
0157 G4cout << " DicomVFileImage::ReadData: result == EC_Normal Reading compressed data "
0158 << std::endl;
0159 DcmPixelItem* pixitem = NULL;
0160
0161 for (int ii = 1; ii < 2; ii++) {
0162 OFCondition cond = dseq->getItem(pixitem, ii);
0163 if (!cond.good()) break;
0164 G4cout << ii << " PIX LENGTH " << pixitem->getLength() << G4endl;
0165 }
0166 if (pixitem == NULL) {
0167 G4Exception("ReadData", "dseq->getItem()", FatalException,
0168 "No DcmPixelItem in DcmPixelSequence");
0169 }
0170 Uint8* pixData = NULL;
0171
0172
0173 Uint32 length = pixitem->getLength();
0174 if (length == 0) {
0175 G4Exception("ReadData", "pixitem->getLength()", FatalException, "PixelData empty");
0176 }
0177
0178 if (DicomFileMgr::verbose >= debugVerb)
0179 G4cout << " DicomVFileImage::ReadData: number of pixels " << length << G4endl;
0180
0181 result = pixitem->getUint8Array(pixData);
0182 }
0183 else {
0184 if (fBitAllocated == 8) {
0185 Uint8* pixData = NULL;
0186 if (!(element->getUint8Array(pixData)).good()) {
0187 G4Exception("ReadData", "getUint8Array pixData, ", FatalException,
0188 ("PixelData not found: " + G4String(result.text())).c_str());
0189 }
0190 for (int ir = 0; ir < fNoVoxelsY; ir++) {
0191 for (int ic = 0; ic < fNoVoxelsX; ic++) {
0192 fHounsfieldV.push_back(pixData[ic + ir * fNoVoxelsX] * fRescaleSlope + fRescaleIntercept);
0193 }
0194 }
0195 }
0196 else if (fBitAllocated == 16) {
0197 Uint16* pixData = NULL;
0198 if (!(element->getUint16Array(pixData)).good()) {
0199 G4Exception("ReadData", "getUint16Array pixData, ", FatalException,
0200 ("PixelData not found: " + G4String(result.text())).c_str());
0201 }
0202 for (int ir = 0; ir < fNoVoxelsY; ir++) {
0203 for (int ic = 0; ic < fNoVoxelsX; ic++) {
0204 fHounsfieldV.push_back(pixData[ic + ir * fNoVoxelsX] * fRescaleSlope + fRescaleIntercept);
0205 }
0206 }
0207 }
0208 else if (fBitAllocated == 32) {
0209 Uint32* pixData = NULL;
0210 if (!(element->getUint32Array(pixData)).good()) {
0211 G4Exception("ReadData", "getUint32Array pixData, ", FatalException,
0212 ("PixelData not found: " + G4String(result.text())).c_str());
0213 }
0214 for (int ir = 0; ir < fNoVoxelsY; ir++) {
0215 for (int ic = 0; ic < fNoVoxelsX; ic++) {
0216 fHounsfieldV.push_back(pixData[ic + ir * fNoVoxelsX] * fRescaleSlope + fRescaleIntercept);
0217 }
0218 }
0219 }
0220 }
0221 }
0222
0223
0224 void DicomVFileImage::operator+=(const DicomVFileImage& rhs)
0225 {
0226 *this = *this + rhs;
0227 }
0228
0229
0230 DicomVFileImage DicomVFileImage::operator+(const DicomVFileImage& rhs)
0231 {
0232
0233 if (fNoVoxelsX != rhs.GetNoVoxelsX() || fNoVoxelsY != rhs.GetNoVoxelsY()) {
0234 G4cerr << "DicomVFileImage error adding two slice headers:\
0235 !!! Different number of voxels: "
0236 << " X= " << fNoVoxelsX << " =? " << rhs.GetNoVoxelsX() << " Y= " << fNoVoxelsY
0237 << " =? " << rhs.GetNoVoxelsY() << " Z= " << fNoVoxelsZ << " =? " << rhs.GetNoVoxelsZ()
0238 << G4endl;
0239 G4Exception("DicomVFileImage::DicomVFileImage", "", FatalErrorInArgument, "");
0240 }
0241
0242 if (fMinX != rhs.GetMinX() || fMaxX != rhs.GetMaxX() || fMinY != rhs.GetMinY()
0243 || fMaxY != rhs.GetMaxY())
0244 {
0245 G4cerr << "DicomVFileImage error adding two slice headers:\
0246 !!! Different extensions: "
0247 << " Xmin= " << fMinX << " =? " << rhs.GetMinX() << " Xmax= " << fMaxX << " =? "
0248 << rhs.GetMaxX() << " Ymin= " << fMinY << " =? " << rhs.GetMinY() << " Ymax= " << fMaxY
0249 << " =? " << rhs.GetMaxY() << G4endl;
0250 G4Exception("DicomVFileImage::operator+", "", FatalErrorInArgument, "");
0251 }
0252
0253
0254 if (fOrientationRows != rhs.GetOrientationRows()
0255 || fOrientationColumns != rhs.GetOrientationColumns())
0256 {
0257 G4cerr << "DicomVFileImage error adding two slice headers: !!!\
0258 Slices have different orientations "
0259 << " Orientation Rows = " << fOrientationRows << " & " << rhs.GetOrientationRows()
0260 << " Orientation Columns " << fOrientationColumns << " & "
0261 << rhs.GetOrientationColumns() << G4endl;
0262 G4Exception("DicomVFileImage::operator+", "", FatalErrorInArgument, "");
0263 }
0264
0265
0266 if (std::fabs(fMinZ - rhs.GetMaxZ()) > G4GeometryTolerance::GetInstance()->GetRadialTolerance()
0267 && std::fabs(fMaxZ - rhs.GetMinZ())
0268 > G4GeometryTolerance::GetInstance()->GetRadialTolerance())
0269 {
0270 G4cerr << "DicomVFileImage error adding two slice headers: !!!\
0271 Slices are not contiguous in Z "
0272 << " Zmin= " << fMinZ << " & " << rhs.GetMinZ() << " Zmax= " << fMaxZ << " & "
0273 << rhs.GetMaxZ() << G4endl;
0274 G4Exception("DicomVFileImage::operator+", "", JustWarning, "");
0275 }
0276
0277
0278 DicomVFileImage temp(*this);
0279
0280
0281 temp.SetMinZ(std::min(fMinZ, rhs.GetMinZ()));
0282 temp.SetMaxZ(std::max(fMaxZ, rhs.GetMaxZ()));
0283 temp.SetNoVoxelsZ(fNoVoxelsZ + rhs.GetNoVoxelsZ());
0284
0285 return temp;
0286 }
0287
0288
0289 void DicomVFileImage::DumpHeaderToTextFile(std::ofstream& fout)
0290 {
0291 if (DicomFileMgr::verbose >= warningVerb)
0292 G4cout << fLocation << " DumpHeaderToTextFile " << fFileName << " " << fHounsfieldV.size()
0293 << G4endl;
0294
0295 G4String fName = fFileName.substr(0, fFileName.length() - 3) + "g4dcm";
0296 std::ofstream out(fName.c_str());
0297
0298 if (DicomFileMgr::verbose >= warningVerb)
0299 G4cout << "### DicomVFileImage::Dumping Z Slice header to Text file " << G4endl;
0300
0301 G4int fCompress = theFileMgr->GetCompression();
0302 fout << fNoVoxelsX / fCompress << " " << fNoVoxelsY / fCompress << " " << fNoVoxelsZ << std::endl;
0303 fout << fMinX << " " << fMaxX << std::endl;
0304 fout << fMinY << " " << fMaxY << std::endl;
0305 fout << fMinZ << " " << fMaxZ << std::endl;
0306 }
0307
0308
0309 void DicomVFileImage::Print(std::ostream& out)
0310 {
0311 G4int fCompress = theFileMgr->GetCompression();
0312 out << "@@ CT Slice " << fLocation << G4endl;
0313
0314 out << "@ NoVoxels " << fNoVoxelsX / fCompress << " " << fNoVoxelsY / fCompress << " "
0315 << fNoVoxelsZ << G4endl;
0316 out << "@ DIM X: " << fMinX << " " << fMaxX << " Y: " << fMinY << " " << fMaxY << " Z: " << fMinZ
0317 << " " << fMaxZ << G4endl;
0318 }