#include #include #include "attrmxls.h" #include "attrtype.h" #include "attrothr.h" #include "attrval.h" #include "elmdict.h" #include "elmconst.h" #include "sopclu.h" #include "mesgtext.h" #include "dcopt.h" static Attribute * isValuePresentElseAbort(AttributeList &list,Tag tag,const char *label,const char *filename,TextOutputStream &log) { Assert(label); Assert(filename); Attribute *a=list[tag]; if (a && a->getVM()) return a; else { log << filename << ": " << AMsgDC(MissingAttribute) << " - " << label << endl; exit(1); } } static void rotate( double dst_row_dircos_x,double dst_row_dircos_y,double dst_row_dircos_z, double dst_col_dircos_x,double dst_col_dircos_y,double dst_col_dircos_z, double dst_nrm_dircos_x,double dst_nrm_dircos_y,double dst_nrm_dircos_z, double src_pos_x,double src_pos_y,double src_pos_z, double &dst_pos_x,double &dst_pos_y,double &dst_pos_z) { dst_pos_x = dst_row_dircos_x * src_pos_x + dst_row_dircos_y * src_pos_y + dst_row_dircos_z * src_pos_z; dst_pos_y = dst_col_dircos_x * src_pos_x + dst_col_dircos_y * src_pos_y + dst_col_dircos_z * src_pos_z; dst_pos_z = dst_nrm_dircos_x * src_pos_x + dst_nrm_dircos_y * src_pos_y + dst_nrm_dircos_z * src_pos_z; } static bool getPositionOrientationSpacingAndSize(AttributeList &list,const char *filename,TextOutputStream &log,bool verbose, double &row_dircos_x,double &row_dircos_y,double &row_dircos_z, double &col_dircos_x,double &col_dircos_y,double &col_dircos_z, double &nrm_dircos_x,double &nrm_dircos_y,double &nrm_dircos_z, double &pos_x,double &pos_y,double &pos_z, unsigned long &rows,unsigned long &cols, double &row_spacing,double &col_spacing, double &row_length,double &col_length) { // the localizer is the "destination" for the posting operation Attribute *aImageOrientationPatient = isValuePresentElseAbort(list, TagFromName(ImageOrientationPatient),"ImageOrientationPatient",filename,log); if (aImageOrientationPatient->getVM() != 6) { log << filename << ": " << AMsgDC(BadAttributeValueMultiplicity) << " - ImageOrientationPatient" << endl; return false; } if (!aImageOrientationPatient->getValue(0,row_dircos_x) || !aImageOrientationPatient->getValue(1,row_dircos_y) || !aImageOrientationPatient->getValue(2,row_dircos_z) || !aImageOrientationPatient->getValue(3,col_dircos_x) || !aImageOrientationPatient->getValue(4,col_dircos_y) || !aImageOrientationPatient->getValue(5,col_dircos_z) ) { log << filename << ": " << AMsgDC(BadAttributeValue) << " - ImageOrientationPatient" << endl; return false; } //cerr << "row_dircos_x = " << row_dircos_x << endl; //cerr << "row_dircos_y = " << row_dircos_y << endl; //cerr << "row_dircos_z = " << row_dircos_z << endl; //cerr << "col_dircos_x = " << col_dircos_x << endl; //cerr << "col_dircos_y = " << col_dircos_y << endl; //cerr << "col_dircos_z = " << col_dircos_z << endl; // compute nrm to row and col (i.e. cross product of row and col unit vectors) nrm_dircos_x = row_dircos_y * col_dircos_z - row_dircos_z * col_dircos_y; nrm_dircos_y = row_dircos_z * col_dircos_x - row_dircos_x * col_dircos_z; nrm_dircos_z = row_dircos_x * col_dircos_y - row_dircos_y * col_dircos_x; //cerr << "nrm_dircos_x = " << nrm_dircos_x << endl; //cerr << "nrm_dircos_y = " << nrm_dircos_y << endl; //cerr << "nrm_dircos_z = " << nrm_dircos_z << endl; // check are unit vectors ... if (!(fabs(row_dircos_x*row_dircos_x+row_dircos_y*row_dircos_y+row_dircos_z*row_dircos_z - 1.0) < 0.000001) || !(fabs(col_dircos_x*col_dircos_x+col_dircos_y*col_dircos_y+col_dircos_z*col_dircos_z - 1.0) < 0.000001) || !(fabs(nrm_dircos_x*nrm_dircos_x+nrm_dircos_y*nrm_dircos_y+nrm_dircos_z*nrm_dircos_z - 1.0) < 0.000001) ) { log << filename << ": " << "Abort - row, column or normal are not unit vectors" << " - ImageOrientationPatient" << endl; return false; } // check are orthogonal (dot product is zero, i.e. cos 90) if (!(fabs(row_dircos_x*col_dircos_x+row_dircos_y*col_dircos_y+row_dircos_z*col_dircos_z) < 0.000001) || !(fabs(row_dircos_x*nrm_dircos_x+row_dircos_y*nrm_dircos_y+row_dircos_z*nrm_dircos_z) < 0.000001) || !(fabs(col_dircos_x*nrm_dircos_x+col_dircos_y*nrm_dircos_y+col_dircos_z*nrm_dircos_z) < 0.000001) ) { log << filename << ": " << "Abort - row, column and normal are not orthogonal" << " - ImageOrientationPatient" << endl; return false; } Attribute *aImagePositionPatient = isValuePresentElseAbort(list, TagFromName(ImagePositionPatient),"ImagePositionPatient",filename,log); if (aImagePositionPatient->getVM() != 3) { log << filename << ": " << AMsgDC(BadAttributeValueMultiplicity) << " - ImagePositionPatient" << endl; return false; } if (!aImagePositionPatient->getValue(0,pos_x) || !aImagePositionPatient->getValue(1,pos_y) || !aImagePositionPatient->getValue(2,pos_z) ) { log << filename << ": " << AMsgDC(BadAttributeValue) << " - ImagePositionPatient" << endl; return false; } //cerr << "pos_x = " << pos_x << endl; //cerr << "pos_y = " << pos_y << endl; //cerr << "pos_z = " << pos_z << endl; Attribute *aPixelSpacing = isValuePresentElseAbort(list, TagFromName(PixelSpacing),"PixelSpacing",filename,log); if (aPixelSpacing->getVM() != 2) { log << filename << ": " << AMsgDC(BadAttributeValueMultiplicity) << " - PixelSpacing" << endl; return false; } if (!aPixelSpacing->getValue(0,row_spacing) || !aPixelSpacing->getValue(1,col_spacing) ) { log << filename << ": " << AMsgDC(BadAttributeValue) << " - PixelSpacing" << endl; return false; } //cerr << "row_spacing = " << row_spacing << endl; //cerr << "col_spacing = " << col_spacing << endl; Attribute *aRows = isValuePresentElseAbort(list, TagFromName(Rows),"Rows",filename,log); if (aRows->getVM() != 1) { log << filename << ": " << AMsgDC(BadAttributeValueMultiplicity) << " - Rows" << endl; return false; } if (!aRows->getValue(0,rows)) { log << filename << ": " << AMsgDC(BadAttributeValue) << " - Rows" << endl; return false; } //cerr << "rows = " << rows << endl; Attribute *aColumns = isValuePresentElseAbort(list, TagFromName(Columns),"Columns",filename,log); if (aColumns->getVM() != 1) { log << filename << ": " << AMsgDC(BadAttributeValueMultiplicity) << " - Columns" << endl; return false; } if (!aColumns->getValue(0,cols)) { log << filename << ": " << AMsgDC(BadAttributeValue) << " - Columns" << endl; return false; } //cerr << "cols = " << cols << endl; row_length=rows*row_spacing; col_length=cols*col_spacing; //cerr << "row_length = " << row_length << endl; //cerr << "col_length = " << col_length << endl; return true; } static bool openAndRead(ManagedAttributeList &list,DicomInputOptions &dicom_input_options,const char *filename, DicomInputStream *din,TextOutputStream &log,bool veryverbose,bool veryveryverbose) { if (!filename) return false; if (veryverbose) log << "Reading \"" << filename << "\"" << endl; #ifdef USEBINARYFLAGFORINPUTOPENMODE ifstream *fstr=new ifstream(filename,ios::in|ios::binary); #else ifstream *fstr=new ifstream(filename); #endif if (!fstr || !*fstr || !fstr->rdbuf()->is_open()) { log << AMsgDC(FileReadOpenFailed); if (filename) log <<" - \"" << filename << "\""; return false; } din = new DicomInputStream(*(istream *)fstr); Assert(din); if (veryverbose) log << "******** While reading ... " << filename << " ... ********" << endl; list.read(*din,&log,veryveryverbose,0xffffffff,true,dicom_input_options.uselengthtoend,dicom_input_options.ignoreoutofordertags); if (!list.good()) { log << list.errors() << EMsgDC(DatasetReadFailed) << endl; return false; } // caller is responsible for deleting din return true; } static inline void drawPixel(Uint16 *graphics_buffer,unsigned long graphics_buffer_rows,unsigned long graphics_buffer_cols, int row_pixel,int col_pixel) { //cerr << "drawPixel: row=" << row_pixel << " col=" << col_pixel << endl; if (row_pixel >= 1 && row_pixel <= graphics_buffer_rows && col_pixel >= 1 && col_pixel <= graphics_buffer_cols) { unsigned long which_bit=(row_pixel-1)*graphics_buffer_cols+(col_pixel-1); graphics_buffer[which_bit/16] |= Uint16(1)<<(which_bit%16); //cerr << "drawPixel: which_bit=" << which_bit << " %16=" << (which_bit%16) << " word=" << (which_bit/16) << endl; } else { //cerr << "clipped" << endl; } } static void drawLine(Uint16 *graphics_buffer,unsigned long graphics_buffer_rows,unsigned long graphics_buffer_cols, int from_row_pixel,int from_col_pixel,int to_row_pixel,int to_col_pixel) { // start and end pixels are not yet clipped to boundaries // pixels are DICOM style ... TLHC is 1,1, BRHC is cols,rows if (abs(to_col_pixel-from_col_pixel) > abs(to_row_pixel-from_row_pixel)) { // integer increment along column axis //cerr << "doing integer increment along column axis" << endl; if (from_col_pixel > to_col_pixel) { // swap drawing direction to keep column increment positive //cerr << "swap drawing direction to keep column increment positive" << endl; int tmp; tmp=from_col_pixel; from_col_pixel=to_col_pixel; to_col_pixel=tmp; tmp=from_row_pixel; from_row_pixel=to_row_pixel; to_row_pixel=tmp; } double drow=to_row_pixel-from_row_pixel; double dcol=to_col_pixel-from_col_pixel; //cerr << "drow = " << drow << endl; //cerr << "dcol = " << dcol << endl; Assert(fabs(dcol) > 0.00001); double slope=drow/dcol; //cerr << "slope drow/dcol = " << slope << endl; Assert(-1.0 <= slope && slope <= 1.0); // otherwise would be doing rows int col; double row=from_row_pixel+0.5; // the 0.5 is a constant throughout for the rounding operation for (col=from_col_pixel; col <= to_col_pixel; ++col) { drawPixel(graphics_buffer,graphics_buffer_rows,graphics_buffer_cols,int(row),col); row+=slope; } } else if (to_row_pixel != from_row_pixel) { // integer increment along row axis //cerr << "doing integer increment along row axis" << endl; if (from_row_pixel > to_row_pixel) { // swap drawing direction to keep row increment positive //cerr << "swap drawing direction to keep row increment positive" << endl; int tmp; tmp=from_col_pixel; from_col_pixel=to_col_pixel; to_col_pixel=tmp; tmp=from_row_pixel; from_row_pixel=to_row_pixel; to_row_pixel=tmp; } double drow=to_row_pixel-from_row_pixel; double dcol=to_col_pixel-from_col_pixel; //cerr << "drow = " << drow << endl; //cerr << "dcol = " << dcol << endl; Assert(fabs(drow) > 0.00001); double slope=dcol/drow; //cerr << "slope dcol/drow = " << slope << endl; int row; double col=from_col_pixel+0.5; // the 0.5 is a constant throughout for the rounding operation for (row=from_row_pixel; row <= to_row_pixel; ++row) { drawPixel(graphics_buffer,graphics_buffer_rows,graphics_buffer_cols,row,int(col)); col+=slope; } } else { // to_col_pixel == from_col_pixel && to_row_pixel == from_row_pixel //cerr << "just draw a point" << endl; drawPixel(graphics_buffer,graphics_buffer_rows,graphics_buffer_cols,to_row_pixel,to_col_pixel); } } int main(int argc, char *argv[]) { bool bad=false; GetNamedOptions options(argc,argv); DicomInputOptions dicom_input_options(options); DicomOutputOptions dicom_output_options(options); bool verbose=options.get("verbose") || options.get("v"); bool veryverbose=options.get("veryverbose") || options.get("vv"); bool veryveryverbose=options.get("veryveryverbose") || options.get("vvv"); if (veryveryverbose) veryverbose=true; if (veryverbose) verbose=true; const char *localizer_filename; if (!options.get("localizer",localizer_filename)) { cerr << "Must specify a localizer image" << endl; bad=true; } dicom_input_options.done(); Assert(!dicom_input_options.filename); dicom_output_options.done(); int numberofinputfiles=!options; const char **filenamestable = new const char *[numberofinputfiles]; Assert(filenamestable); const char **ptr; for (ptr=filenamestable; !options && (*ptr++=options()); ++options); options.done(); DicomOutputOpenerFromOptions output_opener( options,dicom_output_options.filename,cout); cerr << dicom_input_options.errors(); cerr << dicom_output_options.errors(); cerr << options.errors(); cerr << output_opener.errors(); if (!dicom_input_options.good() || !dicom_output_options.good() || !options.good() || !output_opener.good() || !options || bad) { cerr << MMsgDC(Usage) << ": " << options.command() << dicom_input_options.usage() << dicom_output_options.usage() << " [-v|-verbose|-vv|-veryverbose|-vvv|-veryveryverbose]" << " [-localizer filename]" << " " << MMsgDC(InputFile) << " ["<< MMsgDC(InputFile) << " ...]" << " >" << MMsgDC(OutputFile) << endl; exit(1); } if (!dicom_output_options.transfersyntaxuid) dicom_output_options.transfersyntaxuid=ExplicitVRLittleEndianTransferSyntaxUID; bool success=true; TextOutputStream log(cerr); DicomOutputStream dout(*(ostream *)output_opener, dicom_output_options.transfersyntaxuid, dicom_output_options.usemetaheader, dicom_output_options.useimplicitmetaheader, dicom_output_options.addtiff); // Open the localizer image ... ManagedAttributeList localizer_list; DicomInputStream *localizer_din; if (!openAndRead(localizer_list,dicom_input_options,localizer_filename,localizer_din, log,veryverbose,veryveryverbose)) exit(1); double dst_row_dircos_x; double dst_row_dircos_y; double dst_row_dircos_z; double dst_col_dircos_x; double dst_col_dircos_y; double dst_col_dircos_z; double dst_nrm_dircos_x; double dst_nrm_dircos_y; double dst_nrm_dircos_z; double dst_pos_x; double dst_pos_y; double dst_pos_z; double dst_row_spacing; double dst_col_spacing; double dst_row_length; double dst_col_length; unsigned long dst_rows; unsigned long dst_cols; if (!getPositionOrientationSpacingAndSize(localizer_list,localizer_filename,log,verbose, dst_row_dircos_x,dst_row_dircos_y,dst_row_dircos_z, dst_col_dircos_x,dst_col_dircos_y,dst_col_dircos_z, dst_nrm_dircos_x,dst_nrm_dircos_y,dst_nrm_dircos_z, dst_pos_x,dst_pos_y,dst_pos_z, dst_rows,dst_cols, dst_row_spacing,dst_col_spacing, dst_row_length,dst_col_length) ) exit(1); unsigned long graphics_buffer_rows=dst_rows; unsigned long graphics_buffer_cols=dst_cols; unsigned long graphics_buffer_size=(graphics_buffer_rows*graphics_buffer_cols-1)/16+1; Uint16 *graphics_buffer=new Uint16[graphics_buffer_size]; Assert(graphics_buffer); { unsigned long i; Uint16 *ptr; for (i=0,ptr=graphics_buffer; iaddValue(Int16(1)); aOverlayOrigin->addValue(Int16(1)); localizer_list+=aOverlayOrigin; OtherWordSmallNonPixelAttribute *aOverlayData = new OtherWordSmallNonPixelAttribute(Tag(OverlayData_GROUP+u,OverlayData_ELEMENT)); Assert(aOverlayData); aOverlayData->setValue(graphics_buffer,graphics_buffer_size); localizer_list+=aOverlayData; if (!usualManagedAttributeListWrite(localizer_list,dout, dicom_output_options,log,veryverbose)) success=false; if (numberofinputfiles && filenamestable) delete[] filenamestable; if (localizer_din) delete localizer_din; return success ? 0 : 1; }