// NdDataSchema returns the metadata in JSON for this Data func (p *Properties) NdDataMetadata() (string, error) { var err error var size, offset dvid.Point dims := int(p.BlockSize.NumDims()) if p.MinPoint == nil || p.MaxPoint == nil { zeroPt := make([]int32, dims) size, err = dvid.NewPoint(zeroPt) if err != nil { return "", err } offset = size } else { size = p.MaxPoint.Sub(p.MinPoint).AddScalar(1) offset = p.MinPoint } var axesName = []string{"X", "Y", "Z", "t", "c"} var metadata metadataT metadata.Axes = []axisT{} for dim := 0; dim < dims; dim++ { metadata.Axes = append(metadata.Axes, axisT{ Label: axesName[dim], Resolution: p.Resolution.VoxelSize[dim], Units: p.Resolution.VoxelUnits[dim], Size: size.Value(uint8(dim)), Offset: offset.Value(uint8(dim)), }) } metadata.Properties = *p m, err := json.Marshal(metadata) if err != nil { return "", err } return string(m), nil }
// GetGoogleSubvolGeom returns a google-specific voxel spec, which includes how the data is positioned relative to // scaled volume boundaries. Not that the size parameter is the desired size and not what is required to fit // within a scaled volume. func (d *Data) GetGoogleSubvolGeom(scaling Scaling, shape dvid.DataShape, offset dvid.Point3d, size dvid.Point) (*GoogleSubvolGeom, error) { gsg := new(GoogleSubvolGeom) if err := gsg.shape.FromShape(shape); err != nil { return nil, err } gsg.offset = offset // If 2d plane, convert combination of plane and size into 3d size. if size.NumDims() == 2 { size2d := size.(dvid.Point2d) sizeWant, err := dvid.GetPoint3dFrom2d(shape, size2d, 1) if err != nil { return nil, err } gsg.sizeWant = sizeWant } else { var ok bool gsg.sizeWant, ok = size.(dvid.Point3d) if !ok { return nil, fmt.Errorf("Can't convert %v to dvid.Point3d", size) } } // Determine which geometry is appropriate given the scaling and the shape/orientation tileSpec, err := GetGSpec(scaling, shape) if err != nil { return nil, err } geomIndex, found := d.GeomMap[*tileSpec] if !found { return nil, fmt.Errorf("Could not find scaled volume in %q for %s with scaling %d", d.DataName(), shape, scaling) } geom := d.Scales[geomIndex] gsg.gi = geomIndex gsg.channelCount = geom.ChannelCount gsg.channelType = geom.ChannelType // Get the # bytes for each pixel switch geom.ChannelType { case "UINT8": gsg.bytesPerVoxel = 1 case "FLOAT": gsg.bytesPerVoxel = 4 case "UINT64": gsg.bytesPerVoxel = 8 default: return nil, fmt.Errorf("Unknown volume channel type in %s: %s", d.DataName(), geom.ChannelType) } // Check if the requested area is completely outside the volume. volumeSize := geom.VolumeSize if offset[0] >= volumeSize[0] || offset[1] >= volumeSize[1] || offset[2] >= volumeSize[2] { gsg.outside = true return gsg, nil } // Check if the requested shape is on the edge and adjust size. adjSize := gsg.sizeWant maxpt := offset.Add(adjSize) for i := uint8(0); i < 3; i++ { if maxpt.Value(i) > volumeSize[i] { gsg.edge = true adjSize[i] = volumeSize[i] - offset[i] } } gsg.size = adjSize return gsg, nil }
func (v *Voxels) readScaledBlock(block *storage.TKeyValue, blockSize dvid.Point, attenuation uint8) error { if blockSize.NumDims() > 3 { return fmt.Errorf("DVID voxel blocks currently only supports up to 3d, not 4+ dimensions") } blockBeg, dataBeg, dataEnd, err := v.ComputeTransform(block, blockSize) if err != nil { return err } data := v.Data() bytesPerVoxel := int64(v.Values().BytesPerElement()) if bytesPerVoxel != 1 { return fmt.Errorf("Can only scale non-ROI blocks with 1 byte voxels") } // Compute the strides (in bytes) bX := int64(blockSize.Value(0)) * bytesPerVoxel bY := int64(blockSize.Value(1)) * bX dX := int64(v.Stride()) // Get the block beginning coordinates. blockBegX := int64(blockBeg.Value(0)) blockBegY := int64(blockBeg.Value(1)) blockBegZ := int64(blockBeg.Value(2)) // Do the transfers depending on shape of the external voxels. switch { case v.DataShape().Equals(dvid.XY): blockI := blockBegZ*bY + blockBegY*bX + blockBegX*bytesPerVoxel dataI := int64(dataBeg.Value(1))*dX + int64(dataBeg.Value(0))*bytesPerVoxel for y := dataBeg.Value(1); y <= dataEnd.Value(1); y++ { for x := int64(dataBeg.Value(0)); x <= int64(dataEnd.Value(0)); x++ { data[dataI+x] = (block.V[blockI+x] >> attenuation) } blockI += bX dataI += dX } case v.DataShape().Equals(dvid.XZ): blockI := blockBegZ*bY + blockBegY*bX + blockBegX*bytesPerVoxel dataI := int64(dataBeg.Value(2))*dX + int64(dataBeg.Value(0))*bytesPerVoxel for y := dataBeg.Value(2); y <= dataEnd.Value(2); y++ { for x := int64(dataBeg.Value(0)); x <= int64(dataEnd.Value(0)); x++ { data[dataI+x] = (block.V[blockI+x] >> attenuation) } blockI += bY dataI += dX } case v.DataShape().Equals(dvid.YZ): bz := blockBegZ for y := int64(dataBeg.Value(2)); y <= int64(dataEnd.Value(2)); y++ { blockI := blockBegZ*bY + blockBegY*bX + blockBegX*bytesPerVoxel dataI := y*dX + int64(dataBeg.Value(1))*bytesPerVoxel for x := dataBeg.Value(1); x <= dataEnd.Value(1); x++ { data[dataI] = (block.V[blockI] >> attenuation) blockI += bX dataI += bytesPerVoxel } bz++ } case v.DataShape().ShapeDimensions() == 2: // TODO: General code for handling 2d ExtData in n-d space. return fmt.Errorf("DVID currently does not support 2d in n-d space.") case v.DataShape().Equals(dvid.Vol3d): blockOffset := blockBegX * bytesPerVoxel dX := int64(v.Size().Value(0)) * bytesPerVoxel dY := int64(v.Size().Value(1)) * dX dataOffset := int64(dataBeg.Value(0)) * bytesPerVoxel blockZ := blockBegZ for dataZ := dataBeg.Value(2); dataZ <= dataEnd.Value(2); dataZ++ { blockY := blockBegY for dataY := dataBeg.Value(1); dataY <= dataEnd.Value(1); dataY++ { blockI := blockZ*bY + blockY*bX + blockOffset dataI := int64(dataZ)*dY + int64(dataY)*dX + dataOffset for x := int64(dataBeg.Value(0)); x <= int64(dataEnd.Value(0)); x++ { data[dataI+x] = (block.V[blockI+x] >> attenuation) } blockY++ } blockZ++ } default: return fmt.Errorf("Cannot readScaledBlock() unsupported voxels data shape %s", v.DataShape()) } return nil }
func (v *Voxels) writeBlock(block *storage.TKeyValue, blockSize dvid.Point) error { if blockSize.NumDims() > 3 { return fmt.Errorf("DVID voxel blocks currently only supports up to 3d, not 4+ dimensions") } blockBeg, dataBeg, dataEnd, err := v.ComputeTransform(block, blockSize) if err != nil { return err } data := v.Data() bytesPerVoxel := int64(v.Values().BytesPerElement()) // Compute the strides (in bytes) bX := int64(blockSize.Value(0)) * bytesPerVoxel bY := int64(blockSize.Value(1)) * bX dX := int64(v.Stride()) blockBegX := int64(blockBeg.Value(0)) blockBegY := int64(blockBeg.Value(1)) blockBegZ := int64(blockBeg.Value(2)) // Do the transfers depending on shape of the external voxels. switch { case v.DataShape().Equals(dvid.XY): dataI := int64(dataBeg.Value(1))*dX + int64(dataBeg.Value(0))*bytesPerVoxel blockI := blockBegZ*bY + blockBegY*bX + blockBegX*bytesPerVoxel bytes := int64(dataEnd.Value(0)-dataBeg.Value(0)+1) * bytesPerVoxel for y := dataBeg.Value(1); y <= dataEnd.Value(1); y++ { copy(block.V[blockI:blockI+bytes], data[dataI:dataI+bytes]) blockI += bX dataI += dX } case v.DataShape().Equals(dvid.XZ): dataI := int64(dataBeg.Value(2))*dX + int64(dataBeg.Value(0))*bytesPerVoxel blockI := blockBegZ*bY + blockBegY*bX + blockBegX*bytesPerVoxel bytes := int64(dataEnd.Value(0)-dataBeg.Value(0)+1) * bytesPerVoxel for y := dataBeg.Value(2); y <= dataEnd.Value(2); y++ { copy(block.V[blockI:blockI+bytes], data[dataI:dataI+bytes]) blockI += bY dataI += dX } case v.DataShape().Equals(dvid.YZ): bz := blockBegZ for y := int64(dataBeg.Value(2)); y <= int64(dataEnd.Value(2)); y++ { dataI := y*dX + int64(dataBeg.Value(1))*bytesPerVoxel blockI := bz*bY + blockBegY*bX + blockBegX*bytesPerVoxel for x := dataBeg.Value(1); x <= dataEnd.Value(1); x++ { copy(block.V[blockI:blockI+bytesPerVoxel], data[dataI:dataI+bytesPerVoxel]) blockI += bX dataI += bytesPerVoxel } bz++ } case v.DataShape().ShapeDimensions() == 2: // TODO: General code for handling 2d ExtData in n-d space. return fmt.Errorf("DVID currently does not support 2d in n-d space.") case v.DataShape().Equals(dvid.Vol3d): blockOffset := blockBegX * bytesPerVoxel dX := int64(v.Size().Value(0)) * bytesPerVoxel dY := int64(v.Size().Value(1)) * dX dataOffset := int64(dataBeg.Value(0)) * bytesPerVoxel bytes := int64(dataEnd.Value(0)-dataBeg.Value(0)+1) * bytesPerVoxel blockZ := blockBegZ for dataZ := int64(dataBeg.Value(2)); dataZ <= int64(dataEnd.Value(2)); dataZ++ { blockY := blockBegY for dataY := int64(dataBeg.Value(1)); dataY <= int64(dataEnd.Value(1)); dataY++ { dataI := dataZ*dY + dataY*dX + dataOffset blockI := blockZ*bY + blockY*bX + blockOffset copy(block.V[blockI:blockI+bytes], data[dataI:dataI+bytes]) blockY++ } blockZ++ } default: return fmt.Errorf("Cannot writeBlock() unsupported voxels data shape %s", v.DataShape()) } return nil }
func (v *Labels) readMappedBlock(block *storage.TKeyValue, blockSize dvid.Point, m *labels.Mapping) error { if blockSize.NumDims() > 3 { return fmt.Errorf("DVID voxel blocks currently only supports up to 3d, not 4+ dimensions") } blockBeg, dataBeg, dataEnd, err := v.ComputeTransform(block, blockSize) if err != nil { return err } data := v.Data() // Compute the strides (in bytes) bX := int64(blockSize.Value(0)) * 8 bY := int64(blockSize.Value(1)) * bX dX := int64(v.Stride()) blockBegX := int64(blockBeg.Value(0)) blockBegY := int64(blockBeg.Value(1)) blockBegZ := int64(blockBeg.Value(2)) // Do the transfers depending on shape of the external voxels. switch { case v.DataShape().Equals(dvid.XY): dataI := int64(dataBeg.Value(1))*dX + int64(dataBeg.Value(0))*8 blockI := blockBegZ*bY + blockBegY*bX + blockBegX*8 for y := int64(dataBeg.Value(1)); y <= int64(dataEnd.Value(1)); y++ { bI := blockI dI := dataI for x := dataBeg.Value(0); x <= dataEnd.Value(0); x++ { orig := binary.LittleEndian.Uint64(block.V[bI : bI+8]) mapped, found := m.FinalLabel(orig) if found { binary.LittleEndian.PutUint64(data[dI:dI+8], mapped) } else { copy(data[dI:dI+8], block.V[bI:bI+8]) } bI += 8 dI += 8 } blockI += bX dataI += dX } case v.DataShape().Equals(dvid.XZ): dataI := int64(dataBeg.Value(2))*dX + int64(dataBeg.Value(0))*8 blockI := blockBegZ*bY + blockBegY*bX + blockBegX*8 for y := int64(dataBeg.Value(2)); y <= int64(dataEnd.Value(2)); y++ { bI := blockI dI := dataI for x := dataBeg.Value(0); x <= dataEnd.Value(0); x++ { orig := binary.LittleEndian.Uint64(block.V[bI : bI+8]) mapped, found := m.FinalLabel(orig) if found { binary.LittleEndian.PutUint64(data[dI:dI+8], mapped) } else { copy(data[dI:dI+8], block.V[bI:bI+8]) } bI += 8 dI += 8 } blockI += bY dataI += dX } case v.DataShape().Equals(dvid.YZ): bz := blockBegZ for y := int64(dataBeg.Value(2)); y <= int64(dataEnd.Value(2)); y++ { dataI := y*dX + int64(dataBeg.Value(1))*8 blockI := bz*bY + blockBegY*bX + blockBegX*8 for x := dataBeg.Value(1); x <= dataEnd.Value(1); x++ { orig := binary.LittleEndian.Uint64(block.V[blockI : blockI+8]) mapped, found := m.FinalLabel(orig) if found { binary.LittleEndian.PutUint64(data[dataI:dataI+8], mapped) } else { copy(data[dataI:dataI+8], block.V[blockI:blockI+8]) } blockI += bX dataI += 8 } bz++ } case v.DataShape().ShapeDimensions() == 2: // TODO: General code for handling 2d ExtData in n-d space. return fmt.Errorf("DVID currently does not support 2d in n-d space.") case v.DataShape().Equals(dvid.Vol3d): blockOffset := blockBegX * 8 dX := int64(v.Size().Value(0)) * 8 dY := int64(v.Size().Value(1)) * dX dataOffset := int64(dataBeg.Value(0)) * 8 blockZ := blockBegZ for dataZ := int64(dataBeg.Value(2)); dataZ <= int64(dataEnd.Value(2)); dataZ++ { blockY := blockBegY for dataY := int64(dataBeg.Value(1)); dataY <= int64(dataEnd.Value(1)); dataY++ { bI := blockZ*bY + blockY*bX + blockOffset dI := dataZ*dY + dataY*dX + dataOffset for x := dataBeg.Value(0); x <= dataEnd.Value(0); x++ { orig := binary.LittleEndian.Uint64(block.V[bI : bI+8]) mapped, found := m.FinalLabel(orig) if found { binary.LittleEndian.PutUint64(data[dI:dI+8], mapped) } else { copy(data[dI:dI+8], block.V[bI:bI+8]) } bI += 8 dI += 8 } blockY++ } blockZ++ } default: return fmt.Errorf("Cannot readBlock() unsupported voxels data shape %s", v.DataShape()) } return nil }