Golang: How to convert an image.image to uint16 - go

I am trying to use the go-skeltrack library with some depth images I have (Not using freenect). For that I need to modify the provided example by replacing the kinect images by my own. For that I have to read an image and convert it later to an []uint16 variable. The code which I tried is:
file, err := os.Open("./images/4.png")
if err != nil {
fmt.Println("4.png file not found!")
os.Exit(1)
}
defer file.Close()
fileInfo, _ := file.Stat()
var size int64 = fileInfo.Size()
bytes := make([]byte, size)
// read file into bytes
buffer := bufio.NewReader(file)
_, err = buffer.Read(bytes)
integerImage := binary.BigEndian.Uint16(bytes)
onDepthFrame(integerImage)
Where onDepthFrame is a function which has the form
func onDepthFrame(depth []uint16).
But I am getting the following error while compiling:
./skeltrackOfflineImage.go:155: cannot use integerImage (type uint16) as type []uint16 in argument to onDepthFrame
Which of course refers to the fact that I generated a single integer instead of an array. I am quite confused about the way that Go data types conversion works. Please help!
Thanks in advance for your help.
Luis

binary.BigEndian.Uint16 converts two bytes (in a slice) to a 16-bit value using big endian byte order. If you want to convert bytes to a slice of uint16, you should use binary.Read:
// This reads 10 uint16s from file.
slice := make([]uint16, 10)
err := binary.Read(file, binary.BigEndian, slice)

It sounds like you're looking to get raw pixels. If that's the case, I don't recommend reading the file as binary directly. It means you would need to parse the file format yourself since image files contain more information than just the raw pixel values. There are already tools in the image package to deal with that.
This code should get you on the right track. It reads RGBA values, so it ends up with a 1D array of uint8's of length width * height * 4, since there are four values per pixel.
https://play.golang.org/p/WUgHQ3pRla
import (
"bufio"
"fmt"
"image"
"os"
// for decoding png files
_ "image/png"
)
// RGBA attempts to load an image from file and return the raw RGBA pixel values.
func RGBA(path string) ([]uint8, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
img, _, err := image.Decode(bufio.NewReader(file))
if err != nil {
return nil, err
}
switch trueim := img.(type) {
case *image.RGBA:
return trueim.Pix, nil
case *image.NRGBA:
return trueim.Pix, nil
}
return nil, fmt.Errorf("unhandled image format")
}
I'm not entirely sure where the uint16 values you need should come from, but presumably it's data per pixel, so the code should be very similar to this except the switch on trueim should likely check for something other than image.RGBA. Take a look at the other image types in https://golang.org/pkg/image

Related

How to read arbitrary amounts of data directly from a file in Go?

