/** * Copy a set of DICOM files, if they match specified criteria. * * <p>Does not actually check the Modality value in the file, but matches the SOP Class against * what is returned from {@link * com.pixelmed.dicom.SOPClass#getPlausibleStandardSOPClassUIDsForModality(String) * SOPClass.getPlausibleStandardSOPClassUIDsForModality(String)}. * * @param arg array of four strings - the input path, the output path, and the SOP Class UID or * Modality */ public static void main(String arg[]) { try { if (arg.length == 3) { FindAndCopySelectedDicomFiles importer = new FindAndCopySelectedDicomFiles(new PrintStreamMessageLogger(System.err)); importer.outputPath = arg[1]; importer.sopClasses = new HashSet(); if (arg[2].startsWith("1")) { // System.err.println("main(): importer.sopClasses.add = \""+arg[2]+"\""); importer.sopClasses.add(arg[2]); } else { String[] sopClasses = SOPClass.getPlausibleStandardSOPClassUIDsForModality(arg[2]); if (sopClasses == null) { throw new DicomException( "Cannot find plausible SOP Standard Classes for modality \"" + arg[2] + "\""); } else { for (String sopClass : sopClasses) { // System.err.println("main(): importer.sopClasses.add = \""+sopClass+"\""); importer.sopClasses.add(sopClass); } } } importer.importDicomFiles(arg[0]); } else { System.err.println( "Usage: java -cp ./pixelmed.jar com.pixelmed.apps.FindAndCopySelectedDicomFiles srcdir dstdir sopclass|modality"); } } catch (Exception e) { e.printStackTrace(System.err); System.exit(0); } }
/** * Generate commomn attributes for converted images. * * <p>Does NOT add ManufacturerModelName ... that should be added by caller. * * <p>Does NOT call * CodingSchemeIdentification.replaceCodingSchemeIdentificationSequenceWithCodingSchemesUsedInAttributeList * ... that should be done by caller. * * @param list * @param patientName * @param patientID * @param studyID * @param seriesNumber * @param instanceNumber * @param modality may be null * @param sopClass may be null * @throws DicomException * @throws NumberFormatException */ public static void generateCommonAttributes( AttributeList list, String patientName, String patientID, String studyID, String seriesNumber, String instanceNumber, String modality, String sopClass) throws DicomException { UIDGenerator u = new UIDGenerator(); { Attribute a = new UniqueIdentifierAttribute(TagFromName.SOPInstanceUID); a.addValue(u.getAnotherNewUID()); list.put(a); } { Attribute a = new UniqueIdentifierAttribute(TagFromName.SeriesInstanceUID); a.addValue(u.getAnotherNewUID()); list.put(a); } { Attribute a = new UniqueIdentifierAttribute(TagFromName.StudyInstanceUID); a.addValue(u.getAnotherNewUID()); list.put(a); } { Attribute a = new UniqueIdentifierAttribute(TagFromName.FrameOfReferenceUID); a.addValue(u.getAnotherNewUID()); list.put(a); } { Attribute a = new PersonNameAttribute(TagFromName.PatientName); a.addValue(patientName); list.put(a); } { Attribute a = new LongStringAttribute(TagFromName.PatientID); a.addValue(patientID); list.put(a); } { Attribute a = new DateAttribute(TagFromName.PatientBirthDate); list.put(a); } { Attribute a = new CodeStringAttribute(TagFromName.PatientSex); list.put(a); } { Attribute a = new ShortStringAttribute(TagFromName.StudyID); a.addValue(studyID); list.put(a); } { Attribute a = new PersonNameAttribute(TagFromName.ReferringPhysicianName); a.addValue("^^^^"); list.put(a); } { Attribute a = new ShortStringAttribute(TagFromName.AccessionNumber); list.put(a); } { Attribute a = new IntegerStringAttribute(TagFromName.SeriesNumber); a.addValue(seriesNumber); list.put(a); } { Attribute a = new IntegerStringAttribute(TagFromName.InstanceNumber); a.addValue(instanceNumber); list.put(a); } { Attribute a = new LongStringAttribute(TagFromName.Manufacturer); a.addValue("PixelMed"); list.put(a); } { Attribute a = new LongStringAttribute(TagFromName.DeviceSerialNumber); a.addValue(new java.rmi.dgc.VMID().toString()); list.put(a); } { Attribute a = new LongStringAttribute(TagFromName.SoftwareVersions); a.addValue(VersionAndConstants.getBuildDate()); list.put(a); } { Attribute a = new CodeStringAttribute(TagFromName.PatientOrientation); list.put(a); } { Attribute a = new CodeStringAttribute(TagFromName.BurnedInAnnotation); a.addValue("NO"); list.put(a); } { Attribute a = new CodeStringAttribute(TagFromName.RecognizableVisualFeatures); a.addValue("NO"); list.put(a); } { Attribute a = new CodeStringAttribute(TagFromName.ContentQualification); a.addValue("RESEARCH"); list.put(a); } { Attribute a = new CodeStringAttribute(TagFromName.LossyImageCompression); a.addValue("00"); list.put(a); } { Attribute a = new LongStringAttribute(TagFromName.PositionReferenceIndicator); list.put(a); } { java.util.Date currentDateTime = new java.util.Date(); String currentDate = new java.text.SimpleDateFormat("yyyyMMdd").format(currentDateTime); String currentTime = new java.text.SimpleDateFormat("HHmmss.SSS").format(currentDateTime); { Attribute a = new DateAttribute(TagFromName.StudyDate); a.addValue(currentDate); list.put(a); } { Attribute a = new TimeAttribute(TagFromName.StudyTime); a.addValue(currentTime); list.put(a); } { Attribute a = new DateAttribute(TagFromName.SeriesDate); a.addValue(currentDate); list.put(a); } { Attribute a = new TimeAttribute(TagFromName.SeriesTime); a.addValue(currentTime); list.put(a); } { Attribute a = new DateAttribute(TagFromName.ContentDate); a.addValue(currentDate); list.put(a); } { Attribute a = new TimeAttribute(TagFromName.ContentTime); a.addValue(currentTime); list.put(a); } { Attribute a = new DateAttribute(TagFromName.InstanceCreationDate); a.addValue(currentDate); list.put(a); } { Attribute a = new TimeAttribute(TagFromName.InstanceCreationTime); a.addValue(currentTime); list.put(a); } { Attribute a = new ShortStringAttribute(TagFromName.TimezoneOffsetFromUTC); a.addValue(DateTimeAttribute.getTimeZone(java.util.TimeZone.getDefault(), currentDateTime)); list.put(a); } } { Attribute a = new UniqueIdentifierAttribute(TagFromName.InstanceCreatorUID); a.addValue(VersionAndConstants.instanceCreatorUID); list.put(a); } int numberOfFrames = Attribute.getSingleIntegerValueOrDefault(list, TagFromName.NumberOfFrames, 1); int samplesPerPixel = Attribute.getSingleIntegerValueOrDefault(list, TagFromName.SamplesPerPixel, 1); if (sopClass == null) { // if modality were not null, could actually attempt to guess SOP Class based on modality here // :( sopClass = SOPClass.SecondaryCaptureImageStorage; if (numberOfFrames > 1) { if (samplesPerPixel == 1) { int bitsAllocated = Attribute.getSingleIntegerValueOrDefault(list, TagFromName.BitsAllocated, 1); if (bitsAllocated == 8) { sopClass = SOPClass.MultiframeGrayscaleByteSecondaryCaptureImageStorage; } else if (bitsAllocated == 16) { sopClass = SOPClass.MultiframeGrayscaleWordSecondaryCaptureImageStorage; } else { Attribute aPixelData = list.getPixelData(); if (aPixelData instanceof OtherFloatAttribute || aPixelData instanceof OtherDoubleAttribute) { sopClass = SOPClass.ParametricMapStorage; } } } else if (samplesPerPixel == 3) { sopClass = SOPClass.MultiframeTrueColorSecondaryCaptureImageStorage; } } } if (sopClass.equals(SOPClass.ParametricMapStorage)) { addParametricMapFrameTypeSharedFunctionalGroup(list); { Attribute a = new CodeStringAttribute(TagFromName.ContentLabel); a.addValue("LABEL1"); list.put(a); } { Attribute a = new LongStringAttribute(TagFromName.ContentDescription); list.put(a); } { Attribute a = new PersonNameAttribute(TagFromName.ContentCreatorName); list.put(a); } } if (SOPClass.isEnhancedMultiframeImageStorage(sopClass)) { if (samplesPerPixel == 1) { double windowWidth = Attribute.getSingleDoubleValueOrDefault(list, TagFromName.WindowWidth, 0); if (windowWidth > 0) { double windowCenter = Attribute.getSingleDoubleValueOrDefault(list, TagFromName.WindowCenter, 0); String voiLUTFunction = Attribute.getSingleStringValueOrDefault(list, TagFromName.VOILUTFunction, "LINEAR"); FunctionalGroupUtilities.generateVOILUTFunctionalGroup( list, numberOfFrames, windowWidth, windowCenter, voiLUTFunction); list.remove(TagFromName.WindowCenter); list.remove(TagFromName.WindowWidth); list.remove(TagFromName.VOILUTFunction); } } double rescaleSlope = Attribute.getSingleDoubleValueOrDefault(list, TagFromName.RescaleSlope, 0); if (rescaleSlope > 0) { double rescaleIntercept = Attribute.getSingleDoubleValueOrDefault(list, TagFromName.RescaleIntercept, 0); String rescaleType = Attribute.getSingleStringValueOrDefault(list, TagFromName.RescaleType, "US"); FunctionalGroupUtilities.generatePixelValueTransformationFunctionalGroup( list, numberOfFrames, rescaleSlope, rescaleIntercept, rescaleType); list.remove(TagFromName.RescaleSlope); list.remove(TagFromName.RescaleIntercept); list.remove(TagFromName.RescaleType); } // four values required { Attribute a = new CodeStringAttribute(TagFromName.ImageType); a.addValue("DERIVED"); a.addValue("PRIMARY"); a.addValue(""); a.addValue(""); list.put(a); } } else { // two values will usually do { Attribute a = new CodeStringAttribute(TagFromName.ImageType); a.addValue("DERIVED"); a.addValue("PRIMARY"); list.put(a); } } if (SOPClass.isMultiframeSecondaryCaptureImageStorage(sopClass)) { if (list.get(TagFromName.PerFrameFunctionalGroupsSequence) != null) { { AttributeTagAttribute a = new AttributeTagAttribute(TagFromName.FrameIncrementPointer); a.addValue(TagFromName.PerFrameFunctionalGroupsSequence); list.put(a); } } else { if (numberOfFrames > 1) { { AttributeTagAttribute a = new AttributeTagAttribute(TagFromName.FrameIncrementPointer); a.addValue(TagFromName.PageNumberVector); list.put(a); } { Attribute a = new IntegerStringAttribute(TagFromName.PageNumberVector); for (int page = 1; page <= numberOfFrames; ++page) { a.addValue(page); } list.put(a); } } } } System.err.println( "CommonConvertedAttributeGeneration.generateCommonAttributes(): SOP Class = " + sopClass); { Attribute a = new UniqueIdentifierAttribute(TagFromName.SOPClassUID); a.addValue(sopClass); list.put(a); } if (SOPClass.isSecondaryCaptureImageStorage(sopClass)) { { Attribute a = new CodeStringAttribute(TagFromName.ConversionType); a.addValue("WSD"); list.put(a); } } if (modality == null) { // could actually attempt to guess modality based on SOP Class here :( modality = "OT"; } { Attribute a = new CodeStringAttribute(TagFromName.Modality); a.addValue(modality); list.put(a); } { Attribute a = new SequenceAttribute(TagFromName.AcquisitionContextSequence); list.put(a); } }
/** @param list */ private void doCommonConstructorStuff(AttributeList list) throws DicomException { String sopClassUID = Attribute.getSingleStringValueOrEmptyString(list, TagFromName.SOPClassUID); if (SOPClass.isImageStorage(sopClassUID)) { // System.err.println("SuperimposedDicomSegments.doCommonConstructorStuff(): is an image"); SourceImage allFramesImage = new SourceImage(list); Attribute aSegmentSequence = list.get(TagFromName.SegmentSequence); Attribute aSharedFunctionalGroupsSequence = list.get(TagFromName.SharedFunctionalGroupsSequence); Attribute aPerFrameFunctionalGroupsSequence = list.get(TagFromName.PerFrameFunctionalGroupsSequence); int numberOfFrames = allFramesImage.getNumberOfBufferedImages(); if (allFramesImage != null && numberOfFrames > 0 && aSegmentSequence != null && aSegmentSequence instanceof SequenceAttribute && aSharedFunctionalGroupsSequence != null && aSharedFunctionalGroupsSequence instanceof SequenceAttribute && aPerFrameFunctionalGroupsSequence != null && aPerFrameFunctionalGroupsSequence instanceof SequenceAttribute) { System.err.println( "SuperimposedDicomSegments.doCommonConstructorStuff(): have a segmentation object with one or more frames"); SequenceAttribute saSegmentSequence = (SequenceAttribute) aSegmentSequence; int numberOfSegments = saSegmentSequence.getNumberOfItems(); if (numberOfSegments > 0) { for (int i = 0; i < numberOfSegments; ++i) { AttributeList itemList = saSegmentSequence.getItem(i).getAttributeList(); String segmentNumber = Attribute.getSingleStringValueOrEmptyString( itemList, TagFromName .SegmentNumber); // theoretically supposed to start at 1 and increase by 1, // but don't trust it if (segmentNumber.length() > 0) { int[] recommendedDisplayCIELabValues = Attribute.getIntegerValues(itemList, TagFromName.RecommendedDisplayCIELabValue); SegmentInformation si = segmentInformationBySegmentNumber.get(segmentNumber); if (si == null) { si = new SegmentInformation(segmentNumber, recommendedDisplayCIELabValues); segmentInformationBySegmentNumber.put(segmentNumber, si); } else { throw new DicomException("Duplicate segment number"); } } else { throw new DicomException("Missing segment number"); } } } else { System.err.println( "SuperimposedDicomSegments.doCommonConstructorStuff(): Error: No segments in segmentation object"); } SequenceAttribute saSharedFunctionalGroupsSequence = (SequenceAttribute) aSharedFunctionalGroupsSequence; SequenceAttribute saPerFrameFunctionalGroupsSequence = (SequenceAttribute) aPerFrameFunctionalGroupsSequence; SequenceAttribute sharedSegmentIdentificationSequence = (SequenceAttribute) (SequenceAttribute.getNamedAttributeFromWithinSequenceWithSingleItem( saSharedFunctionalGroupsSequence, TagFromName.SegmentIdentificationSequence)); int nPerFrameFunctionalGroupsSequence = saPerFrameFunctionalGroupsSequence.getNumberOfItems(); if (nPerFrameFunctionalGroupsSequence == numberOfFrames) { for (int f = 0; f < numberOfFrames; ++f) { SequenceAttribute useSegmentIdentificationSequence = sharedSegmentIdentificationSequence; if (useSegmentIdentificationSequence == null) { useSegmentIdentificationSequence = (SequenceAttribute) (saPerFrameFunctionalGroupsSequence .getItem(f) .getAttributeList() .get(TagFromName.SegmentIdentificationSequence)); } if (useSegmentIdentificationSequence != null) { Attribute aReferencedSegmentNumber = SequenceAttribute.getNamedAttributeFromWithinSequenceWithSingleItem( useSegmentIdentificationSequence, TagFromName.ReferencedSegmentNumber); String referencedSegmentNumber = aReferencedSegmentNumber == null ? "" : aReferencedSegmentNumber.getSingleStringValueOrEmptyString(); if (referencedSegmentNumber.length() > 0) { SortedSet<Integer> framesForSegment = framesForSegmentBySegmentNumber.get(referencedSegmentNumber); if (framesForSegment == null) { framesForSegment = new TreeSet<Integer>(); framesForSegmentBySegmentNumber.put(referencedSegmentNumber, framesForSegment); } framesForSegment.add(new Integer(f)); } else { throw new DicomException("Missing ReferencedSegmentNumber for frame " + f); } } else { throw new DicomException("Missing SegmentIdentificationSequence for frame " + f); } } } else { throw new DicomException( "Number of frames " + numberOfFrames + " does not match number of PerFrameFunctionalGroupsSequence items " + nPerFrameFunctionalGroupsSequence); } // SortedMap<String,SortedSet<Integer>> framesForSegmentBySegmentNumber for (String segmentNumber : framesForSegmentBySegmentNumber.keySet()) { // System.err.println("SuperimposedDicomSegments.doCommonConstructorStuff(): Making // SourceImageSubset for segmentNumber "+segmentNumber); SortedSet<Integer> framesForSegment = framesForSegmentBySegmentNumber.get(segmentNumber); int[] parentFrameNumbers = new int[framesForSegment.size()]; { int childFrameNumber = 0; for (Integer parentFrameNumber : framesForSegment) { // System.err.println("SuperimposedDicomSegments.doCommonConstructorStuff(): // parentFrameNumber["+childFrameNumber+"] = "+parentFrameNumber); parentFrameNumbers[childFrameNumber++] = parentFrameNumber.intValue(); } } SourceImage sourceImageForSegment = new SourceImageSubset(allFramesImage, parentFrameNumbers); GeometryOfVolume geometryForSegment = new GeometryOfVolumeFromAttributeList(list, parentFrameNumbers); if (!geometryForSegment.isVolumeSampledRegularlyAlongFrameDimension()) { System.err.println( "SuperimposedDicomSegments.doCommonConstructorStuff(): Warning: superimposed geometry is not a single regularly sampled volume for segment " + segmentNumber); } superimposedImagesBySegmentNumber.put( segmentNumber, new SuperimposedImage( sourceImageForSegment, geometryForSegment, segmentInformationBySegmentNumber.get(segmentNumber) .recommendedDisplayCIELabValues)); } // superimposedGeometry = new GeometryOfVolumeFromAttributeList(list); // if (!superimposedGeometry.isVolumeSampledRegularlyAlongFrameDimension()) { // System.err.println("SuperimposedDicomSegments.doCommonConstructorStuff(): Warning: // superimposed geometry is not a single regularly sampled volume"); // } } else { System.err.println( "SuperimposedDicomSegments.doCommonConstructorStuff(): Error: Not a valid segmentation object"); } } }