Skip to content

Commit

Permalink
Support parsing NativePixelData when it appears multiple times in a D…
Browse files Browse the repository at this point in the history
…ICOM (#79)

This fixes #77 and appears to work on provided DICOMs. This is a relatively quick fix, that does seem to get the job done. There are some minor improvements that can be made in future PRs, but it will be best to get these changes in to unblock future work.

This also appears to fix #82, and fix #65 (we are able to parse those images without errors).

For most of the provided images, the issue was that an icon image sequence could appear in the DICOMs in addition to the primary PixelData. When reading that particular image sequence, a different set of metadata tags need to be used (instead of the global ones, which apply only to the core PixelData).

There may be additional work to fully and correctly parsing icon image sets (most of the icons seem to be unpopulated in the sample images), but this change will at least prevent the parser from failing on DICOMs like this.
  • Loading branch information
suyashkumar authored Jun 8, 2020
1 parent 2daf5f9 commit 9d8d8d9
Showing 1 changed file with 25 additions and 9 deletions.
34 changes: 25 additions & 9 deletions parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ type parser struct {
parsedElements *element.DataSet
op ParseOptions
frameChannel chan *frame.Frame
file *os.File // may be populated if coming from file
file *os.File // may be populated if this parser is coming from a file
// currentSequenceDataset is populated with Elements read so far in a SQ DICOM sequence (or is nil if not currently
// reading a sequence).
currentSequenceDataset *element.DataSet
}

// NewParser initializes and returns a new Parser
Expand Down Expand Up @@ -163,11 +166,15 @@ func (p *parser) Parse(options ParseOptions) (*element.DataSet, error) {
}

}
if p.frameChannel != nil {
close(p.frameChannel)
}
return p.parsedElements, p.decoder.Error()
}

func (p *parser) ParseNext(options ParseOptions) *element.Element {
tag := readTag(p.decoder)

if tag == dicomtag.PixelData && options.DropPixelData {
return element.EndOfData
}
Expand Down Expand Up @@ -254,9 +261,7 @@ func (p *parser) ParseNext(options ParseOptions) *element.Element {
p.frameChannel <- &f // write frame to channel
}
}
if p.frameChannel != nil {
close(p.frameChannel)
}

data = append(data, image)
} else {
// Assume we're reading NativeData data since we have a defined value length as per Part 5 Sec A.4 of DICOM spec.
Expand All @@ -266,7 +271,13 @@ func (p *parser) ParseNext(options ParseOptions) *element.Element {
return nil // TODO(suyash) investigate error handling in this library
}

image, _, err := readNativeFrames(p.decoder, p.parsedElements, p.frameChannel)
datasetToUse := p.parsedElements

if p.currentSequenceDataset != nil && len(p.currentSequenceDataset.Elements) > 0 {
datasetToUse = p.currentSequenceDataset
}

image, _, err := readNativeFrames(p.decoder, datasetToUse, p.frameChannel)

if err != nil {
p.decoder.SetError(err)
Expand All @@ -280,6 +291,10 @@ func (p *parser) ParseNext(options ParseOptions) *element.Element {
// Note: when reading subitems inside sequence or item, we ignore
// DropPixelData and other shortcircuiting options. If we honored them, we'decoder
// be unable to read the rest of the file.

// TODO: refactor to avoid temporarily storing two copies
oldDataset := p.currentSequenceDataset
p.currentSequenceDataset = &element.DataSet{}
if vl == element.VLUndefinedLength {
// Format:
// Sequence := ItemSet* SequenceDelimitationItem
Expand Down Expand Up @@ -316,9 +331,12 @@ func (p *parser) ParseNext(options ParseOptions) *element.Element {
break
}
data = append(data, item)
p.currentSequenceDataset.Elements = append(p.currentSequenceDataset.Elements, item)
}
p.decoder.PopLimit()
}
// Restore oldDataset if any:
p.currentSequenceDataset = oldDataset
} else if tag == dicomtag.Item { // Item (component of SQ)
if vl == element.VLUndefinedLength {
// Format: Item Any* ItemDelimitationItem
Expand All @@ -332,6 +350,7 @@ func (p *parser) ParseNext(options ParseOptions) *element.Element {
break
}
data = append(data, subelem)
p.currentSequenceDataset.Elements = append(p.currentSequenceDataset.Elements, subelem)
}
} else {
// Sequence of arbitary elements, for the total of "vl" bytes.
Expand All @@ -343,6 +362,7 @@ func (p *parser) ParseNext(options ParseOptions) *element.Element {
break
}
data = append(data, subelem)
p.currentSequenceDataset.Elements = append(p.currentSequenceDataset.Elements, subelem)
}
p.decoder.PopLimit()
}
Expand Down Expand Up @@ -590,10 +610,6 @@ func readNativeFrames(d *dicomio.Decoder, parsedData *element.DataSet, frameChan
}
}

if frameChan != nil {
close(frameChan) // close frameChan if it exists
}

bytesRead = (bitsAllocated / 8) * samplesPerPixel * pixelsPerFrame * nFrames

return &image, bytesRead, nil
Expand Down

0 comments on commit 9d8d8d9

Please sign in to comment.