// NewLabels returns labelblk Labels, a representation of externally usable subvolume // or slice data, given some geometry and optional image data. // If img is passed in, the function will initialize Voxels with data from the image. // Otherwise, it will allocate a zero buffer of appropriate size. // // TODO : Unlike the standard imageblk.NewVoxels, the labelblk version can modify the // labels based on the z-coordinate of the given geometry for Raveler labeling. // This will be removed when Raveler-specific labels are moved outside DVID. func (d *Data) NewLabels(geom dvid.Geometry, img interface{}) (*Labels, error) { bytesPerVoxel := d.Properties.Values.BytesPerElement() stride := geom.Size().Value(0) * bytesPerVoxel var data []byte if img == nil { numVoxels := geom.NumVoxels() if numVoxels <= 0 { return nil, fmt.Errorf("Illegal geometry requested: %s", geom) } requestSize := int64(bytesPerVoxel) * numVoxels if requestSize > server.MaxDataRequest { return nil, fmt.Errorf("Requested payload (%d bytes) exceeds this DVID server's set limit (%d)", requestSize, server.MaxDataRequest) } data = make([]byte, requestSize) } else { switch t := img.(type) { case image.Image: var inputBytesPerVoxel, actualStride int32 var err error data, inputBytesPerVoxel, actualStride, err = dvid.ImageData(t) if err != nil { return nil, err } if actualStride != stride { // Need to do some conversion here. switch d.Labeling { case Standard64bit: data, err = d.convertTo64bit(geom, data, int(inputBytesPerVoxel), int(actualStride)) if err != nil { return nil, err } case RavelerLabel: data, err = d.addLabelZ(geom, data, actualStride) if err != nil { return nil, err } default: return nil, fmt.Errorf("unexpected label type in labelblk: %s", d.Labeling) } } case []byte: data = t actualLen := int64(len(data)) expectedLen := int64(bytesPerVoxel) * geom.NumVoxels() if actualLen != expectedLen { return nil, fmt.Errorf("labels data was %d bytes, expected %d bytes for %s", actualLen, expectedLen, geom) } default: return nil, fmt.Errorf("unexpected image type given to NewVoxels(): %T", t) } } labels := &Labels{ imageblk.NewVoxels(geom, d.Properties.Values, data, stride), } return labels, nil }
// Create a RGB interleaved volume. func (d *Data) storeComposite(v dvid.VersionID, channels []*Channel) error { // Setup the composite Channel geom := channels[0].Geometry pixels := int(geom.NumVoxels()) stride := geom.Size().Value(0) * 4 composite := &Channel{ Voxels: imageblk.NewVoxels(geom, compositeValues, channels[0].Data(), stride), channelNum: channels[0].channelNum, } // Get the min/max of each channel. numChannels := len(channels) if numChannels > 3 { numChannels = 3 } var min, max [3]uint16 min[0] = uint16(0xFFFF) min[1] = uint16(0xFFFF) min[2] = uint16(0xFFFF) for c := 0; c < numChannels; c++ { channel := channels[c] data := channel.Data() beg := 0 for i := 0; i < pixels; i++ { value := binary.LittleEndian.Uint16(data[beg : beg+2]) if value < min[c] { min[c] = value } if value > max[c] { max[c] = value } beg += 2 } } // Do second pass, normalizing each channel and storing it into the appropriate byte. compdata := composite.Voxels.Data() for c := 0; c < numChannels; c++ { channel := channels[c] window := int(max[c] - min[c]) if window == 0 { window = 1 } data := channel.Data() beg := 0 begC := c // Channel 0 -> R, Channel 1 -> G, Channel 2 -> B for i := 0; i < pixels; i++ { value := binary.LittleEndian.Uint16(data[beg : beg+2]) normalized := 255 * int(value-min[c]) / window if normalized > 255 { normalized = 255 } compdata[begC] = uint8(normalized) beg += 2 begC += 4 } } // Set the alpha channel to 255. alphaI := 3 for i := 0; i < pixels; i++ { compdata[alphaI] = 255 alphaI += 4 } // Store the result return d.PutVoxels(v, composite.Voxels, nil) }
// ServeHTTP handles all incoming HTTP requests for this data. func (d *Data) ServeHTTP(uuid dvid.UUID, ctx *datastore.VersionedCtx, w http.ResponseWriter, r *http.Request) { timedLog := dvid.NewTimeLog() // Get the action (GET, POST) action := strings.ToLower(r.Method) switch action { case "get": case "post": default: server.BadRequest(w, r, "Can only handle GET or POST HTTP verbs") return } // Break URL request into arguments url := r.URL.Path[len(server.WebAPIPath):] parts := strings.Split(url, "/") if len(parts[len(parts)-1]) == 0 { parts = parts[:len(parts)-1] } if len(parts) < 4 { server.BadRequest(w, r, "Incomplete API request") return } // Process help and info. switch parts[3] { case "help": w.Header().Set("Content-Type", "text/plain") fmt.Fprintln(w, d.Help()) return case "info": jsonBytes, err := d.MarshalJSON() if err != nil { server.BadRequest(w, r, err) return } w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, string(jsonBytes)) return default: } // Get the data name and parse out the channel number or see if composite is required. var channelNum int32 channumStr := strings.TrimPrefix(parts[2], string(d.DataName())) if len(channumStr) == 0 { channelNum = 0 } else { n, err := strconv.ParseInt(channumStr, 10, 32) if err != nil { server.BadRequest(w, r, "Error parsing channel number from data name '%s': %v", parts[2], err) return } if int(n) > d.NumChannels { minChannelName := fmt.Sprintf("%s1", d.DataName()) maxChannelName := fmt.Sprintf("%s%d", d.DataName(), d.NumChannels) server.BadRequest(w, r, "Data only has %d channels. Use names '%s' -> '%s'", d.NumChannels, minChannelName, maxChannelName) return } channelNum = int32(n) } // Get the data shape. shapeStr := dvid.DataShapeString(parts[3]) dataShape, err := shapeStr.DataShape() if err != nil { server.BadRequest(w, r, "Bad data shape given '%s'", shapeStr) return } switch dataShape.ShapeDimensions() { case 2: sizeStr, offsetStr := parts[4], parts[5] slice, err := dvid.NewSliceFromStrings(shapeStr, offsetStr, sizeStr, "_") if err != nil { server.BadRequest(w, r, err) return } if action == "post" { server.BadRequest(w, r, "DVID does not yet support POST of slices into multichannel data") return } else { if d.NumChannels == 0 || d.Data.Values == nil { server.BadRequest(w, r, "Cannot retrieve absent data '%d'. Please load data.", d.DataName()) return } values := d.Data.Values if len(values) <= int(channelNum) { server.BadRequest(w, r, "Must choose channel from 0 to %d", len(values)) return } stride := slice.Size().Value(0) * values.BytesPerElement() dataValues := dvid.DataValues{values[channelNum]} data := make([]uint8, int(slice.NumVoxels())) v := imageblk.NewVoxels(slice, dataValues, data, stride) channel := &Channel{ Voxels: v, channelNum: channelNum, } img, err := d.GetImage(ctx.VersionID(), channel.Voxels, nil) var formatStr string if len(parts) >= 7 { formatStr = parts[6] } //dvid.ElapsedTime(dvid.Normal, startTime, "%s %s upto image formatting", op, slice) err = dvid.WriteImageHttp(w, img.Get(), formatStr) if err != nil { server.BadRequest(w, r, err) return } } case 3: sizeStr, offsetStr := parts[4], parts[5] _, err := dvid.NewSubvolumeFromStrings(offsetStr, sizeStr, "_") if err != nil { server.BadRequest(w, r, err) return } if action == "get" { server.BadRequest(w, r, "DVID does not yet support GET of volume data") return } else { server.BadRequest(w, r, "DVID does not yet support POST of volume data") return } default: server.BadRequest(w, r, "DVID does not yet support nD volumes") return } timedLog.Infof("HTTP %s: %s", r.Method, dataShape) }
func (V3DRawMarshaler) UnmarshalV3DRaw(reader io.Reader) ([]*Channel, error) { magicString := make([]byte, 24) if n, err := reader.Read(magicString); n != 24 || err != nil { return nil, fmt.Errorf("error reading magic string in V3D Raw file: %v", err) } if string(magicString) != "raw_image_stack_by_hpeng" { return nil, fmt.Errorf("bad magic string in V3D Raw File: %s", string(magicString)) } endianType := make([]byte, 1, 1) if n, err := reader.Read(endianType); n != 1 || err != nil { return nil, fmt.Errorf("could not read endianness of V3D Raw file: %v", err) } var byteOrder binary.ByteOrder switch string(endianType) { case "L": byteOrder = binary.LittleEndian case "B": return nil, fmt.Errorf("cannot handle big endian byte order in V3D Raw File") default: return nil, fmt.Errorf("illegal byte order '%s' in V3D Raw File", endianType) } var dataType uint16 if err := binary.Read(reader, byteOrder, &dataType); err != nil { return nil, err } var bytesPerVoxel int32 switch dataType { case 1: bytesPerVoxel = 1 case 2: bytesPerVoxel = 2 default: return nil, fmt.Errorf("cannot handle V3D Raw File with data type %d", dataType) } var width, height, depth, numChannels uint32 if err := binary.Read(reader, byteOrder, &width); err != nil { return nil, fmt.Errorf("error reading width in V3D Raw File: %v", err) } if err := binary.Read(reader, byteOrder, &height); err != nil { return nil, fmt.Errorf("error reading height in V3D Raw File: %v", err) } if err := binary.Read(reader, byteOrder, &depth); err != nil { return nil, fmt.Errorf("error reading depth in V3D Raw File: %v", err) } if err := binary.Read(reader, byteOrder, &numChannels); err != nil { return nil, fmt.Errorf("error reading # channels in V3D Raw File: %v", err) } // Allocate the V3DRaw struct for the # channels totalBytes := int(bytesPerVoxel) * int(width*height*depth) size := dvid.Point3d{int32(width), int32(height), int32(depth)} volume := dvid.NewSubvolume(dvid.Point3d{0, 0, 0}, size) v3draw := make([]*Channel, numChannels, numChannels) var c int32 for c = 0; c < int32(numChannels); c++ { data := make([]uint8, totalBytes, totalBytes) var t dvid.DataType switch bytesPerVoxel { case 1: t = dvid.T_uint8 case 2: t = dvid.T_uint16 } values := dvid.DataValues{ { T: t, Label: fmt.Sprintf("channel%d", c), }, } v := imageblk.NewVoxels(volume, values, data, int32(width)*bytesPerVoxel) v3draw[c] = &Channel{ Voxels: v, channelNum: c + 1, } } // Read in the data for each channel for c = 0; c < int32(numChannels); c++ { if err := binary.Read(reader, byteOrder, v3draw[c].Data()); err != nil { return nil, fmt.Errorf("error reading data for channel %d: %v", c, err) } } return v3draw, nil }