function getZoomData($uisubject, $SubjectKey, $StudyEventOID, $StudyEventRepeatKey) { require dirname(__FILE__) . "/../../../lib/nanodicom/nanodicom.php"; $importPathAnon = $uisubject->m_tblConfig["IMPORT_BASE_PATH"] . "dicom/anonymizedDICOM/"; $imageDir = $uisubject->m_tblConfig["PATH_TO_AJAXZOOM_PICT"]; $files = array(); //Populate $files array if ($handle = opendir($imageDir)) { while ($file = readdir($handle)) { if ($file != "." && $file != "..") { $fileinfo = explode("_", $file); $file_SubjectKey = $fileinfo[0]; $file_StudyEventOID = $fileinfo[1]; $file_StudyEventRepeatKey = $fileinfo[2]; if ($file_SubjectKey == $SubjectKey && $file_StudyEventOID == $StudyEventOID && $file_StudyEventRepeatKey == $StudyEventRepeatKey) { $files[$file] = $file; } } } closedir($handle); } ksort($files); $zoomData = array(); $i = 1; foreach ($files as $file) { $zoomData[$i]['f'] = $file; // File $zoomData[$i]['p'] = "/pic/zoom/dicom/"; // Path $i++; } $dicomFilename = $importPathAnon . substr($zoomData[1]['f'], 0, strpos($zoomData[1]['f'], ".")); $dicom = Nanodicom::factory($dicomFilename, 'simple'); $dicom->parse(array('PixelSpacing')); $pixArr = explode("\\", $dicom->PixelSpacing); $pixelSpacingH = $pixArr[0]; $pixelSpacingV = $pixArr[1]; //Turn the array $zoomData into a string that can be passed over query string in one variable $zoomData = strtr(base64_encode(addslashes(gzcompress(serialize($zoomData), 9))), '+/=', '-_,'); $zoomDatas = array($zoomData, $i - 1, $pixelSpacingH, $pixelSpacingV); return $zoomDatas; }
/** */ public function provider() { $samples_dir = realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR; $output_dir = realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR; $files = array(); if ($handle = opendir($samples_dir)) { while (false !== ($file = readdir($handle))) { if ($file != "." && $file != ".." && is_file($samples_dir . $file)) { $files[] = $file; } } closedir($handle); } $data = array(); foreach ($files as $file) { $filename = $samples_dir . $file; $dicom = Nanodicom::factory($filename); $data[] = array($dicom->summary(), file_get_contents($output_dir . $file . '.summary.txt')); unset($dicom); } return $data; }
/** * Parses the object. * * If the list of elements has a tag name, dictionaries will be loaded. For performance * is better to pass only arrays of the form: * array(group, element) where group and element are numbers (hex or decimal equivalents or any other base). * @param mixed array for a list of elements tags to read. parsing stops when all found. Or TRUE to force * load dictionaries when parsing. This tool force the reading of dictionaries * @param boolean a flag to test if dicom file has DCM header only. * @return this */ public function parse($vr_reading_list = TRUE, $check_dicom_preamble = FALSE) { return parent::parse($vr_reading_list, $check_dicom_preamble); }
function DisplayCTSeries($id, $study_num, $uid, $audit, $fix) { /* get the subject information */ $sqlstring = "select * from subjects a left join enrollment b on a.subject_id = b.subject_id left join studies c on b.enrollment_id = c.enrollment_id where c.study_id = $id"; $result = MySQLQuery($sqlstring, __FILE__, __LINE__); if (mysql_num_rows($result) > 0) { $row = mysql_fetch_array($result, MYSQL_ASSOC); $dbsubjectname = $row['name']; $dbsubjectdob = $row['birthdate']; $dbsubjectsex = $row['gender']; $dbstudydatetime = $row['study_datetime']; } else { echo "$sqlstring<br>"; } ?> <!--<a href="studies.php?id=<?$id?>&action=addseries&modality=CT">Add Series</a>--> <style type="text/css"> .edit_inline { background-color: lightyellow; padding-left: 2pt; padding-right: 2pt; } .edit_textarea { background-color: lightyellow; } textarea.inplace_field { background-color: white; font-family: courier new; font-size: 8pt; border: 1pt solid gray; width: 800px; } input.inplace_field { background-color: white; font-size: 8pt; border: 1pt solid gray; width: 200px; } </style> <span class="smallnote"><b>Upload file(s) by clicking the button or drag-and-drop (Firefox and Chrome only)</b><br> DICOM files will only be associated with the study under which they were originally run... If you upload files from a different study, they won't show up here.</span> <br><br> <div id="file-uploader-demo1"> <noscript> <p>Please enable JavaScript to use file uploader.</p> <!-- or put a simple form for upload here --> </noscript> </div> <br> <table class="smalldisplaytable" width="100%"> <thead> <tr> <th>Series</th> <th>Desc</th> <th>Protocol</th> <th>Time</th> <th>Notes</th> <th>Contrast</th> <th>Body part</th> <th>Options</th> <th>KVP</th> <th>Collection Dia</th> <th>Contrast Route</th> <th>Rotation Dir</th> <th>Exposure</th> <th>Tube current</th> <th>Filter type</th> <th>Power</th> <th>Kernel</th> <th>Spacing</th> <th>Image size</th> <th># files</th> <th>Size</th> </tr> </thead> <tbody> <? $sqlstring = "select * from ct_series where study_id = $id order by series_num"; $result = MySQLQuery($sqlstring, __FILE__, __LINE__); while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) { $ctseries_id = $row['ctseries_id']; $series_datetime = date('g:ia',strtotime($row['series_datetime'])); $series_desc = $row['series_desc']; $protocol = $row['series_protocol']; $sequence = $row['series_sequencename']; $series_num = $row['series_num']; $series_contrastbolusagent = $row['series_contrastbolusagent']; $series_bodypartexamined = $row['series_bodypartexamined']; $series_scanoptions = $row['series_scanoptions']; $series_kvp = $row['series_kvp']; $series_datacollectiondiameter = $row['series_datacollectiondiameter']; $series_contrastbolusroute = $row['series_contrastbolusroute']; $series_rotationdirection = $row['series_rotationdirection']; $series_exposuretime = $row['series_exposuretime']; $series_xraytubecurrent = $row['series_xraytubecurrent']; $series_filtertype = $row['series_filtertype']; $series_generatorpower = $row['series_generatorpower']; $series_convolutionkernel = $row['series_convolutionkernel']; $series_spacingx = $row['series_spacingx']; $series_spacingy = $row['series_spacingy']; $series_spacingz = $row['series_spacingz']; $img_rows = $row['series_imgrows']; $img_cols = $row['series_imgcols']; $img_slices = $row['series_imgslices']; $numfiles = $row['numfiles']; $series_size = $row['series_size']; $series_status = $row['series_status']; $series_notes = $row['series_notes']; $data_type = $row['data_type']; $lastupdate = $row['lastupdate']; if ( (preg_match("/epfid2d1/i",$sequence)) && ($numfiles_beh < 1)) { $behcolor = "red"; } else { $behcolor = ""; } if ($numfiles_beh < 1) { $numfiles_beh = "-"; } $thumbpath = $GLOBALS['cfg']['archivedir'] . "/$uid/$study_num/$series_num/thumb.png"; $realignpath = $GLOBALS['cfg']['archivedir'] . "/$uid/$study_num/$series_num/MotionCorrection.txt"; /* --- audit the dicom files --- */ if ($audit) { $dicoms = glob($GLOBALS['cfg']['archivedir'] . "/$uid/$study_num/$series_num/dicom/*.dcm"); //print_r($dicoms); $dcmcount = count($dicoms); $dupes = null; if ($dcmcount > 0) { //$filename = $dicoms[0]; $mergeddcms = null; foreach ($dicoms as $dcmfile) { $dicom = Nanodicom::factory($dcmfile, 'simple'); $dicom->parse(array(array(0x0010, 0x0010), array(0x0010, 0x0030), array(0x0010, 0x0040), array(0x0018, 0x1030), array(0x0008, 0x103E), array(0x0010, 0x0020), array(0x0020, 0x0012), array(0x0020, 0x0013), array(0x0008, 0x0020), array(0x0008, 0x0030), array(0x0008, 0x0032))); $dicom->profiler_diff('parse'); $filesubjectname = trim($dicom->value(0x0010, 0x0010)); $filesubjectdob = trim($dicom->value(0x0010, 0x0030)); $filesubjectsex = trim($dicom->value(0x0010, 0x0040)); $fileprotocol = trim($dicom->value(0x0018, 0x1030)); $fileseriesdesc = trim($dicom->value(0x0008, 0x103E)); $fileseriesnum = trim($dicom->value(0x0020, 0x0011)); $filescanid = trim($dicom->value(0x0010, 0x0020)); $fileinstancenumber = trim($dicom->value(0x0020, 0x0013)); $fileslicenumber = trim($dicom->value(0x0020, 0x0012)); $fileacquisitiontime = trim($dicom->value(0x0008, 0x0032)); $filestudydate = trim($dicom->value(0x0008, 0x0020)); $filestudytime = trim($dicom->value(0x0008, 0x0030)); unset($dicom); //echo "<pre>$fileprotocol, $protocol -- $fileslicenumber, $fileinstancenumber - [$filestudydate $filestudytime] - [$dbstudydatetime]</pre><br>"; $filestudydatetime = $filestudydate . substr($filestudytime,0,6); $dbstudydatetime = str_replace(array(":","-"," "),"",$dbstudydatetime); $dbsubjectdob = str_replace(array(":","-"," "),"",$dbsubjectdob); if ( ($fileprotocol != $protocol) || ($dbsubjectname != $filesubjectname) || ($dbsubjectdob != $filesubjectdob) || ($dbsubjectsex != $filesubjectsex) || ($series_num != $fileseriesnum) || ($filestudydatetime != $dbstudydatetime) ) { if ($fileprotocol != $protocol) { //echo "Protocol does not match (File: $fileprotocol DB: $protocol)<br>"; //echo "files don't match DB<br>"; $errantdcms[]{'filename'} = $dcmfile; $errantdcms[]{'error'} = "Protocol does not match (File: $fileprotocol DB: $protocol)"; } if (strcasecmp($dbsubjectname,$filesubjectname) != 0) { if (($dbsubjectname == "") && ($filesubjectname) != "") { //echo "Patient name does not match (File: $filesubjectname DB: $dbsubjectname)<br>"; $errantdcms[]{'filename'} = $dcmfile; $errantdcms[]{'error'} = "Patient name does not match (File: $filesubjectname DB: $dbsubjectname)"; } elseif (($filesubjectname == "") && ($dbsubjectname) != "") { //echo "Patient name does not match (File: $filesubjectname DB: $dbsubjectname)<br>"; $errantdcms[]{'filename'} = $dcmfile; $errantdcms[]{'error'} = "Patient name does not match (File: $filesubjectname DB: $dbsubjectname)"; } else { if ((stristr($dbsubjectname, $filesubjectname) === false) && (stristr($filesubjectname, $dbsubjectname) === false)) { //echo "Patient name does not match (File: $filesubjectname DB: $dbsubjectname)<br>"; $errantdcms[]{'filename'} = $dcmfile; $errantdcms[]{'error'} = "Patient name does not match (File: $filesubjectname DB: $dbsubjectname)"; } } } if ($dbsubjectdob != $filesubjectdob) { //echo "Patient DOB does not match (File: $filesubjectdob DB: $dbsubjectdob)<br>"; $errantdcms[]{'filename'} = $dcmfile; $errantdcms[]{'error'} = "Patient DOB does not match (File: $filesubjectdob DB: $dbsubjectdob)"; } if ($dbsubjectsex != $filesubjectsex) { //echo "Patient sex does not match (File: $filesubjectsex DB: $dbsubjectsex)<br>"; $errantdcms[]{'filename'} = $dcmfile; $errantdcms[]{'error'} = "Patient sex does not match (File: $filesubjectsex DB: $dbsubjectsex)"; } if ($series_num != $fileseriesnum) { //echo "Series number does not match (File: $fileseriesnum DB: $series_num)<br>"; $errantdcms[]{'filename'} = $dcmfile; $errantdcms[]{'error'} = "Series number does not match (File: $fileseriesnum DB: $series_num)"; } if ($filestudydatetime != $dbstudydatetime) { //echo "Study datetime does not match (File: $filestudydatetime DB: $dbstudydatetime)<br>"; $errantdcms[]{'filename'} = $dcmfile; $errantdcms[]{'error'} = "Study datetime does not match (File: $filestudydatetime DB: $dbstudydatetime)"; } } //$mergeddcms{$filesubjectname}{$filesubjectdob}{$filesubjectsex}{$filestudydate}{$filestudytime}{$fileseriesnum}{$fileslicenumber}{$fileinstancenumber} = $dcmfile; $mergeddcms{$filesubjectname}{$filesubjectdob}{$filesubjectsex}{$filestudydate}{$filestudytime}{$fileseriesnum}{$fileslicenumber}{$fileinstancenumber}{$fileacquisitiontime}++; if ($mergeddcms{$filesubjectname}{$filesubjectdob}{$filesubjectsex}{$filestudydate}{$filestudytime}{$fileseriesnum}{$fileslicenumber}{$fileinstancenumber}{$fileacquisitiontime} > 1) { /* check the MD5 hash to see if the files really are the same */ //$hash1 = md5_file( echo "Series $fileseriesnum contains duplicate files<br>"; $dupes[$series_num] = 1; if ($fix) { /* move the duplicate file to the dicom/extra directory */ if (!file_exists($GLOBALS['cfg']['archivedir'] . "/$uid/$study_num/$series_num/dicom/duplicates")) { mkdir($GLOBALS['cfg']['archivedir'] . "/$uid/$study_num/$series_num/dicom/duplicates"); } echo "Moving [$dcmfile] -> [" . $GLOBALS['cfg']['archivedir'] . "/$uid/$study_num/$series_num/dicom/duplicates/" . GenerateRandomString(20) . ".dcm]<br>"; rename($dcmfile, $GLOBALS['cfg']['archivedir'] . "/$uid/$study_num/$series_num/dicom/duplicates/" . GenerateRandomString(20) . ".dcm"); } } } } echo "<pre>"; //print_r($mergeddcms); print_r($errantdcms); echo "</pre>"; /* move the errant files */ if ($fix) { for($i=0;$i<count($errantdcms);$i++) { echo "Moving [$errantdcms[$i]{'filename'}] -> [" . $GLOBALS['dicomincomingpath'] . "/" . GenerateRandomString(20) . ".dcm]<br>"; rename($errantdcms[$i]{'filename'},$GLOBALS['dicomincomingpath'] . "/" . GenerateRandomString(20) . ".dcm"); } /* rename the files in the directory */ $dicoms = glob($GLOBALS['cfg']['archivedir'] . "/$uid/$study_num/$series_num/dicom/*.dcm"); //print_r($dicoms); $dcmcount = count($dicoms); if ($dcmcount > 0) { $dcmsize = 0; foreach ($dicoms as $dcmfile) { $dicom = Nanodicom::factory($dcmfile, 'simple'); $dicom->parse(array(array(0x0010, 0x0010), array(0x0010, 0x0030), array(0x0010, 0x0040), array(0x0018, 0x1030), array(0x0008, 0x103E), array(0x0010, 0x0020), array(0x0020, 0x0012), array(0x0020, 0x0013), array(0x0008, 0x0020), array(0x0008, 0x0030), array(0x0008, 0x0032))); $dicom->profiler_diff('parse'); $fileseriesnum = trim($dicom->value(0x0020, 0x0011)); $fileinstancenumber = trim($dicom->value(0x0020, 0x0013)); $fileslicenumber = trim($dicom->value(0x0020, 0x0012)); $fileacquisitiontime = trim($dicom->value(0x0008, 0x0032)); unset($dicom); $dcmsize += filesize($dcmfile); $newdcmfile = $GLOBALS['cfg']['archivedir'] . "/$uid/$study_num/$series_num/dicom/$uid" . "_$study_num" . "_$series_num" . "_" . sprintf("%05d",$fileslicenumber) . "_" . sprintf("%05d",$fileinstancenumber) . "_$fileacquisitiontime.dcm"; //if (file_exists($newdcmfile)) { /* some DTI files are weird, so we'll append the aquisition time */ //} echo "$dcmfile --> $newdcmfile<br>"; rename($dcmfile, $newdcmfile); } /* update the database with the new info */ $sqlstring5 = "update ct_series set series_size = $dcmsize, numfiles = $dcmcount where ctseries_id = $ctseries_id"; $result5 = MySQLQuery($sqlstring5, __FILE__, __LINE__); } } } ?> <script type="text/javascript"> $(document).ready(function(){ $(".edit_inline<? echo $ctseries_id; ?>").editInPlace({ url: "series_inlineupdate.php", params: "action=editinplace&modality=CT&id=<? echo $ctseries_id; ?>", default_text: "<i style='color:#AAAAAA'>Add notes...</i>", bg_over: "white", bg_out: "lightyellow", }); }); </script> <tr> <td><?php echo $series_num; ?> <? if ($dupes[$series_num] == 1) { ?><span style="color: white; background-color: red; padding: 1px 5px; font-weight: bold; font-size: 8pt">Contains duplicates</span> <? } ?> </td> <td><?php echo $series_desc; ?> </td> <td><?php echo $protocol; ?> <a href="preview.php?image=<?php echo $thumbpath; ?> " class="preview"><img src="images/preview.gif" border="0"></a></td> <td><?php echo $series_datetime; ?> </td> <td><span id="series_notes" class="edit_inline<? echo $ctseries_id; ?>" style="background-color: lightyellow; padding: 1px 3px; font-size: 8pt;"><? echo $series_notes; ?></span></td> <td><?php echo $series_contrastbolusagent; ?> </td> <td><?php echo $series_bodypartexamined; ?> </td> <td><?php echo $series_scanoptions; ?> </td> <td><?php echo $series_kvp; ?> <span class="tiny">V</span></td> <td><?php echo $series_datacollectiondiameter; ?> <span class="tiny">mm</span></td> <td><?php echo $series_contrastbolusroute; ?> </td> <td><?php echo $series_rotationdirection; ?> </td> <td><?php echo $series_exposuretime; ?> <span class="tiny">ms</span></td> <td><?php echo $series_xraytubecurrent; ?> <span class="tiny">mA</span></td> <td><?php echo $series_filtertype; ?> </td> <td><?php echo $series_generatorpower; ?> <span class="tiny">V</span></td> <td><?php echo $series_convolutionkernel; ?> </td> <td><?php echo number_format($series_spacingx, 1); ?> × <?php echo number_format($series_spacingy, 1); ?> × <?php echo number_format($series_spacingz, 1); ?> </td> <td><?php echo $img_cols; ?> × <?php echo $img_rows; ?> × <?php echo $img_slices; ?> </td> <td> <?php echo $numfiles; ?> <? if (($dcmcount != $numfiles) && ($audit)) { ?><span style="color: white; background-color: red; padding: 1px 5px; font-weight: bold"><?php echo $dcmcount; ?> </span> <? } ?> </td> <td nowrap><?php echo HumanReadableFilesize($series_size); ?> <a href="download.php?modality=ct&type=dicom&seriesid=<?php echo $ctseries_id; ?> " border="0"><img src="images/download16.png" title="Download <?php echo $data_type; ?> data"></a></td> </tr> <? } ?> </tbody> </table> <? }
/** * Public method to get the summary of the given file. * * @param string how the output is returned. Either as string (ready to be echoed) or array * @return mixed|false Either a string, array or FALSE (when file is not DICOM) */ public function summary($output = 'string') { // Parse the file $this->parse(); $transfer_syntax = trim($this->get(0x2, 0x10, 'UN')); $transfer_syntax .= ($transfer_syntax == 'UN' or !array_key_exists($transfer_syntax, Nanodicom_Dictionary::$transfer_syntaxes)) ? ' - Unknow' : ' - Parsed using: ' . Nanodicom_Dictionary::$transfer_syntaxes[$transfer_syntax][0]; //.'. Parsed using: '.Nanodicom_Dictionary::$transfer_syntaxes[$this->_transfer_syntax][0]; if ($transfer_syntax == 'UN - Unknow') { $transfer_syntax .= ' [Parsed Using: ' . $this->_transfer_syntax . ' - ' . Nanodicom_Dictionary::$transfer_syntaxes[$this->_transfer_syntax][0] . ']'; } // Checking for "rows" since that value should be set for images. $has_images = $this->get(0x28, 0x10, 'N/A') != 'N/A' ? 'YES' : 'NO'; $statuses = array('Not parsed yet', 'Partially parsed. Some tags were found', 'Successfully parsed!', 'Failed'); $values = array('Filename: ' => basename($this->_location), 'Transfer Syntax: ' => $transfer_syntax, 'DICOM file? ' => $statuses[$this->status], 'Has DCM preamble? ' => $this->has_dicom_preamble === TRUE ? 'YES' : 'NO', 'Has Metadata? ' => $this->get(0x2, 0x0, FALSE) ? 'YES' : 'NO', 'Modality: ' => $this->get(0x8, 0x60, 'UN'), 'Patient Name: ' => $this->get(0x10, 0x10, 'N/A'), 'Images? ' => $has_images); $pixel_representation = array('0' => 'Unsigned Integer. Only positive values allowed.', '1' => '2\'s complement. Negative and positive allowed.', 'N/A' => 'Not available'); $planar_configuration = array('0' => 'Color-by-pixel: RGB, RGB, RGB..', '1' => 'Color-by-plane: RRR..., GGG..., BBB...', 'N/A' => 'Not available'); if ($has_images == 'YES') { $values = $values + array('Rows: ' => $this->get(0x28, 0x10, 'N/A'), 'Cols: ' => $this->get(0x28, 0x11, 'N/A'), 'Samples per pixel: ' => $this->get(0x28, 0x2, 'N/A'), 'Bits Allocated: ' => $this->get(0x28, 0x100, 'N/A'), 'Bits Stored: ' => $this->get(0x28, 0x101, 'N/A'), 'High bit: ' => $this->get(0x28, 0x102, 'N/A'), 'Dose scaling: ' => $this->get(0x3004, 0xe, 'N/A'), 'Window Width: ' => $this->get(0x28, 0x1051, 'N/A'), 'Window Center: ' => $this->get(0x28, 0x1050, 'N/A'), 'Rescale intercept: ' => $this->get(0x28, 0x1052, 'N/A'), 'Rescale slope: ' => $this->get(0x28, 0x1053, 'N/A'), 'Number of Frames: ' => $this->get(0x28, 0x8, 'N/A'), 'Photometric Inter: ' => $this->get(0x28, 0x4, 'N/A'), 'Px Representation: ' => $this->get(0x28, 0x103, 'N/A') . ' - ' . Nanodicom::array_get($pixel_representation, $this->get(0x28, 0x103, 'N/A'), 'Wrong'), 'Planar Config: ' => $this->get(0x28, 0x6, 'N/A') . ' - ' . Nanodicom::array_get($planar_configuration, $this->get(0x28, 0x6, 'N/A'), 'Wrong')); } if ($output == 'string') { $output = ''; foreach ($values as $index => $value) { $output .= $index . "\t" . $value . "\n"; } // Set the output back to values $values = $output; } return $values; }
$result = mysql_query($sqlstring) or die("Query failed: " . mysql_error() . "<br><i>{$sqlstring}</i><br>"); $row = mysql_fetch_array($result, MYSQL_ASSOC); if (mysql_num_rows($result) > 0) { $found = 1; $seriesid = $row['ppiseries_id']; } if ($found) { /* check the dicom files */ $dicoms = glob("{$archivedir}/{$subject}/{$study}/{$series}/dicom/*.dcm"); //print_r($dicoms); $dcmcount = count($dicoms); if ($dcmcount > 0) { $filename = $dicoms[0]; //echo "$filename\n"; /* open the dicom file, check the 3 important tags */ $dicom = Nanodicom::factory($filename, 'simple'); $dicom->parse(array(array(0x10, 0x10), array(0x10, 0x30), array(0x10, 0x40))); /* patient name,dob,sex */ // Only a small subset of the dictionary entries were loaded $dicom->profiler_diff('parse'); //echo 'Patient name if exists: '.$dicom->value(0x0010, 0x0010)."\n"; // Patient Name if exists // This will return nothing because dictionaries were not loaded //echo 'Patient name should be empty here: '.$dicom->PatientName."\n"; $filesubjectname = trim($dicom->value(0x10, 0x10)); $filesubjectdob = trim($dicom->value(0x10, 0x30)); $filesubjectsex = trim($dicom->value(0x10, 0x40)); $fileprotocol = trim($dicom->value(0x18, 0x1030)); $fileseriesdesc = trim($dicom->value(0x8, 0x103e)); $filescanid = trim($dicom->value(0x10, 0x20)); //print_r($dicom); if (strcasecmp($subjectname, $filesubjectname) != 0) {
/** * Public method to get the images from the dicom object * * @param integer a default window width * @param integer a default window center * @return mixed false if something is missing or not image data found, otherwise an * array of GD objects */ public function get_images($width = NULL, $center = NULL) { // Parse the object if not parsed yet $this->parse(); // Set the profiler $this->profiler['pixel']['start'] = microtime(TRUE); $return = $this->_check_driver(); // If FALSE, driver not found if (!$return) { return FALSE; } // Supported transfer syntaxes if (!array_key_exists(trim($this->_transfer_syntax), self::$reading_image_transfer_syntaxes)) { // Not supported transfer syntax found throw new Nanodicom_Exception('Transfer syntax ":syntax" not supported', array(':syntax' => $this->_transfer_syntax), 300); } // Let's read some values from DICOM file $rows = $this->get(0x28, 0x10); $cols = $this->get(0x28, 0x11); if ($rows == NULL or $cols === NULL) { // There is no rows, no samples per pixel, no pixel data or malformed dicom file throw new Nanodicom_Exception('There is no rows, no samples per pixel, no pixel data or malformed dicom file', NULL, 301); } $samples_per_pixel = $this->get(0x28, 0x2, 1); $bits_allocated = $this->get(0x28, 0x100); $bits_stored = $this->get(0x28, 0x101); $high_bit = $this->get(0x28, 0x102); $dose_scaling = $this->get(0x3004, 0xe, 1); $window_width = $width == NULL ? $this->get(0x28, 0x1051, 0) : $width; $window_center = $center == NULL ? $this->get(0x28, 0x1050, 0) : $center; $rescale_intercept = $this->get(0x28, 0x1052, 0); $rescale_slope = $this->get(0x28, 0x1053, 1); $number_of_frames = (int) $this->get(0x28, 0x8, 1); $pixel_representation = $this->get(0x28, 0x103); $photometric_interpretation = trim($this->get(0x28, 0x4, 'NONE')); $planar_configuration = $this->get(0x28, 0x6, 0); $transfer_syntax_uid = trim($this->get(0x2, 0x10)); $blob = $this->get(0x7fe0, 0x10); // Save some values for internal use // TODO: improve this, probably using $this->pixeler[]? $this->_rows = $rows; $this->_cols = $cols; $this->_dose_scaling = $dose_scaling; $this->_rescale_slope = $rescale_slope; $this->_rescale_intercept = $rescale_intercept; $this->_samples_per_pixel = $samples_per_pixel; $this->_pixel_representation = $pixel_representation; // Window Center and Width can have multiple values. By now, just reading the first one. // It assumes the delimiter is the "\" if (!(strpos($window_center, "\\") === FALSE)) { $temp = explode("\\", $window_center); $window_center = (int) $temp[0]; } if (!(strpos($window_width, "\\") === FALSE)) { $temp = explode("\\", $window_width); $window_width = (int) $temp[0]; } // Setting some values $images = array(); $max = array(); $min = array(); $current_position = $starting_position = 0; $current_image = 0; $bytes_to_read = (int) $bits_allocated / 8; $image_size = $cols * $rows * $samples_per_pixel * $bytes_to_read; list($vr_mode, $endian) = Nanodicom::decode_transfer_syntax($transfer_syntax_uid); $this->_vr_mode = $vr_mode; $this->_endian = $endian; if ($transfer_syntax_uid == '1.2.840.10008.1.2.4.50') { // This is jpeg lossy 8-bits. Just get the data. $images = array(); $counter = 0; foreach ($blob as $group => $elements) { foreach ($elements as $element => $indexes) { if ($element == Nanodicom::SEQUENCE_DELIMITER) { continue; } foreach ($indexes as $values) { $data = $values; if ($counter == 0) { // Read Basic Offset Table } else { // It is a real Item if (!isset($data['done'])) { // Read value if not read yet $this->_read_value_from_blob($data, $group, $element); } $images[] = $this->_read_image_blob($data['val']); } $counter++; } } } return $images; } if ($transfer_syntax_uid == '1.2.840.10008.1.2.5') { // It is "RLE - Run Length Encoding, Lossless" $counter = 0; $temp = array(); foreach ($blob as $group => $elements) { foreach ($elements as $element => $indexes) { if ($element == Nanodicom::SEQUENCE_DELIMITER) { continue; } foreach ($indexes as $values) { $data = $values; $data['g'] = $group; $data['e'] = $element; if ($counter == 0) { // Read Basic Offset Table } else { // It is a real Item $dir = realpath(dirname($this->_location)) . DIRECTORY_SEPARATOR; $file = basename($this->_location); if (!isset($data['done'])) { // Read value if not read yet $this->_read_value_from_blob($data, $group, $element); } // This is the item data $item = $data['val']; // Save the header $header = array(); // 16 Unsigned Long values for ($i = 0; $i <= 16; $i++) { $chunk = substr($item, 4 * $i, 4); $header[] = $this->{Nanodicom::$_read_int}(4, Nanodicom::LITTLE_ENDIAN, 4, Nanodicom::UNSIGNED, $chunk); } $total_segments = array_shift($header); $segment_index = 0; foreach ($header as $starting_byte_of_segment) { // This is a segment, do the uncompression if ($starting_byte_of_segment == 0) { // Only process if the segment has a positive starting value break; } $size_of_segment = $header[$segment_index + 1] == 0 ? strlen($item) - $starting_byte_of_segment : $header[$segment_index + 1] - $starting_byte_of_segment; $temp[$counter - 1][$segment_index] = ''; $expected_segment_size = $cols * $rows * $bytes_to_read / $total_segments; $bytes_count = $current_segment_size = 0; while ($bytes_count < $size_of_segment) { $tmp = $starting_byte_of_segment + $bytes_count; // Read "n" $n = substr($item, $starting_byte_of_segment + $bytes_count, 1); $n = $this->{Nanodicom::$_read_int}(1, Nanodicom::LITTLE_ENDIAN, 1, Nanodicom::SIGNED, $n); // Add 1 $bytes_count++; if ($n >= 0 and $n <= 127) { $temp[$counter - 1][$segment_index] .= substr($item, $starting_byte_of_segment + $bytes_count, $n + 1); $bytes_count = $bytes_count + $n + 1; $current_segment_size = $current_segment_size + $n + 1; } elseif ($n <= -1 and $n >= -127) { $byte = substr($item, $starting_byte_of_segment + $bytes_count, 1); $temp[$counter - 1][$segment_index] .= str_repeat($byte, -$n + 1); $bytes_count++; $current_segment_size = $current_segment_size - $n + 1; } else { // Do nothing } } $segment_index++; } } // Increment counter $counter++; } } } $counter--; $blob = ''; for ($count = 0; $count < $counter; $count++) { if ($photometric_interpretation == 'RGB') { if ($planar_configuration == 1) { // Color-by-plane: RRR..., GGG..., BBB... $blob .= implode('', $temp[$count]); } else { // Color-by-pixel: RGB, RGB, RGB.. } } else { $dimension = $cols * $rows; for ($i = 0; $i < $dimension; $i++) { $part = ''; foreach ($temp[$count] as $segment) { $part = substr($segment, $i, 1) . $part; } $blob .= $part; } } } } // Blob here has "uncompressed" data (from raw or RLE) if ($photometric_interpretation == 'PALETTE COLOR') { $this->_samples_per_pixel = 3; $palettes = array(); $palettes['R'] = array($this->get(0x28, 0x1101), $this->get(0x28, 0x1201)); $palettes['G'] = array($this->get(0x28, 0x1102), $this->get(0x28, 0x1202)); $palettes['B'] = array($this->get(0x28, 0x1103), $this->get(0x28, 0x1203)); $palettes['A'] = array($this->get(0x28, 0x1104), $this->get(0x28, 0x1204)); $entries = (int) $palettes['R'][0]['val1']; $entries = $entries == 0 ? pow(2, 16) : $entries; $first = $palettes['R'][0]['val2']; $size = $palettes['R'][0]['val3']; $palette_byte_size = (int) $size / 8; $offset = 8; $current_position = 0; $colors = array('R', 'G', 'B'); // Now let's create the right values for the images for ($index = 0; $index < $number_of_frames; $index++) { // Create the image object $image = self::create_image($cols, $rows); for ($y = 0; $y < $rows; $y++) { for ($x = 0; $x < $cols; $x++) { $rgb = array(); $value = $this->_read_gray($blob, $current_position, $bytes_to_read); $palette_index = $value <= $first ? $first : ($value > $first + $entries ? $first + $entries - 1 : $value); $current_position += $bytes_to_read; for ($sample = 0; $sample < 3; $sample++) { $tmp = $this->_read_gray($palettes[$colors[$sample]][1], $palette_byte_size * $palette_index, $palette_byte_size); $rgb[$sample] = $tmp >> 8; } // Set the color $color = $this->_allocate_color_rgb($image, $rgb); $rgb = NULL; // Set the pixel value $this->_set_pixel($image, $x, $y, $color); $color = NULL; } } // Append the current image $images[] = $image; $image = NULL; } return $images; } else { // Do this if no window center and window width are set and when samples per pixel is 1 (gray images). if (($window_center == 0 or $window_width == 0) and $samples_per_pixel == 1) { $length = strlen($blob); // This is costly performance wise! :( while ($current_position < $starting_position + $length) { if ($current_position == $starting_position + $current_image * $image_size) { // A new image has been found $x = 0; $y = 0; $max[$current_image] = -200000; // Small enough so it will be properly calculated $min[$current_image] = 200000; // Large enough so it wil be properly calculated $current_image++; } $gray = $this->_read_gray($blob, $current_position, $bytes_to_read); $current_position += $bytes_to_read; // Getting the max if ($gray > $max[$current_image - 1]) { // max $max[$current_image - 1] = $gray; } // Getting the min if ($gray < $min[$current_image - 1]) { // min $min[$current_image - 1] = $gray; } $y++; if ($y == $cols) { // Next row $x++; $y = 0; } } } } $current_position = $starting_position = 0; // Now let's create the right values for the images for ($index = 0; $index < $number_of_frames; $index++) { if ($samples_per_pixel == 1) { // Real max and min according to window center & width (if set) $maximum = ($window_center != 0 and $window_width != 0) ? round($window_center + $window_width / 2) : $max[$index]; $minimum = ($window_center != 0 and $window_width != 0) ? round($window_center - $window_width / 2) : $min[$index]; // Check if window and level are sent $maximum = (!empty($window) and !empty($level)) ? round($level + $window / 2) : $maximum; $minimum = (!empty($window) and !empty($level)) ? round($level - $window / 2) : $minimum; if ($maximum == $minimum) { // Something wrong. Avoid having a zero division throw new Nanodicom_Exception('Division by zero', NULL, 302); } } // Create the image object $image = self::create_image($cols, $rows); $pixels = array(); for ($y = 0; $y < $rows; $y++) { for ($x = 0; $x < $cols; $x++) { switch ($samples_per_pixel) { case 1: $gray = $this->_read_gray($blob, $current_position, $bytes_to_read); $current_position += $bytes_to_read; // truncating pixel values over max and below min $gray = $gray > $maximum ? $maximum : $gray; $gray = $gray < $minimum ? $minimum : $gray; // Converting to gray value $gray = ($gray - $minimum) / ($maximum - $minimum) * 255; // For MONOCHROME1 we have to invert the pixel values. if ($photometric_interpretation == 'MONOCHROME1') { $gray = 255 - $gray; } // Set the (gray) color $color = $this->_allocate_color_gray($image, $gray); $gray = NULL; break; case 3: // It has 3 colors $rgb = array(); for ($sample = 0; $sample < $samples_per_pixel; $sample++) { $current_position = $planar_configuration == 0 ? $current_position : $sample * ($rows * $cols) + ($y * $cols + $x); $rgb[$sample] = $this->_read_gray($blob, $current_position, $bytes_to_read); $current_position += $bytes_to_read; } // Set the color $color = $this->_allocate_color_rgb($image, $rgb); $rgb = NULL; break; default: break; } // Set the pixel value $this->_set_pixel($image, $x, $y, $color); $color = NULL; } } // Append the current image $images[] = $image; $image = NULL; } // Collect the ending time for the profiler $this->profiler['pixel']['end'] = microtime(TRUE); return $images; }
function DisplayAllScanParamaters($filename) { $urllist['Home'] = "index.php"; $urllist['Scan Params'] = "series.php"; NavigationBar("MR Scan Parameters", $urllist); $dicom = Nanodicom::factory($filename, 'dumper'); $tags = $dicom->dump(); //print_r($tags); $lines = explode("\n", $tags); ?> <div align="center"> <table style="font-size: 10pt; border: 1px solid #DDDDDD" cellspacing="0" cellpadding="2"> <tr> <td colspan="3" style="font-weight: bold; font-size: 14pt; text-align: center; padding:10px; border-bottom: 2px solid #666666">MR Sequence Parameters <span style="color:darkred">(CONTAINS PHI - DO NOT SHARE)</span></td> </tr> <?php $lasttag1 = ''; foreach ($lines as $line) { preg_match('/.*(\\w{4}):(\\w{4})\\s+(\\w+)\\s+([A-Z]{2})\\s+(\\d+)\\s+\\[(.*)\\].*/', $line, $matches); //print_r($matches); $tag1 = $matches[1]; $tag2 = $matches[2]; $name = $matches[3]; $value = $matches[6]; if (trim($tag1) == "") { continue; } preg_match_all('/((?:^|[A-Z])[a-z]+)/', $name, $matches2); $pieces = $matches2[0]; $name = implode(' ', $pieces); if ($tag1 == "0018") { switch ($tag2) { case '0050': $units = 'mm'; break; case '0080': $units = 'ms'; break; case '0081': $units = 'ms'; break; case '0082': $units = 'ms'; break; case '0084': $units = 'Hz'; break; case '0087': $units = 'T'; break; case '0093': $units = '%'; break; case '0094': $units = '%'; break; case '1314': $units = '°'; break; default: $units = ''; } } if ($lasttag1 != $tag1) { $style = "border-top: solid 2px #666666"; } else { $style = "border-top: solid 1px #CCCCCC"; } ?> <tr> <td style="color:darkblue; <?php echo $style; ?> "><?php echo $tag1; ?> :<?php echo $tag2; ?> </td> <td style="<?php echo $style; ?> "><?php echo $name; ?> </td> <td style="<?php echo $style; ?> "><?php echo $value; ?> <span class="tiny"><?php echo $units; ?> </span></td> </tr> <?php $lasttag1 = $tag1; } ?> <tr> <td colspan="3" style="font-size:8pt; border-top: solid 2px #666666; padding:8px">Generated by NiDB <?php echo date("D M j, Y g:i a T"); ?> . Tags extracted using <a href="http://www.nanodicom.org">Nanodicom</a> <br>Based on DICOM file [<?php echo $filename; ?> ]</td> </tr> </table> </div> <?php unset($dicom); }
/** *Extract image from DICOM file and save it as PNG *Saved image are stored in the data directory, dicom_images folder *Naming convention $SubjectKey_$StudyEventOID_$StudyEventRepeatKey_$FormOID_$FormRepeatKey_$imageSuffix_UID.png * allow the identification of the image *@author wlt **/ public function saveImage($file, $SubjectKey, $StudyEventOID, $StudyEventRepeatKey, $FormOID = "", $FormRepeatKey = "", $imageSuffix = "") { $this->addLog(__METHOD__ . "({$file},{$SubjectKey},{$StudyEventOID},{$StudyEventRepeatKey},{$FormOID},{$FormRepeatKey},{$imageSuffix})", TRACE); $importPath = $this->m_tblConfig["IMPORT_BASE_PATH"] . "dicom"; $exportPath = $this->m_tblConfig["PATH_TO_AJAXZOOM_PICT"]; $filename = $importPath . "/" . $file; //Checking filename parameter if (!file_exists($filename)) { $this->addLog(__METHOD__ . " File {$filename} does not exists", FATAL); } //We need at least a StudyEventOID and a StudyEventRepeatKey if ($StudyEventOID == "" || $StudyEventRepeatKey == "") { $this->addLog(__METHOD__ . " StudyEventOID and StudyEventRepeatKey must be set", FATAL); } //Handle of Exception must be done at the upper level, to be added to the import report $dicom = Nanodicom::factory($filename, 'pixeler'); $imageFilename = $SubjectKey . "_" . $StudyEventOID . "_" . $StudyEventRepeatKey . "_" . $FormOID . "_" . $FormRepeatKey . "_" . $imageSuffix . "_" . $file; if (!file_exists($imageFilename . '.0.jpg')) { $images = $dicom->get_images(); if ($images !== FALSE) { foreach ($images as $index => $image) { $dicom->write_image($image, $exportPath . "/" . $imageFilename . '.' . $index); } } else { throw new Exception("For file {$filename} there are no DICOM images or transfer syntax not supported yet"); } $images = NULL; $dicom = Nanodicom::factory($filename, 'anonymizer'); file_put_contents(dirname($filename) . "/anonymizedDICOM/{$imageFilename}", $dicom->anonymize()); unset($dicom); } else { throw new Exception("File {$imageFilename}.0.jpg is already here"); } unset($dicom); }
// If using another library, for example, imagemagick, the following should be done: // $images = $dicom->set_driver('imagick')->get_images(); if ($images !== FALSE) { foreach ($images as $index => $image) { // Defaults to jpg $dicom->write_image($image, $dir . $file . '.' . $index); // To write another format, pass the format in second parameter. // This will write a png image instead // $dicom->write_image($image, $dir.$file.'.'.$index, 'png'); } } else { echo "There are no DICOM images or transfer syntax not supported yet.\n"; } $images = NULL; } else { echo "Image already exists\n"; } unset($dicom); } catch (Nanodicom_Exception $e) { echo 'File failed. ' . $e->getMessage() . "\n"; } // 21) Prints summary report try { echo "21) Prints summary report\n"; $dicom = Nanodicom::factory($filename); echo $dicom->summary(); unset($dicom); } catch (Nanodicom_Exception $e) { echo 'File failed. ' . $e->getMessage() . "\n"; } }