/** * * Count number of duplicate image positions in given image list. * * \param imageList List of images to count duplicate image positions in. * * \return Number of duplicate image positions. * */ int XipDicomSortUtil::getNumDuplicateImagePositions(const XipDicomSortImageList &imageList, unsigned int &sortOption) { XipDicomSortImageList::const_iterator i; int duplicates = 0; sortOption = SORT_OPTIONS_ALL; double prevPos = (*imageList.begin())->getAttributes()->objectPositionZ; float prevAcqTime = (*imageList.begin())->getAttributes()->acquisitionTime; float prevTriggerTime = (*imageList.begin())->getAttributes()->triggerTime; unsigned int prevSeriesNumber = (*imageList.begin())->getAttributes()->seriesNumber; unsigned int prevImageNumber = (*imageList.begin())->getAttributes()->imageNumber; float prevScanOptions = getFirstNumber((*imageList.begin())->getAttributes()->scanOptions); for (i = imageList.begin() + 1; i != imageList.end(); i++) { double pos = (*i)->getAttributes()->objectPositionZ; if (pos == prevPos) { if (prevTriggerTime == (*i)->getAttributes()->triggerTime) { sortOption &= ~TRIGGER_TIME; } if (prevSeriesNumber == (*i)->getAttributes()->seriesNumber) { sortOption &= ~SERIES_NUMBER; } if (prevAcqTime == (*i)->getAttributes()->acquisitionTime) { sortOption &= ~ACQUISITION_TIME; } if (prevImageNumber == (*i)->getAttributes()->imageNumber) { sortOption &= ~IMAGE_NUMBER; } if (prevScanOptions == getFirstNumber((*i)->getAttributes()->scanOptions)) { sortOption &= ~SCAN_OPTIONS; } duplicates++; } prevPos = pos; prevAcqTime = (*i)->getAttributes()->acquisitionTime; prevTriggerTime = (*i)->getAttributes()->triggerTime; prevSeriesNumber = (*i)->getAttributes()->seriesNumber; prevImageNumber = (*i)->getAttributes()->imageNumber; prevScanOptions = getFirstNumber((*i)->getAttributes()->scanOptions); } return duplicates; }
static ssize_t device_write(struct file *filp, const char *buffer, size_t length, loff_t *data){ unsigned int digitos; fib_previo = getFirstNumber(buffer, length, &digitos); if( digitos+1 >= length ) { printk(KERN_ALERT "Cantidad de parametros en Fibonacci incorrecto\n"); return 1; } fib_actual = getFirstNumber(&buffer[digitos+1], length-(digitos+1), NULL); return 2*sizeof(unsigned long); }
// comparison function to sort by scan options and image position static bool scanOptions_imagePosition_less ( const XipDicomSortImage* elem1, const XipDicomSortImage* elem2 ) { float v1 = getFirstNumber(elem1->getAttributes()->scanOptions); float v2 = getFirstNumber(elem2->getAttributes()->scanOptions); if (v1 < v2) { return true; } else if (v1 > v2) { return false; } // if equal trigger time, sort by position return (elem1->getAttributes()->objectPositionZ < elem2->getAttributes()->objectPositionZ); }
/** * * Quick check if number in scan options will separate images with duplicate positions. * * \return Returns true if number in scan options is different in images with same position. * */ bool XipDicomSortUtil::canSortByScanOptions(const XipDicomSortImageList &imageList) const { // in order to sort we need to find same attribute in at least three // but less than all of the images XipDicomSortImageList::const_iterator i; unsigned int duplicates = 0; float scanOptions = 0; for (i = imageList.begin(); i != imageList.end(); i++) { if (i == imageList.begin()) { scanOptions = getFirstNumber((*i)->getAttributes()->scanOptions); } if (scanOptions == getFirstNumber((*i)->getAttributes()->scanOptions)) { duplicates++; } } return ( (duplicates > 1) && (duplicates < imageList.size()) ); }
/** * This method invokes sorting of the objects identified by the names contained in dataObjectNamelist * set by the client application using XipDicomSortUtil::setObjects(). This method sorts the objects into * a list of groups, each group representing a set of volumes with similar characteristics. * * The client application can subsequently query the group descriptor and use the information. The information * provided through the group descriptor will be valid until the next sorting session is invoked. * * \param option Optional sorting option/criteria. Can be RADSORT_SAME_ROWVECTOR, RADSORT_SAME_COLUMNVECTOR, * RADSORTGENERIC_CREATE_DEFAULTGROUP or a combination of all values. * * \b Example: \code // assumed that sorting and data plugins are loaded, dataObjects are dragged and dropped // and a valid dataObjectNamelist is created by the dataPlugin. // The application sets the dataObjectNamelist and dataConnector to the sorting plugin // and invokes the sorting by calling XipDicomSortUtil::sort() with appropriate optional flags. mSorterPlugin->setObjects(dataObjectNamelist, dataConnectorPtr); mSorterPlugin->sort(RADSORT_SAME_ROWVECTOR | RADSORT_SAME_COLUMNVECTOR); // As a result of the above, the sorting plugin has created the group list which can // be queried by the application now. // get the group count unsigned int numberOfAvailableGroups = mSorterPlugin->getGroups(); //get a pointer to the first group unsigned int groupIndex = 0; Rad4DSequenceDescriptor * desc = (Rad4DSequenceDescriptor*) ( mSorterPlugin->getGroupDescriptor(groupIndex) ); //use the information contained in the group descriptor. //The application must not delete the pointer to Rad4DSequenceDescriptor object. \endcode */ void XipDicomSortUtil::sort(unsigned int option) { if (!mSortImageList) return; if (mSortVolumeList) { mSortVolumeList->clear(); } else { mSortVolumeList = new XipDicomSortVolumeList(); if (!mSortVolumeList) return; } XipDicomSortImageList::const_iterator from; XipDicomSortImageList::const_iterator i; XipDicomSortVolumeList::iterator g; // first pass, put all images into baskets XipDicomSortVolumeList firstPassBaskets; // sort by group separator std::sort(mSortImageList->begin(), mSortImageList->end(), XipDicomSortKeyGroup_less ); XipDicomSortImageList imageList; from = mSortImageList->begin(); for (i = mSortImageList->begin(); i != mSortImageList->end(); i++) { if (XipDicomSortAlg(*from) != XipDicomSortAlg(*i)) { imageList.assign(from, i); if (imageList.size() > 0) firstPassBaskets.push_back(imageList); from = i; } } imageList.assign(from, i); if (imageList.size() > 0) firstPassBaskets.push_back(imageList); // now deal with each basket individually for (g = firstPassBaskets.begin(); g != firstPassBaskets.end(); g++) { // sort all slices by image position std::sort(g->begin(), g->end(), imagePosition_less ); // check if time sequence (or any other overlapping stuff) unsigned int sortHint; int numDupImagePositions = getNumDuplicateImagePositions(*g, sortHint); if (numDupImagePositions == 0) { // no duplicated slices, take as is mSortVolumeList->push_back(*g); } else { // NOTE: It requires a minimum of two slices when it goes through the following conditions. // TBD: What if only the first or last slice have duplicates such as with older CT scans? // most likely multiple volumes such as time sequence // might be separable by: // - trigger time // - image number // - scan options // - acquisition time if ((sortHint & TRIGGER_TIME) && canSortByTriggerTime(*g)) { // assume that all slices in a volume have the same trigger time std::sort(g->begin(), g->end(), triggerTime_imagePosition_less ); from = g->begin(); float triggerTime = (*(g->begin()))->getAttributes()->triggerTime; for (i = g->begin(); i != g->end(); i++) { if (triggerTime != (*i)->getAttributes()->triggerTime) { imageList.assign(from, i); // add new group if (imageList.size() > 0) { mSortVolumeList->push_back(imageList); } from = i; triggerTime = (*i)->getAttributes()->triggerTime; } } // add last group imageList.assign(from, i); if (imageList.size() > 0) { mSortVolumeList->push_back(imageList); } } else if ((sortHint & SERIES_NUMBER) && canSortBySeriesNumber(*g)) { // assume that all slices in a volume have the same series number std::sort(g->begin(), g->end(), seriesNumber_imagePosition_less ); from = g->begin(); unsigned int seriesNumber = (*(g->begin()))->getAttributes()->seriesNumber; for (i = g->begin(); i != g->end(); i++) { if (seriesNumber != (*i)->getAttributes()->seriesNumber) { imageList.assign(from, i); // add new group if (imageList.size() > 0) { mSortVolumeList->push_back(imageList); } from = i; seriesNumber = (*i)->getAttributes()->seriesNumber; } } // add last group imageList.assign(from, i); if (imageList.size() > 0) { mSortVolumeList->push_back(imageList); } } else if ((sortHint & IMAGE_NUMBER) && canSortByImageNumber(*g)) { // assume that all slices in a volume have the same image number std::sort(g->begin(), g->end(), imageNumber_imagePosition_less ); from = g->begin(); unsigned int imageNumber = (*(g->begin()))->getAttributes()->imageNumber; for (i = g->begin(); i != g->end(); i++) { if (imageNumber != (*i)->getAttributes()->imageNumber) { imageList.assign(from, i); // add new group if (imageList.size() > 0) { mSortVolumeList->push_back(imageList); } from = i; imageNumber = (*i)->getAttributes()->imageNumber; } } // add last group imageList.assign(from, i); if (imageList.size() > 0) { mSortVolumeList->push_back(imageList); } } else if ((sortHint & SCAN_OPTIONS) && canSortByScanOptions(*g)) { // assume that all slices in a volume have the same number in the scan options std::sort(g->begin(), g->end(), scanOptions_imagePosition_less ); from = g->begin(); float scanOptions = getFirstNumber((*(g->begin()))->getAttributes()->scanOptions); for (i = g->begin(); i != g->end(); i++) { if (scanOptions != getFirstNumber((*i)->getAttributes()->scanOptions)) { imageList.assign(from, i); // add new group if (imageList.size() > 0) { mSortVolumeList->push_back(imageList); } from = i; scanOptions = getFirstNumber((*i)->getAttributes()->scanOptions); } } // add last group imageList.assign(from, i); if (imageList.size() > 0) { mSortVolumeList->push_back(imageList); } } else if ((sortHint & ACQUISITION_TIME) && canSortByAcquisitionTime(*g)) { // assume that all slices in a volume have the same acquisition time std::sort(g->begin(), g->end(), acquisitionTime_imagePosition_less ); from = g->begin(); float acquisitionTime = (*(g->begin()))->getAttributes()->acquisitionTime; for (i = g->begin(); i != g->end(); i++) { if (acquisitionTime != (*i)->getAttributes()->acquisitionTime) { imageList.assign(from, i); // add new group if (imageList.size() > 0) { mSortVolumeList->push_back(imageList); } from = i; acquisitionTime = (*i)->getAttributes()->acquisitionTime; } } // add last group imageList.assign(from, i); if (imageList.size() > 0) { mSortVolumeList->push_back(imageList); } } else if (sortHint & TRIGGER_TIME) { // we have unique trigger time for each slice // sort by trigger time and break volumes once direction in image position changes std::sort(g->begin(), g->end(), triggerTime_imagePosition_less ); double prevImagePosition = (*(g->begin()))->getAttributes()->objectPositionZ; double nextImagePosition = (*(g->begin() + 1))->getAttributes()->objectPositionZ; bool dir = (nextImagePosition > prevImagePosition); from = g->begin(); for (i = g->begin(); i != g->end(); i++) { if (dir ? (*i)->getAttributes()->objectPositionZ < prevImagePosition : (*i)->getAttributes()->objectPositionZ > prevImagePosition) { imageList.assign(from, i); // add new group if (imageList.size() > 0) { mSortVolumeList->push_back(imageList); } from = i; } prevImagePosition = (*i)->getAttributes()->objectPositionZ; } // add last group imageList.assign(from, i); if (imageList.size() > 0) { mSortVolumeList->push_back(imageList); } } else if (sortHint & IMAGE_NUMBER) { // we have unique image numbers for each slice // sort by image number and break volumes once direction in image position changes std::sort(g->begin(), g->end(), imageNumber_imagePosition_less ); double prevImagePosition = (*(g->begin()))->getAttributes()->objectPositionZ; double nextImagePosition = (*(g->begin() + 1))->getAttributes()->objectPositionZ; bool dir = (nextImagePosition > prevImagePosition); from = g->begin(); for (i = g->begin(); i != g->end(); i++) { if (dir ? (*i)->getAttributes()->objectPositionZ < prevImagePosition : (*i)->getAttributes()->objectPositionZ > prevImagePosition) { imageList.assign(from, i); // add new group if (imageList.size() > 0) { mSortVolumeList->push_back(imageList); } from = i; } prevImagePosition = (*i)->getAttributes()->objectPositionZ; } // add last group imageList.assign(from, i); if (imageList.size() > 0) { mSortVolumeList->push_back(imageList); } } else { // cannot separate by any criteria // just sort by position and hope for the best mSortVolumeList->push_back(*g); } } } }