Without reading the contents of a file into memory, how can I read "x" bytes from the file so that I can specify what x is for every separate read operation?
I see that the Read method of various Readers takes a byte slice of a certain length and I can read from a file into that slice. But in that case the size of the slice is fixed, whereas what I would like to do, ideally, is something like:
func main() {
f, err := os.Open("./file.txt")
if err != nil {
panic(err)
}
someBytes := f.Read(2)
someMoreBytes := f.Read(4)
}
bytes.Buffer has a Next method which behaves very closely to what I would want, but it requires an existing buffer to work, whereas I'm hoping to read an arbitrary amount of bytes from a file without needing to read the whole thing into memory.
What is the best way to accomplish this?
Thank you for your time.
Use this function:
// readN reads and returns n bytes from the reader.
// On error, readN returns the partial bytes read and
// a non-nil error.
func readN(r io.Reader, n int) ([]byte, error) {
// Allocate buffer for result
b := make([]byte, n)
// ReadFull ensures buffer is filled or error is returned.
n, err := io.ReadFull(r, b)
return b[:n], err
}
Call like this:
someBytes, err := readN(f, 2)
if err != nil { /* handle error here */
someMoreBytes := readN(f, 4)
if err != nil { /* handle error here */
you can do something like this:
f, err := os.Open("/tmp/dat")
check(err)
b1 := make([]byte, 5)
n1, err := f.Read(b1)
check(err)
fmt.Printf("%d bytes: %s\n", n1, string(b1[:n1]))
for more reading please check site.

image.Decode() unknown format

I have an image that is stored in the filesystem. This file should be decoded to an image and then resized. I know how to resize it, but I can't decode the image. Whatever image path/image I insert in program, it results: image: unknown format.
I've already read all sites about this problem, but none of them did help me. This code represents my simplified program logic (I'd like to understand why this error occurs). In advance, thanks for your attention!
import (
"bufio"
"fmt"
"image"
"image/png"
_ "image/jpeg"
_ "image/png"
"log"
"os"
)
func main() {
file, err := os.Open(`D:\photos\img.png`)
if err != nil {
log.Fatal(err)
}
defer file.Close()
config, format, err := image.DecodeConfig(bufio.NewReader(file))
if err != nil {
log.Fatal(err)
}
fmt.Println(format, config.Height, config.Width, config.ColorModel)
decodedImg, format, err := image.Decode(bufio.NewReader(file)) // ERROR HERE
if err != nil {
log.Fatal(err)
}
fmt.Println(format,"decode")
outputFile, err := os.Create(`D:\photos\image.png`)
if err != nil {
log.Fatal(err)
}
defer outputFile.Close()
png.Encode(outputFile, decodedImg)
}
Output:
png 512 512 &{0x4ae340}
2020/07/11 09:37:10 image: unknown format
Both image.Decode and image.DecodeConfig consume the bytes from the passed-in io.Reader.
This means that after DecodeConfig is done, the position in the file is after the bytes already read. image.Decode then comes along with the same underlying file, expects to find the image header, but doesn't.
bufio.NewReader does not reset the position to the beginning of the file (because it can't, it only knows the underlying object is an io.Reader).
You have a few solutions (in order or personal preference):
seek back to the beginning of the file before calling image.Decode. eg: newOffset, err := file.Seek(0, 0)
don't use image.DecodeConfig (this might not be an option)
read the file into a []byte and use a bytes.Buffer
open the file again (not particularly efficient)
As a side note, you don't need to wrap the os.File object in a bufio.Reader, it already implements the io.Reader interface.

How can I convert a structure with a byte slice data type to bytes?

I need to send struct data with byte slice data type during socket communication.
type A struct {
header []byte
body []byte
}
So I wrote the following source code to convert the structure to bytes.
var a A
a.header = byte slice data...
a.body = byte slice data...
buf := new(bytes.Buffer)
binary.Write(buf, binary.BigEndian, a)
However, I get an error with the binary.Write function showing the following error:
binary.Write: invalid type main.A
I have found that fixed arrays solve the problem. But since the length of the data is constantly changing, I have to use a slice rather than a fixed array.
Is there a way to solve this problem?
If you write a variable length of byte slice, the other end would not know how many bytes it needs to read. You have to communicate the length too.
So one way to send a byte slice is to first write the length (number of bytes) using a fixed-size type, e.g. int32 or int64. Then simply write the byte slice.
For example:
var w io.Writer // This represents your connection
var a A
if err := binary.Write(w, binary.LittleEndian, int32(len(a.header))); err != nil {
// Handle error
}
if _, err := w.Write(a.header); err != nil {
// Handle error
}
You may use the same logic to send a.body too.
On the other end, this is how you could read it:
var r io.Reader // This represents your connection
var a A
var size int32
if err := binary.Read(r, binary.LittleEndian, &size); err != nil {
// Handle error
}
a.header = make([]byte, size)
if _, err := io.ReadFull(r, a.header); err != nil {
// Handle error
}
Try a working example on the Go Playground.
If you have to transfer more complex structs, consider using the encoding/gob which handles sending slices with ease. For an example and some insights, see Efficient Go serialization of struct to disk.

Convert an image to grayscale in Go

I'm trying to convert an image to grayscale using Go.
I've found the below code, however, I'm struggling to understand it.
It would be extremely helpful if you could explain what each function is doing and where to define the incoming and outgoing file.
package main
import (
"image"
_ "image/jpeg" // Register JPEG format
"image/png" // Register PNG format
"image/color"
"log"
"os"
)
// Converted implements image.Image, so you can
// pretend that it is the converted image.
type Converted struct {
Img image.Image
Mod color.Model
}
// We return the new color model...
func (c *Converted) ColorModel() color.Model{
return c.Mod
}
// ... but the original bounds
func (c *Converted) Bounds() image.Rectangle{
return c.Img.Bounds()
}
// At forwards the call to the original image and
// then asks the color model to convert it.
func (c *Converted) At(x, y int) color.Color{
return c.Mod.Convert(c.Img.At(x,y))
}
func main() {
if len(os.Args) != 3 { log.Fatalln("Needs two arguments")}
infile, err := os.Open(os.Args[1])
if err != nil {
log.Fatalln(err)
}
defer infile.Close()
img, _, err := image.Decode(infile)
if err != nil {
log.Fatalln(err)
}
// Since Converted implements image, this is now a grayscale image
gr := &Converted{img, color.GrayModel}
// Or do something like this to convert it into a black and
// white image.
// bw := []color.Color{color.Black,color.White}
// gr := &Converted{img, color.Palette(bw)}
outfile, err := os.Create(os.Args[2])
if err != nil {
log.Fatalln(err)
}
defer outfile.Close()
png.Encode(outfile,gr)
}
I'm quite new to Go so any suggestions or help would be appreciated.
So as Atomic_alarm pointed out, https://maxhalford.github.io/blog/halftoning-1/ explains how to do this succinctly.
But you're question, if I understand correctly, is about the file opening and creation?
The first step is to use the image package to Decode the opened file into an image.Image struct:
infile, err := os.Open("fullcolor.png")
if err != nil {
return nil, err
}
defer infile.Close()
img, _, err := image.Decode(infile) // img -> image.Image
if err != nil {
return nil, err
}
With this Go image.Image struct, you can convert it to a grayscaled image, image.Gray and then, finally, write or encode the image onto an outgoing file on the disk:
outfile, _ := os.Create("grayscaled.png")
defer outfile.Close()
png.Encode(outfile, grayscaledImage) // grayscaledImage -> image.Gray
Inbetween the infile opening and outfile creating, you have to, of course, convert the image to grayscale. Again, try the link above, and you'll find this function, which takes an image.Image and returns a pointer to a image.Gray:
func rgbaToGray(img image.Image) *image.Gray {
var (
bounds = img.Bounds()
gray = image.NewGray(bounds)
)
for x := 0; x < bounds.Max.X; x++ {
for y := 0; y < bounds.Max.Y; y++ {
var rgba = img.At(x, y)
gray.Set(x, y, rgba)
}
}
return gray
}
Concerning the code you provided (and your comment), you were opening a file with os.Args[1], and creating the file os.Args[2]. os.Args is a slice of arguments passed when running the program, 0 will always be the program itself (main), and whatever follows will with 1, 2, etc. The docs states:
Args hold the command-line arguments, starting with the program name.
var Args []string
so you would run your code above like this:
$ go run main.go infile.png outfile.png
infile.png must to be a file on disk (inside the directory you are running the code from, or the complete path to file).
What I have provide above doesn't use os.Args but rather hard codes the file names into the program.

Golang Converting Image magick object to []byte

I am using the following code which fetch the object from Amazon s3 and after performing resizing and cropping. I want to store it on s3. But the problem is i am not able convert the mw (Image maigck object) to byte array. Which will be used for storing it on s3. Moreover in current method it uses jpeg.Encode. What if the image in .png or .gif format. How will we convert it to []byte?
Could you please also tell me how to evenly crop an image just passing the aspect ratio not cropping coordinates. imgStream.Crop((int)originalWidth, ((int)(originalWidth / masterAspectRatio)), Gravity.Center) like we do it in .net. Reason i am asking is there is no method in library which provides this flexibility.
s3Client := s3.New(session.New(), &aws.Config{Region: aws.String(region)})
params := &s3.GetObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(keyName),
}
out, err := s3Client.GetObject(params)
if err != nil {
log.Fatal(err)
}
img, err := ioutil.ReadAll(out.Body)
if err != nil {
log.Fatal(err)
}
mw := imagick.NewMagickWand()
err = mw.ReadImageBlob(img)
if err != nil {
log.Fatal(err)
}
//Perform resizing and cropping on mw object
buf := new(bytes.Buffer)
err = jpeg.Encode(buf, mw, nil)
sendmw_s3 := buf.Bytes()
paramsPut := &s3.PutObjectInput{
Bucket: aws.String(masterBucketName),
Key: aws.String(keyName),
Body: bytes.NewReader(sendmw_s3),
}
resp, err := s3Client.PutObject(paramsPut)
if err != nil {
log.Fatal(err)
}
Error :
cannot use mw (type *imagick.MagickWand) as type image.Image in argument to jpeg.Encode:
*imagick.MagickWand does not implement image.Image (missing At method)
You need to use the func (mw *MagickWand) GetImageBlob() []byte function.
It returns a slice of bytes containing a complete encoded image for the current file format (JPEG, gif, PNG...).
The returned data can therefore be saved to disk, or sent to s3 as-is.
See https://gowalker.org/github.com/gographics/imagick/imagick#MagickWand_GetImageBlob for the documentation.
This question is actually two questions, and #SirDarius answered one of them, by suggesting the use of GetImageBlob(). You can also use SetImageFormat() to change the image format before generating the blob.
For the part about the crop, I am sure there are a bunch of ways to do this with ImageMagick. The way I have done it, to achieve a center crop is to first transform the image so that the smaller dimension fits into my desired target resolution. And then to crop away the parts that overflow.
// Create a new image where smallest dimension is fit
// and the rest overflows the dimensions
size := fmt.Sprintf("%dx%d^+0+0", w, h)
tx := wand.TransformImage("", size)
// Center Crop away the extra parts of the image, to perform
tx.SetImageGravity(imagick.GRAVITY_CENTER)
offsetX := -(int(w) - int(tx.GetImageWidth())) / 2
offsetY := -(int(h) - int(tx.GetImageHeight())) / 2
err := tx.ExtentImage(w, h, offsetX, offsetY)
...

Resources