decoding images of float32 pixels

351 views
Skip to first unread message

Seb Binet

unread,
Apr 21, 2016, 10:29:30 AM4/21/16
to golang-nuts
hi there,

I am trying to read and decode astrophysics images coming out of a telescope.
the image payload is stored as a big-endian encoded slice of float32.

the python doc only vaguely defines that format:
(search for "32-bit floating point pixels")

re-engineering the bytes output of an f32-pixels image converted to rgba via the python tools, I came up with this:

 floats := make([]float32, size)
 err = binary.Read(raw, binary.BigEndian, floats)
 pix := make([]byte, 4*size)
 for i,v := range floats {
   ii := i*4
   pix[ii+0] = byte(v)
   pix[ii+1] = byte(v)
   pix[ii+2] = byte(v)
   pix[ii+3] = 255
 }
 img := image.NewNRGBA(rect)
 img.Pix = pix

but it seems a bit strange to me (and the resulting image looks slightly different, perhaps due to some saturation my code doesn't handle properly?)

has anyone encountered this kind of float32-pixels ?
(and, bonus points, already implemented an image.Image for this?)

-s

Andy Balholm

unread,
Apr 21, 2016, 12:07:20 PM4/21/16
to Seb Binet, golang-nuts
First, why the image looks different: I suspect you need to apply some sort of gamma correction.

Second, how to implement the Image interface with 32-bit float storage: I would make a float32 that implements the Color interface.

type float32Gray float32

const gamma = 1 / 2.2
const scale = 255

func (c float32Gray) RGBA() (r, g, b, a uint32) {
f := math.Pow(float64(c) / scale, gamma)
if f > 1 {
f = 1
}
i := uint32(f * 0xffff)
return i, i, i, 0xffff
}

You will need to play around with the values of gamma and scale to get the right results. Scale should be approximately the value of the brightest pixel in the image. (Your code snippet seemed to assume a scale of 255.) The value of gamma that I’m using assumes that the input values are linear, and that we want the output to be displayed as an sRGB image.

Then it should be pretty simple to create an implementation of Image that returns these pixels.

Andy

Seb Binet

unread,
Apr 21, 2016, 1:26:49 PM4/21/16
to Andy Balholm, golang-nuts
Andy,

thanks.

I had indeed a normalization bug in my initial code:
   pix[ii+0] = byte(v)
   pix[ii+1] = byte(v)
   pix[ii+2] = byte(v)

should have been:
   vv := byte(v)
   if v > 255 { vv = 255 }
   pix[ii+0] = vv
   pix[ii+1] = vv
   pix[ii+2] = vv

and I get the same output than with this f32Image implementation:


I assume that for a f64Image, I would have to define a f64Gray as:

func (c f64Gray) RGBA() (r, g, b, a uint32) {
f := math.Pow(float64(c)/scalef64, gammaf64)
if f > 1 {
f = 1
}
i := uint32(f * 0xffffffff)
return i, i, i, 0xffff
}

right ?

also, is it safe to assume that, to be able to handle any image (f32- or f64-encoded) thrown at my program, I would first to detect the scale, scanning all the f32 or f64 data slice for the min/max and then adjust scalef32 (resp. scalef64) accordingly ?
my initial 255 value was really drawn out of thin air...

-s

Dan Kortschak

unread,
Apr 21, 2016, 9:25:49 PM4/21/16
to Seb Binet, Andy Balholm, golang-nuts
It looks like this is similar (the same?) as TIFF float/double encoding.

I don't think the scale should change for double encoded images.

Nigel Tao

unread,
Apr 21, 2016, 9:34:26 PM4/21/16
to Seb Binet, golang-nuts
On Fri, Apr 22, 2016 at 12:29 AM, Seb Binet <seb....@gmail.com> wrote:
> for i,v := range floats {
> ii := i*4
> pix[ii+0] = byte(v)
> pix[ii+1] = byte(v)
> pix[ii+2] = byte(v)
> pix[ii+3] = 255
> }
> img := image.NewNRGBA(rect)
> img.Pix = pix

A couple of tangential points:

You might be better off with an image.Gray instead of an image.NRGBA.

You might be better off with a struct literal instead of calling
image.NewFoo, as the NewFoo function will allocate a pix buffer that
(in this case) is nothing but garbage for collecting.

img := &image.Gray{
Pix: pix,
Stride, rect.Dy(),
Rect: rect,
}

chai2010

unread,
Apr 22, 2016, 11:18:11 AM4/22/16
to Seb Binet, golang-nuts
I also need to read float32 image for DEM(Digital Elevation Model) data form ".dem" or float32 TIFF.
I defined a Memory Picture image format for these works:


For float32 data type, `MemPColor` use `uint16(float32(v))` rule to convert the value the `color.Gray16`.
And you can read the float32 through `PixSilce(memp.Pix()[off:]).Float32s()[...]`.

If you need read float32 TIFF, you can try https://godoc.org/github.com/chai2010/gdal pkg.


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

Seb Binet

unread,
Apr 22, 2016, 11:21:25 AM4/22/16
to Dan Kortschak, Andy Balholm, golang-nuts
On Fri, Apr 22, 2016 at 3:25 AM, Dan Kortschak <dan.ko...@adelaide.edu.au> wrote:
It looks like this is similar (the same?) as TIFF float/double encoding.

I don't think the scale should change for double encoded images.

thanks, TIFF-6's specs are now my bedtime reading...

-s

Seb Binet

unread,
Apr 22, 2016, 11:22:06 AM4/22/16
to Nigel Tao, golang-nuts
yes, thanks.

Seb Binet

unread,
Apr 22, 2016, 11:22:47 AM4/22/16
to chai2010, golang-nuts
On Fri, Apr 22, 2016 at 5:17 PM, chai2010 <chais...@gmail.com> wrote:
I also need to read float32 image for DEM(Digital Elevation Model) data form ".dem" or float32 TIFF.
I defined a Memory Picture image format for these works:


For float32 data type, `MemPColor` use `uint16(float32(v))` rule to convert the value the `color.Gray16`.
And you can read the float32 through `PixSilce(memp.Pix()[off:]).Float32s()[...]`.

If you need read float32 TIFF, you can try https://godoc.org/github.com/chai2010/gdal pkg.

ok, thanks.

(BTW, any reason why this is spelled Silce and not Slice?  https://godoc.org/github.com/chai2010/image#PixSilce)

-s

chai2010

unread,
Apr 22, 2016, 11:26:35 AM4/22/16
to Seb Binet, golang-nuts
It is a typo :)

Seb Binet

unread,
May 26, 2016, 12:36:11 PM5/26/16
to golang-nuts
fyi, I put the code I needed in there:

thanks all again for your ideas and suggestions.

-s
Reply all
Reply to author
Forward
0 new messages