File indexing completed on 2025-04-10 08:06:19
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 "DicomFileCT.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 DicomFileCT::DicomFileCT() {}
0043
0044
0045 DicomFileCT::DicomFileCT(DcmDataset* dset) : DicomVFileImage(dset) {}
0046
0047
0048 void DicomFileCT::BuildMaterials()
0049 {
0050 G4int fCompress = theFileMgr->GetCompression();
0051 if (fNoVoxelsX % fCompress != 0 || fNoVoxelsY % fCompress != 0) {
0052 G4Exception("DicompFileMgr.:BuildMaterials", "DFC004", FatalException,
0053 ("Compression factor = " + std::to_string(fCompress)
0054 + " has to be a divisor of Number of voxels X = " + std::to_string(fNoVoxelsX)
0055 + " and Y " + std::to_string(fNoVoxelsY))
0056 .c_str());
0057 }
0058
0059
0060 double meanHV = 0.;
0061 for (int ir = 0; ir < fNoVoxelsY; ir += fCompress) {
0062 for (int ic = 0; ic < fNoVoxelsX; ic += fCompress) {
0063 meanHV = 0.;
0064 int isumrMax = std::min(ir + fCompress, fNoVoxelsY);
0065 int isumcMax = std::min(ic + fCompress, fNoVoxelsX);
0066 for (int isumr = ir; isumr < isumrMax; isumr++) {
0067 for (int isumc = ic; isumc < isumcMax; isumc++) {
0068 meanHV += fHounsfieldV[isumc + isumr * fNoVoxelsX];
0069
0070 }
0071 }
0072 meanHV /= (isumrMax - ir) * (isumcMax - ic);
0073 G4double meanDens = theFileMgr->Hounsfield2density(meanHV);
0074
0075
0076 fDensities.push_back(meanDens);
0077 size_t mateID;
0078 if (theFileMgr->IsMaterialsDensity()) {
0079 mateID = theFileMgr->GetMaterialIndexByDensity(meanDens);
0080 }
0081 else {
0082 mateID = theFileMgr->GetMaterialIndex(meanHV);
0083 }
0084 fMateIDs.push_back(mateID);
0085 }
0086 }
0087 }
0088
0089
0090 void DicomFileCT::DumpMateIDsToTextFile(std::ofstream& fout)
0091 {
0092 G4int fCompress = theFileMgr->GetCompression();
0093 if (DicomFileMgr::verbose >= warningVerb)
0094 G4cout << fLocation << " DumpMateIDsToTextFile " << fFileName << " " << fMateIDs.size()
0095 << G4endl;
0096 for (int ir = 0; ir < fNoVoxelsY / fCompress; ir++) {
0097 for (int ic = 0; ic < fNoVoxelsX / fCompress; ic++) {
0098 fout << fMateIDs[ic + ir * fNoVoxelsX / fCompress];
0099 if (ic != fNoVoxelsX / fCompress - 1) fout << " ";
0100 }
0101 fout << G4endl;
0102 }
0103 }
0104
0105
0106 void DicomFileCT::DumpDensitiesToTextFile(std::ofstream& fout)
0107 {
0108 G4int fCompress = theFileMgr->GetCompression();
0109 if (DicomFileMgr::verbose >= warningVerb)
0110 G4cout << fLocation << " DumpDensitiesToTextFile " << fFileName << " " << fDensities.size()
0111 << G4endl;
0112
0113 G4int copyNo = 0;
0114 for (int ir = 0; ir < fNoVoxelsY / fCompress; ir++) {
0115 for (int ic = 0; ic < fNoVoxelsX / fCompress; ic++) {
0116 fout << fDensities[ic + ir * fNoVoxelsX / fCompress];
0117 if (ic != fNoVoxelsX / fCompress - 1) fout << " ";
0118 if (copyNo % 8 == 7) fout << G4endl;
0119 copyNo++;
0120 }
0121 if (copyNo % 8 != 0) fout << G4endl;
0122 }
0123 }
0124
0125
0126 void DicomFileCT::BuildStructureIDs()
0127 {
0128 G4int fCompress = theFileMgr->GetCompression();
0129 std::vector<DicomFileStructure*> dfs = theFileMgr->GetStructFiles();
0130 if (dfs.size() == 0) return;
0131
0132 G4int NMAXROI = DicomFileMgr::GetInstance()->GetStructureNMaxROI();
0133 G4int NMAXROI_real = std::log(INT_MAX) / std::log(NMAXROI);
0134
0135
0136 for (int ir = 0; ir < fNoVoxelsY / fCompress; ir++) {
0137 for (int ic = 0; ic < fNoVoxelsX / fCompress; ic++) {
0138
0139 fStructure.push_back(0);
0140 }
0141 }
0142
0143 std::set<double> distInters;
0144
0145
0146
0147 for (size_t ii = 0; ii < dfs.size(); ii++) {
0148 std::vector<DicomROI*> rois = dfs[ii]->GetROIs();
0149 for (size_t jj = 0; jj < rois.size(); jj++) {
0150 if (DicomFileMgr::verbose >= debugVerb)
0151 std::cout << " BuildStructureIDs checking ROI " << rois[jj]->GetNumber() << " "
0152 << rois[jj]->GetName() << G4endl;
0153 std::vector<DicomROIContour*> contours = rois[jj]->GetContours();
0154
0155 G4int roiID = rois[jj]->GetNumber();
0156 for (size_t kk = 0; kk < contours.size(); kk++) {
0157
0158 DicomROIContour* roic = contours[kk];
0159
0160
0161 if (DicomFileMgr::verbose >= debugVerb)
0162 G4cout << " " << roiID << " " << kk << " INTERS CONTOUR " << roic->GetZ() << " SLICE Z "
0163 << fMinZ << " " << fMaxZ << G4endl;
0164
0165
0166 if (roic->GetZ() > fMaxZ || roic->GetZ() < fMinZ) continue;
0167 if (DicomFileMgr::verbose >= debugVerb)
0168 G4cout << " INTERS CONTOUR WITH Z SLIZE " << fMinZ << " < " << roic->GetZ() << " < "
0169 << fMaxZ << G4endl;
0170 if (roic->GetGeomType() == "CLOSED_PLANAR") {
0171
0172 std::vector<G4ThreeVector> points = roic->GetPoints();
0173 if (DicomFileMgr::verbose >= debugVerb)
0174 G4cout << jj << " " << kk << " NPOINTS " << points.size() << G4endl;
0175 std::vector<G4ThreeVector> dirs = roic->GetDirections();
0176 double minXc = DBL_MAX;
0177 double maxXc = -DBL_MAX;
0178 double minYc = DBL_MAX;
0179 double maxYc = -DBL_MAX;
0180 for (size_t ll = 0; ll < points.size(); ll++) {
0181 minXc = std::min(minXc, points[ll].x());
0182 maxXc = std::max(maxXc, points[ll].x());
0183 minYc = std::min(minYc, points[ll].y());
0184 maxYc = std::max(maxYc, points[ll].y());
0185 }
0186 if (minXc < fMinX || maxXc > fMaxX || minYc < fMinY || maxYc > fMaxY) {
0187 G4cerr << " minXc " << minXc << " < " << fMinX << " maxXc " << maxXc << " > " << fMaxX
0188 << " minYc " << minYc << " < " << fMinY << " maxYc " << maxYc << " > " << fMaxY
0189 << G4endl;
0190 G4Exception("DicomFileCT::BuildStructureIDs", "DFCT001", JustWarning,
0191 "Contour limits exceed Z slice extent");
0192 }
0193 int idMinX = std::max(0, int((minXc - fMinX) / fVoxelDimX / fCompress));
0194 int idMaxX =
0195 std::min(fNoVoxelsX / fCompress - 1, int((maxXc - fMinX) / fVoxelDimX / fCompress + 1));
0196 int idMinY = std::max(0, int((minYc - fMinY) / fVoxelDimY / fCompress));
0197 int idMaxY =
0198 std::min(fNoVoxelsY / fCompress - 1, int((maxYc - fMinY) / fVoxelDimY / fCompress + 1));
0199 if (DicomFileMgr::verbose >= debugVerb)
0200 G4cout << " minXc " << minXc << " < " << fMinX << " maxXc " << maxXc << " > " << fMaxX
0201 << " minYc " << minYc << " < " << fMinY << " maxYc " << maxYc << " > " << fMaxY
0202 << G4endl;
0203 if (DicomFileMgr::verbose >= debugVerb)
0204 G4cout << " idMinX " << idMinX << " idMaxX " << idMaxX << " idMinY " << idMinY
0205 << " idMaxY " << idMaxY << G4endl;
0206
0207
0208 for (int ix = idMinX; ix <= idMaxX; ix++) {
0209 for (int iy = idMinY; iy <= idMaxY; iy++) {
0210 G4bool bOK = false;
0211 G4int bOKs;
0212 if (DicomFileMgr::verbose >= debugVerb)
0213 G4cout << "@@@@@ TRYING POINT (" << fMinX + fVoxelDimX * fCompress * (ix + 0.5)
0214 << "," << fMinY + fVoxelDimY * fCompress * (iy + 0.5) << ")" << G4endl;
0215
0216 for (int icx = 0; icx <= 1; icx++) {
0217 for (int icy = 0; icy <= 1; icy++) {
0218 bOKs = 0;
0219 if (bOK) continue;
0220 double p0x = fMinX + fVoxelDimX * fCompress * (ix + icx);
0221 double p0y = fMinY + fVoxelDimY * fCompress * (iy + icy);
0222 double v0x = 1.;
0223 if (icx == 1) v0x = -1.;
0224 double v0y = 0.99 * fVoxelDimY / fVoxelDimX * std::pow(-1., icy);
0225 if (DicomFileMgr::verbose >= testVerb)
0226 G4cout << ix << " + " << icx << " " << iy << " + " << icy << " CORNER (" << p0x
0227 << "," << p0y << ") "
0228 << " DIR= (" << v0x << "," << v0y << ") " << G4endl;
0229 int NTRIES = theFileMgr->GetStructureNCheck();
0230 for (int ip = 0; ip < NTRIES; ip++) {
0231 distInters.clear();
0232 v0y -= ip * 0.1 * v0y;
0233 G4double halfDiagonal = 0.5 * fVoxelDimX * fCompress;
0234 if (DicomFileMgr::verbose >= testVerb)
0235 G4cout << ip << " TRYING WITH DIRECTION ("
0236 << " DIR= (" << v0x << "," << v0y << ") " << bOKs << G4endl;
0237 for (size_t ll = 0; ll < points.size(); ll++) {
0238 double d0x = points[ll].x() - p0x;
0239 double d0y = points[ll].y() - p0y;
0240 double w0x = dirs[ll].x();
0241 double w0y = dirs[ll].y();
0242 double fac1 = w0x * v0y - w0y * v0x;
0243 if (fac1 == 0) {
0244 continue;
0245 }
0246 double fac2 = d0x * v0y - d0y * v0x;
0247 double fac3 = d0y * w0x - d0x * w0y;
0248 double lambdaq = -fac2 / fac1;
0249 if (lambdaq < 0. || lambdaq >= 1.) continue;
0250
0251 double lambdap = fac3 / fac1;
0252 if (lambdap > 0.) {
0253 distInters.insert(lambdap);
0254 if (DicomFileMgr::verbose >= testVerb)
0255 G4cout << " !! GOOD INTERS " << lambdaq << " ("
0256 << d0x + p0x + lambdaq * w0x << "," << d0y + p0y + lambdaq * w0y
0257 << ") = (" << p0x + lambdap * v0x << "," << p0y + lambdap * v0y
0258 << ") "
0259 << " N " << distInters.size() << G4endl;
0260 }
0261 if (DicomFileMgr::verbose >= testVerb)
0262 G4cout << " INTERS LAMBDAQ " << lambdaq << " P " << lambdap << G4endl;
0263
0264 if (DicomFileMgr::verbose >= debugVerb)
0265 G4cout << " INTERS POINT (" << d0x + p0x + lambdaq * w0x << ","
0266 << d0y + p0y + lambdaq * w0y << ") = (" << p0x + lambdap * v0x
0267 << "," << p0y + lambdap * v0y << ") " << G4endl;
0268 }
0269 if (distInters.size() % 2 == 1) {
0270 if (*(distInters.begin()) > halfDiagonal) {
0271
0272 bOKs += 1;
0273 if (DicomFileMgr::verbose >= debugVerb)
0274 G4cout << " OK= " << bOKs << " N INTERS " << distInters.size() << " "
0275 << *(distInters.begin()) << " > " << halfDiagonal << G4endl;
0276 }
0277 }
0278 }
0279 if (bOKs == NTRIES) {
0280 bOK = true;
0281 if (DicomFileMgr::verbose >= debugVerb)
0282 G4cout << "@@@@@ POINT OK (" << fMinX + fVoxelDimX * fCompress * (ix + 0.5)
0283 << "," << fMinY + fVoxelDimY * fCompress * (iy + 0.5) << ")" << G4endl;
0284 }
0285 }
0286 }
0287 if (bOK) {
0288
0289 int roival = fStructure[ix + iy * fNoVoxelsX / fCompress];
0290
0291 if (roival != 0 && roival != int(roiID)) {
0292 std::set<G4int> roisVoxel;
0293 int nRois = std::log10(roival) / std::log10(NMAXROI) + 1;
0294 if (nRois > NMAXROI_real) {
0295 G4Exception("DicomFileCT:BuildStructureIDs", "DFC0004", FatalException,
0296 G4String("Too many ROIs associated to a voxel: \
0297 " + std::to_string(nRois) + " > " + std::to_string(NMAXROI_real)
0298 + " TRY CHAN\
0299 GING -NStructureNMaxROI argument to a lower value")
0300 .c_str());
0301 }
0302 for (int inr = 0; inr < nRois; inr++) {
0303 roisVoxel.insert(int(roival / std::pow(NMAXROI, inr)) % NMAXROI);
0304 }
0305 roisVoxel.insert(roiID);
0306 roival = 0;
0307 size_t inr = 0;
0308 for (std::set<G4int>::const_iterator ite = roisVoxel.begin();
0309 ite != roisVoxel.end(); ite++, inr++)
0310 {
0311 roival += (*ite) * std::pow(NMAXROI, inr);
0312 }
0313 fStructure[ix + iy * fNoVoxelsX / fCompress] = roival;
0314 if (DicomFileMgr::verbose >= testVerb) {
0315 G4cout << " WITH PREVIOUS ROI IN VOXEL " << roival << G4endl;
0316 }
0317 }
0318 else {
0319 fStructure[ix + iy * fNoVoxelsX / fCompress] = roiID;
0320 }
0321 }
0322 }
0323 }
0324 }
0325 }
0326 }
0327 }
0328
0329 if (DicomFileMgr::verbose >= 1) {
0330
0331
0332 if (DicomFileMgr::verbose >= 0) G4cout << " STRUCTURES FOR SLICE " << fLocation << G4endl;
0333 for (size_t ii = 0; ii < dfs.size(); ii++) {
0334 std::vector<DicomROI*> rois = dfs[ii]->GetROIs();
0335 for (size_t jj = 0; jj < rois.size(); jj++) {
0336 int roi = rois[jj]->GetNumber();
0337 std::vector<DicomROIContour*> contours = rois[jj]->GetContours();
0338 for (size_t kk = 0; kk < contours.size(); kk++) {
0339 DicomROIContour* roic = contours[kk];
0340
0341 if (roic->GetZ() > fMaxZ || roic->GetZ() < fMinZ) continue;
0342 if (roic->GetGeomType() == "CLOSED_PLANAR") {
0343 if (DicomFileMgr::verbose >= testVerb)
0344 G4cout << " PRINTING CONTOUR? " << roi << " " << kk << " INTERS CONTOUR "
0345 << roic->GetZ() << " SLICE Z " << fMinZ << " " << fMaxZ << G4endl;
0346 if (roic->GetZ() > fMaxZ || roic->GetZ() < fMinZ) continue;
0347 std::vector<G4ThreeVector> points = roic->GetPoints();
0348 std::vector<G4ThreeVector> dirs = roic->GetDirections();
0349 if (DicomFileMgr::verbose >= 0)
0350 std::cout << " STRUCTURE Z " << roic->GetZ() << std::endl;
0351 for (size_t ll = 0; ll < points.size(); ll++) {
0352 if (DicomFileMgr::verbose >= 0)
0353 G4cout << roi << " : " << ll << " STRUCTURE POINT (" << points[ll].x() << ","
0354 << points[ll].y() << ") "
0355 << " (" << dirs[ll].x() << "," << dirs[ll].y() << ") = " << roi << G4endl;
0356 }
0357 }
0358 }
0359 }
0360 }
0361
0362 for (int ir = 0; ir < fNoVoxelsY / fCompress; ir++) {
0363 for (int ic = 0; ic < fNoVoxelsX / fCompress; ic++) {
0364 if (fStructure[ic + ir * fNoVoxelsX / fCompress] != 0) {
0365 if (DicomFileMgr::verbose >= 0)
0366 G4cout << ic + ir * fNoVoxelsX / fCompress << " = " << ic << " " << ir
0367 << " STRUCTURE VOXEL (" << fMinX + fVoxelDimX * fCompress * (ic + 0.5) << ","
0368 << fMinY + fVoxelDimY * fCompress * (ir + 0.5)
0369 << ") = " << fStructure[ic + ir * fNoVoxelsX / fCompress] << G4endl;
0370 }
0371 }
0372 }
0373 }
0374 }
0375
0376
0377 void DicomFileCT::DumpStructureIDsToTextFile(std::ofstream& fout)
0378 {
0379 G4int fCompress = theFileMgr->GetCompression();
0380 if (DicomFileMgr::verbose >= 0)
0381 G4cout << fLocation << " DumpStructureIDsToTextFile " << fFileName << " " << fStructure.size()
0382 << G4endl;
0383 std::vector<DicomFileStructure*> dfs = theFileMgr->GetStructFiles();
0384 if (dfs.size() == 0) return;
0385
0386 for (int ir = 0; ir < fNoVoxelsY / fCompress; ir++) {
0387 for (int ic = 0; ic < fNoVoxelsX / fCompress; ic++) {
0388 fout << fStructure[ic + ir * fNoVoxelsX / fCompress];
0389 if (ic != fNoVoxelsX / fCompress - 1) fout << " ";
0390 }
0391 fout << G4endl;
0392 }
0393 }