func ReadNestedManifest(manifestPath, annotationPath, nestedSuffix string) (*AnnotationTracker, error) {

	mayBeNested := true

	// We assume that the Dicom filename for the merged image file has this
	// suffix. TODO: Make configurable.
	assumedMergedImageSuffix := ".png.overlay.png"

	// Fetch any annotations that already exist, or create a file to hold them
	// if none yet do.
	annotations, err := OpenOrCreateAnnotationFile(annotationPath)
	if err != nil {
		return nil, err
	}

	// Now open the full manifest of files we want to critique.
	f, _, err := bulkprocess.MaybeOpenFromGoogleStorage(manifestPath, global.storageClient)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	cr := csv.NewReader(f)
	cr.Comma = '\t'
	recs, err := cr.ReadAll()
	if err != nil {
		return nil, err
	}

	output := make([]ManifestEntry, 0, len(recs))

	header := struct {
		SampleID       int
		Zip            int
		Dicom          int
		Series         int
		InstanceNumber int
	}{
		0,
		-1,
		-1,
		0,
		0,
	}

	for i, cols := range recs {
		if i == 0 {
			for j, col := range cols {
				if col == "zip_file" {
					header.Zip = j
				} else if col == "dicom_file" {
					header.Dicom = j
				} else if col == "series" {
					header.Series = j
				} else if col == "instance_number" {
					header.InstanceNumber = j
				} else if col == "sample_id" {
					header.SampleID = j
				}
			}
			continue
		}

		if header.Dicom == -1 {
			return nil, fmt.Errorf("header column 'dicom_file' not detected")
		}

		// If Zip isn't found, this isn't an error, unless you intended to use a
		// nested structure
		if header.Zip == -1 {
			mayBeNested = false
			header.Zip = 0

			if nestedSuffix != "" {
				return nil, fmt.Errorf("header column 'zip_file' not detected")
			}
		}

		intInstance, err := strconv.Atoi(cols[header.InstanceNumber])
		if err != nil {
			// Ignore the error
			intInstance = 0
		}

		anno, _ := annotations[DicomFilename(cols[header.Dicom])]
		// Set the annotation DICOM name to be the raw dicom name
		anno.Dicom = cols[header.Dicom]

		output = append(output, ManifestEntry{
			SampleID:       cols[header.SampleID],
			Zip:            MergedNameToRawName(cols[header.Zip], nestedSuffix, ".zip"),
			Dicom:          cols[header.Dicom] + assumedMergedImageSuffix, // Total hack
			Series:         cols[header.Series],
			InstanceNumber: intInstance,
			Annotation:     anno,
		})
	}

	// For now, don't sort manifests - permits you to arrange them in a preprocessing step
	// sort.Slice(output, generateManifestSorter(output))

	return &AnnotationTracker{Entries: output, Nested: mayBeNested, AnnotationPath: annotationPath}, nil
}
// ReadNestedManifest will attempt to parse a classical manifest. This is
// necessary when the image files are nested within a container.
ReadNestedManifest will attempt to parse a classical manifest. This is
necessary when the image files are nested within a container.
// ReadNestedManifest will attempt to parse a classical manifest . This is // necessary when the image files are nested within a container .
func ReadNestedManifest(manifestPath, annotationPath, nestedSuffix string) (*AnnotationTracker, error) {
	mayBeNested := true
	assumedMergedImageSuffix := ".png.overlay.png"
	annotations, err := OpenOrCreateAnnotationFile(annotationPath)
	if err != nil {
		return nil, err
	}
	f, _, err := bulkprocess.MaybeOpenFromGoogleStorage(manifestPath, global.storageClient)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	cr := csv.NewReader(f)
	cr.Comma = '\t'
	recs, err := cr.ReadAll()
	if err != nil {
		return nil, err
	}
	output := make([]ManifestEntry, 0, len(recs))
	header := struct {
		SampleID       int
		Zip            int
		Dicom          int
		Series         int
		InstanceNumber int
	}{
		0,
		-1,
		-1,
		0,
		0,
	}
	for i, cols := range recs {
		if i == 0 {
			for j, col := range cols {
				if col == "zip_file" {
					header.Zip = j
				} else if col == "dicom_file" {
					header.Dicom = j
				} else if col == "series" {
					header.Series = j
				} else if col == "instance_number" {
					header.InstanceNumber = j
				} else if col == "sample_id" {
					header.SampleID = j
				}
			}
			continue
		}
		if header.Dicom == -1 {
			return nil, fmt.Errorf("header column 'dicom_file' not detected")
		}
		if header.Zip == -1 {
			mayBeNested = false
			header.Zip = 0
			if nestedSuffix != "" {
				return nil, fmt.Errorf("header column 'zip_file' not detected")
			}
		}
		intInstance, err := strconv.Atoi(cols[header.InstanceNumber])
		if err != nil {
			intInstance = 0
		}
		anno, _ := annotations[DicomFilename(cols[header.Dicom])]
		anno.Dicom = cols[header.Dicom]
		output = append(output, ManifestEntry{
			SampleID:       cols[header.SampleID],
			Zip:            MergedNameToRawName(cols[header.Zip], nestedSuffix, ".zip"),
			Dicom:          cols[header.Dicom] + assumedMergedImageSuffix, 
			Series:         cols[header.Series],
			InstanceNumber: intInstance,
			Annotation:     anno,
		})
	}
	return &AnnotationTracker{Entries: output, Nested: mayBeNested, AnnotationPath: annotationPath}, nil
}
func ReadNestedManifest ( manifestPath , annotationPath , nestedSuffix string ) ( * AnnotationTracker , error ) { mayBeNested := true assumedMergedImageSuffix := " " annotations , err := OpenOrCreateAnnotationFile ( annotationPath ) if err != nil { return nil , err } f , _ , err := bulkprocess . MaybeOpenFromGoogleStorage ( manifestPath , global . storageClient ) if err != nil { return nil , err } defer f . Close ( ) cr := csv . NewReader ( f ) cr . Comma = '\t' recs , err := cr . ReadAll ( ) if err != nil { return nil , err } output := make ( [ ] ManifestEntry , 0 , len ( recs ) ) header := struct { SampleID int Zip int Dicom int Series int InstanceNumber int } { 0 , - 1 , - 1 , 0 , 0 , } for i , cols := range recs { if i == 0 { for j , col := range cols { if col == " " { header . Zip = j } else if col == " " { header . Dicom = j } else if col == " " { header . Series = j } else if col == " " { header . InstanceNumber = j } else if col == " " { header . SampleID = j } } continue } if header . Dicom == - 1 { return nil , fmt . Errorf ( " " ) } if header . Zip == - 1 { mayBeNested = false header . Zip = 0 if nestedSuffix != " " { return nil , fmt . Errorf ( " " ) } } intInstance , err := strconv . Atoi ( cols [ header . InstanceNumber ] ) if err != nil { intInstance = 0 } anno , _ := annotations [ DicomFilename ( cols [ header . Dicom ] ) ] anno . Dicom = cols [ header . Dicom ] output = append ( output , ManifestEntry { SampleID : cols [ header . SampleID ] , Zip : MergedNameToRawName ( cols [ header . Zip ] , nestedSuffix , " " ) , Dicom : cols [ header . Dicom ] + assumedMergedImageSuffix , Series : cols [ header . Series ] , InstanceNumber : intInstance , Annotation : anno , } ) } return & AnnotationTracker { Entries : output , Nested : mayBeNested , AnnotationPath : annotationPath } , nil }
ReadNestedManifest will attempt to parse a classical manifest.
ReadNestedManifest will attempt to parse a classical manifest .
// We assume that the Dicom filename for the merged image file has this // suffix. TODO: Make configurable. // Fetch any annotations that already exist, or create a file to hold them // if none yet do. // Now open the full manifest of files we want to critique. // If Zip isn't found, this isn't an error, unless you intended to use a // nested structure // Ignore the error // Set the annotation DICOM name to be the raw dicom name // Total hack // For now, don't sort manifests - permits you to arrange them in a preprocessing step // sort.Slice(output, generateManifestSorter(output))