Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSDK-2077 Make sure custom depth type is big endian encoded #1984

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .artifact/tree.json
Original file line number Diff line number Diff line change
Expand Up @@ -3881,7 +3881,7 @@
"size": 567
},
"fakeDM.vnd.viam.dep": {
"hash": "4a7dca803d353064c65886fae49c823a",
"hash": "80f3125fe6b7244ea0ca8ab7a27fa866",
"size": 424
},
"go_encoded_image.png": {
Expand Down
32 changes: 20 additions & 12 deletions rimage/depth_map_raw.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ import (
const MagicNumIntVersionX = 6363110499870197078

// MagicNumIntViamType is the magic number (as an int) for the custom Viam depth type.
// magic number for ViamCustomType is uint64([]byte("DEPTHMAP")), Little Endian.
const MagicNumIntViamType = 5782988369567958340
// magic number for ViamCustomType is uint64([]byte("DEPTHMAP")), Big Endian.
const MagicNumIntViamType = 4919426490892632400

// MagicNumIntViamTypeLittleEndian is "PAMHTPED" for the ReadDepthMap function which uses LittleEndian to read.
const MagicNumIntViamTypeLittleEndian = 5782988369567958340

func _readNext(r io.Reader) (int64, error) {
data := make([]byte, 8)
Expand Down Expand Up @@ -63,7 +66,7 @@ func ReadDepthMap(r io.Reader) (*DepthMap, error) {
switch firstBytes {
case MagicNumIntVersionX: // magic number for VERSIONX
return readDepthMapVersionX(r)
case MagicNumIntViamType: // magic number for ViamCustomType is int64([]byte("DEPTHMAP"))
case MagicNumIntViamTypeLittleEndian: // magic number for ViamCustomType PAMHTPED (LittleEndian DEPTHMAP)
return readDepthMapViam(r)
default:
return readDepthMapRaw(r, firstBytes)
Expand All @@ -88,20 +91,25 @@ func readDepthMapRaw(ff io.Reader, firstBytes int64) (*DepthMap, error) {
func readDepthMapViam(ff io.Reader) (*DepthMap, error) {
f := bufio.NewReader(ff)
dm := &DepthMap{}
data := make([]byte, 8)

rawWidth, err := _readNext(f)
Copy link
Member Author

@bhaney bhaney Mar 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_readNext is coded to read in LittleEndian byte order, so for backwards compatbility with .dat and .dat.gz files, we can keep it. We replace the Viam Depth type to read in BigEndian order

_, err := f.Read(data)
if err != nil {
return nil, errors.Wrapf(err, "could not read vnd.viam.dep width")
}
rawWidth := binary.BigEndian.Uint64(data)
dm.width = int(rawWidth)
rawHeight, err := _readNext(f)

_, err = f.Read(data)
if err != nil {
return nil, errors.Wrapf(err, "could not read vnd.viam.dep height")
}
rawHeight := binary.BigEndian.Uint64(data)
dm.height = int(rawHeight)

// dump the rest of the bytes in a depth slice
datSlice := make([]Depth, dm.height*dm.width)
err = binary.Read(f, binary.LittleEndian, &datSlice)
err = binary.Read(f, binary.BigEndian, &datSlice)
if err != nil {
return nil, errors.Wrapf(err, "could not read vnd.viam.dep data slice")
}
Expand Down Expand Up @@ -315,39 +323,39 @@ func WriteViamDepthMapTo(img image.Image, out io.Writer) (int64, error) {
width := img.Bounds().Dx()
height := img.Bounds().Dy()

binary.LittleEndian.PutUint64(buf, uint64(MagicNumIntViamType))
binary.BigEndian.PutUint64(buf, uint64(MagicNumIntViamType))
n, err := out.Write(buf)
totalN += int64(n)
if err != nil {
return totalN, err
}
binary.LittleEndian.PutUint64(buf, uint64(width))
binary.BigEndian.PutUint64(buf, uint64(width))
n, err = out.Write(buf)
totalN += int64(n)
if err != nil {
return totalN, err
}

binary.LittleEndian.PutUint64(buf, uint64(height))
binary.BigEndian.PutUint64(buf, uint64(height))
n, err = out.Write(buf)
totalN += int64(n)
if err != nil {
return totalN, err
}
switch dm := img.(type) {
case *DepthMap:
err = binary.Write(out, binary.LittleEndian, dm.data) // uint16 data
err = binary.Write(out, binary.BigEndian, dm.data)
if err != nil {
return totalN, err
}
totalN += int64(len(dm.data) * 2)
totalN += int64(len(dm.data) * 2) // uint16 data
case *image.Gray16:
grayBuf := make([]byte, 2)
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
i := dm.PixOffset(x, y)
z := uint16(dm.Pix[i+0])<<8 | uint16(dm.Pix[i+1])
binary.LittleEndian.PutUint16(grayBuf, z)
binary.BigEndian.PutUint16(grayBuf, z)
n, err = out.Write(grayBuf)
totalN += int64(n)
if err != nil {
Expand Down
5 changes: 0 additions & 5 deletions rimage/depth_map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,6 @@ func TestViamDepthMap(t *testing.T) {
func TestDepthMapEncoding(t *testing.T) {
m, err := NewDepthMapFromFile(context.Background(), artifact.MustPath("rimage/fakeDM.vnd.viam.dep"))
test.That(t, err, test.ShouldBeNil)

// Test values at points of DepthMap
// This example DepthMap (fakeDM) was made such that Depth(x,y) = x*y
test.That(t, m.Width(), test.ShouldEqual, 20)
Expand All @@ -385,10 +384,6 @@ func TestDepthMapEncoding(t *testing.T) {
test.That(t, testPt2, test.ShouldEqual, 60)

// Save DepthMap BYTES to a file
buf := bytes.Buffer{}
err = m.WriteToBuf(&buf)
test.That(t, err, test.ShouldBeNil)
test.That(t, buf.Bytes(), test.ShouldNotBeNil)
Comment on lines -388 to -391
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WriteToBuf writes a grayscale PNG

outDir := testutils.TempDirT(t, "", "rimage")
saveTo := outDir + "/grayboard_bytes.vnd.viam.dep"
err = WriteRawDepthMapToFile(m, saveTo)
Expand Down
20 changes: 7 additions & 13 deletions rimage/image_file.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package rimage

import (
"bufio"
"bytes"
"context"
"encoding/binary"
Expand Down Expand Up @@ -94,23 +93,18 @@ func init() {
},
func(r io.Reader) (image.Config, error) {
// Using Gray 16 as underlying color model for depth
f := r.(*bufio.Reader)
firstBytes, err := _readNext(r)
if err != nil || firstBytes != MagicNumIntViamType {
return image.Config{}, errors.Wrap(err, "first image bytes do not match expected magic number")
}
rawWidth, err := _readNext(f)
if err != nil {
return image.Config{}, err
}
rawHeight, err := _readNext(f)
imgBytes := make([]byte, RawDepthHeaderLength)
_, err := io.ReadFull(r, imgBytes)
if err != nil {
return image.Config{}, err
}
header := imgBytes[:RawDepthHeaderLength]
width := binary.BigEndian.Uint64(header[8:16])
height := binary.BigEndian.Uint64(header[16:24])
return image.Config{
ColorModel: color.Gray16Model,
Width: int(rawWidth),
Height: int(rawHeight),
Width: int(width),
Height: int(height),
}, nil
},
)
Expand Down
53 changes: 53 additions & 0 deletions rimage/image_file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,22 @@ func TestRawRGBAEncodingDecoding(t *testing.T) {

encodedImgBytes, err := EncodeImage(context.Background(), img, utils.MimeTypeRawRGBA)
test.That(t, err, test.ShouldBeNil)
reader := bytes.NewReader(encodedImgBytes)

conf, header, err := image.DecodeConfig(reader)
test.That(t, err, test.ShouldBeNil)
test.That(t, header, test.ShouldEqual, "vnd.viam.rgba")
test.That(t, conf.Width, test.ShouldEqual, img.Bounds().Dx())
test.That(t, conf.Height, test.ShouldEqual, img.Bounds().Dy())

// decode with image package
reader = bytes.NewReader(encodedImgBytes)
imgDecoded, header, err := image.Decode(reader)
test.That(t, err, test.ShouldBeNil)
test.That(t, header, test.ShouldEqual, "vnd.viam.rgba")
test.That(t, imgDecoded.Bounds(), test.ShouldResemble, img.Bounds())
test.That(t, imgDecoded.At(3, 6), test.ShouldResemble, img.At(3, 6))
test.That(t, imgDecoded.At(1, 3), test.ShouldResemble, img.At(1, 3))

decodedImg, err := DecodeImage(context.Background(), encodedImgBytes, utils.MimeTypeRawRGBA)
test.That(t, err, test.ShouldBeNil)
Expand All @@ -96,3 +112,40 @@ func TestRawRGBAEncodingDecoding(t *testing.T) {
test.That(t, imgB, test.ShouldResemble, decodedImgB)
test.That(t, imgA, test.ShouldResemble, decodedImgA)
}

func TestRawDepthEncodingDecoding(t *testing.T) {
img := NewEmptyDepthMap(4, 8)
for x := 0; x < 4; x++ {
for y := 0; y < 8; y++ {
img.Set(x, y, Depth(x*y))
}
}
encodedImgBytes, err := EncodeImage(context.Background(), img, utils.MimeTypeRawDepth)
test.That(t, err, test.ShouldBeNil)
reader := bytes.NewReader(encodedImgBytes)

// decode Header
conf, header, err := image.DecodeConfig(reader)
test.That(t, err, test.ShouldBeNil)
test.That(t, header, test.ShouldEqual, "vnd.viam.dep")
test.That(t, conf.Width, test.ShouldEqual, img.Bounds().Dx())
test.That(t, conf.Height, test.ShouldEqual, img.Bounds().Dy())

// decode with image package
reader = bytes.NewReader(encodedImgBytes)
imgDecoded, header, err := image.Decode(reader)
test.That(t, err, test.ShouldBeNil)
test.That(t, header, test.ShouldEqual, "vnd.viam.dep")
test.That(t, imgDecoded.Bounds(), test.ShouldResemble, img.Bounds())
test.That(t, imgDecoded.At(2, 3), test.ShouldResemble, img.At(2, 3))
test.That(t, imgDecoded.At(1, 0), test.ShouldResemble, img.At(1, 0))

// decode with rimage package
decodedImg, err := DecodeImage(context.Background(), encodedImgBytes, utils.MimeTypeRawDepth)
test.That(t, err, test.ShouldBeNil)
test.That(t, decodedImg.Bounds(), test.ShouldResemble, img.Bounds())
decodedDm, ok := decodedImg.(*DepthMap)
test.That(t, ok, test.ShouldBeTrue)
test.That(t, decodedDm.GetDepth(2, 3), test.ShouldEqual, img.GetDepth(2, 3))
test.That(t, decodedDm.GetDepth(1, 0), test.ShouldEqual, img.GetDepth(1, 0))
}