func NewRaytracer(cfg Config) *Raytracer { rect := cfg.Images[0].Bounds() numCPU := 1 if cfg.MultiThreaded { numCPU = runtime.NumCPU() for numCPU%rect.Max.Y != 0 { numCPU++ } } rt := &Raytracer{ cfg: cfg, frame: uint32(cfg.FrameSeed), clear: color.RGBA{0, 0, 0, 255}, numThreads: numCPU, work: make(chan rtJob, numCPU*2), } if cfg.Depth { rect := cfg.Images[0].Bounds() rt.depth = [2]*image.Gray16{image.NewGray16(rect), image.NewGray16(rect)} } for i := 0; i < numCPU; i++ { go rt.workerLoop() } return rt }
func to_img(brot *[size][size]uint, max uint) { gray := image.NewGray16(image.Rect(0, 0, size, size)) norm_gray := image.NewGray16(image.Rect(0, 0, size, size)) for x := 0; x < size; x++ { for y := 0; y < size; y++ { pix := brot[x][y] norm := float64(brot[x][y]*4) / float64(max) * 65534 if norm > 65534 { norm = 65534 } if pix > 65534 { pix = 65534 } gray.SetGray16( x, y, color.Gray16{uint16(pix)}) norm_gray.SetGray16( x, y, color.Gray16{uint16(norm)}) } } w, _ := os.OpenFile("./brot.png", os.O_CREATE|os.O_WRONLY, 0666) png.Encode(w, gray) n, _ := os.OpenFile("./brot-norm.png", os.O_CREATE|os.O_WRONLY, 0666) png.Encode(n, norm_gray) }
// NewDrawableSize returns a new draw.Image with the same type as p and the given bounds. // If p is not a draw.Image, another type is used. func NewDrawableSize(p image.Image, r image.Rectangle) draw.Image { switch p := p.(type) { case *image.RGBA: return image.NewRGBA(r) case *image.RGBA64: return image.NewRGBA64(r) case *image.NRGBA: return image.NewNRGBA(r) case *image.NRGBA64: return image.NewNRGBA64(r) case *image.Alpha: return image.NewAlpha(r) case *image.Alpha16: return image.NewAlpha16(r) case *image.Gray: return image.NewGray(r) case *image.Gray16: return image.NewGray16(r) case *image.Paletted: pl := make(color.Palette, len(p.Palette)) copy(pl, p.Palette) return image.NewPaletted(r, pl) case *image.CMYK: return image.NewCMYK(r) default: return image.NewRGBA(r) } }
func NewImageOfTypeRect(src image.Image, bounds image.Rectangle) image.Image { switch i := src.(type) { case *image.Alpha: return image.NewAlpha(bounds) case *image.Alpha16: return image.NewAlpha16(bounds) case *image.Gray: return image.NewGray(bounds) case *image.Gray16: return image.NewGray16(bounds) case *image.NRGBA: return image.NewNRGBA(bounds) case *image.NRGBA64: return image.NewNRGBA64(bounds) case *image.Paletted: return image.NewPaletted(bounds, i.Palette) case *image.RGBA: return image.NewRGBA(bounds) case *image.RGBA64: return image.NewRGBA64(bounds) case *image.YCbCr: return image.NewYCbCr(bounds, i.SubsampleRatio) } panic("Unknown image type") }
func Draw(f Function, re_from, re_to, im_from, im_to float64, pix_size float64) image.Image { w := re_to - re_from h := im_to - im_from if w < 0 || h < 0 { panic("negative width or height") } if pix_size < 0 { panic("negative pixel size") } c := coords{pix_size, complex(re_from, im_from)} resx := int(w / pix_size) resy := int(h / pix_size) m := image.NewGray16(image.Rect(0, 0, resx, resy)) bounds := m.Bounds() for y := bounds.Min.Y; y < bounds.Max.Y; y++ { for x := bounds.Min.X; x < bounds.Max.X; x++ { z := c.At(x, y) o := Orbit(f, z, 2, 500) if o < 0 { m.Set(x, y, color.Black) } else { m.Set(x, y, color.Gray16{uint16(o * 0x10000 / 32)}) } } } return m }
// Return an image of the grid, with black blocks for true items and // white blocks for false items, with the given block size and margin. func (g *BitGrid) ImageWithMargin(blockSize, margin int) image.Image { width := blockSize * (2*margin + g.Width()) height := blockSize * (2*margin + g.Height()) i := image.NewGray16(image.Rect(0, 0, width, height)) for y := 0; y < blockSize*margin; y++ { for x := 0; x < width; x++ { i.Set(x, y, color.White) i.Set(x, height-1-y, color.White) } } for y := blockSize * margin; y < height-blockSize*margin; y++ { for x := 0; x < blockSize*margin; x++ { i.Set(x, y, color.White) i.Set(width-1-x, y, color.White) } } for y, w, h := 0, g.Width(), g.Height(); y < h; y++ { for x := 0; x < w; x++ { x0 := blockSize * (x + margin) y0 := blockSize * (y + margin) c := color.White if g.Get(x, y) { c = color.Black } for dy := 0; dy < blockSize; dy++ { for dx := 0; dx < blockSize; dx++ { i.Set(x0+dx, y0+dy, c) } } } } return i }
func (u *UGM) WriteToFile(path string, img image.Image) { // create in memory image based on ICM results matrix newImg := image.NewGray16(img.Bounds()) for x := 0; x < u.X(); x++ { for y := 0; y < u.Y(); y++ { if u.Node(x, y).X() == -1 { newImg.SetGray16(x, y, color.Black) } else { newImg.SetGray16(x, y, color.White) } } } // create/overwrite file to write to imgFile, err := os.Create(path) if err != nil { fmt.Printf("%v", err) os.Exit(1) } defer imgFile.Close() // close when exiting.. // write png to file if err := png.Encode(imgFile, newImg); err != nil { fmt.Println(err) os.Exit(1) } }
func EdgesGray16(radius int, img Channel) *image.Gray16 { bounds := img.Bounds() edgeImage := image.NewGray16(bounds) if radius < 1 { return edgeImage } // Compute the horizontal and vertical averages. hGA := RowAverageGray16(radius, img) vGA := ColumnAverageGray16(radius, img) QuickRP( AllPointsRP( func(pt image.Point) { e := float64(hGA.Gray16At(pt.X, pt.Y).Y) w := float64(hGA.Gray16At(pt.X-radius+1, pt.Y).Y) n := float64(vGA.Gray16At(pt.X, pt.Y).Y) s := float64(vGA.Gray16At(pt.X, pt.Y-radius+1).Y) edgeImage.Set(pt.X, pt.Y, color.Gray16{ Y: uint16(math.Max(math.Abs(e-w), math.Abs(s-n))), //uint16((math.Abs(e-w) + math.Abs(s-n)) / 2.0), }, ) }, ), )(bounds) return edgeImage }
//BackProjectGray computes back projection of img // in Gray16 by performing an addition // of backprojection by line. // 16Gray avoids white noise. func BackProjectGray(img image.Gray) (*image.Gray16, error) { size := img.Bounds().Size() width := size.Y nbProj := size.X step := 180.0 / float64(nbProj) out := image.NewGray16(image.Rect(0, 0, width, width)) for X := 0; X < nbProj; X++ { //Extract a 1D-projection (one row Y of sinogram) line := img.SubImage(image.Rect(X, 0, X+1, width)).(*image.Gray) // 3- Do the backprojection and rotate accordingly wideLine := resize.Resize(uint(width), uint(width), line, resize.Lanczos3).(*image.Gray) θ := manipulator.Rad(float64(X)*step) + math.Pi/2 rotatedWideLine := image.NewGray(image.Rect(0, 0, width, width)) err := graphics.Rotate(rotatedWideLine, wideLine, &graphics.RotateOptions{Angle: θ}) if err != nil { return out, err } // 4- Add the rotated backprojection in the output image for x := 0; x < width; x++ { for y := 0; y < width; y++ { point := uint16(out.At(x, y).(color.Gray16).Y) + uint16(rotatedWideLine.At(x, y).(color.Gray).Y) out.Set(x, y, color.Gray16{uint16(point)}) } } } return out, nil }
func createRandomImage(maxPaletteSize int) image.Image { r := image.Rectangle{Min: image.Point{0, 0}, Max: image.Point{gen.Rand(32) + 1, gen.Rand(32) + 1}} var img Image switch gen.Rand(10) { case 0: img = image.NewAlpha(r) case 1: img = image.NewAlpha16(r) case 2: img = image.NewCMYK(r) case 3: img = image.NewGray(r) case 4: img = image.NewGray16(r) case 5: img = image.NewNRGBA(r) case 6: img = image.NewNRGBA64(r) case 7: img = image.NewPaletted(r, randPalette(maxPaletteSize)) case 8: img = image.NewRGBA(r) case 9: img = image.NewRGBA64(r) default: panic("bad") } fill := gen.Rand(19) var palette []color.Color if fill == 17 { palette = randPalette(maxPaletteSize) } for y := 0; y < r.Max.Y; y++ { for x := 0; x < r.Max.X; x++ { switch { case fill <= 15: img.Set(x, y, color.RGBA64{ ^uint16(0) * uint16((fill>>0)&1), ^uint16(0) * uint16((fill>>1)&1), ^uint16(0) * uint16((fill>>2)&1), ^uint16(0) * uint16((fill>>3)&1), }) case fill == 16: img.Set(x, y, randColor()) case fill == 17: img.Set(x, y, palette[gen.Rand(len(palette))]) case fill == 18: if gen.Rand(3) != 0 { img.Set(x, y, color.RGBA64{}) } else { img.Set(x, y, randColor()) } default: panic("bad") } } } return img.(image.Image) }
func setup() { w, h := termbox.Size() board := image.NewGray16(image.Rect(0, 0, w, h)) draw.Draw(board, board.Bounds(), &image.Uniform{color.White}, image.ZP, draw.Src) ant = &Ant{X: w / 2, Y: h / 2, W: w, H: h, D: direction, B: board} }
// ConvertToGray16 returns an *image.Gray16 instance by asserting the given // ImageReader has that type or, if it does not, using Copy to concurrently // set the color.Color values of a new *image.Gray16 instance with the same // bounds. func ConvertToGray16(src ImageReader) *image.Gray16 { if dst, ok := src.(*image.Gray16); ok { return dst } dst := image.NewGray16(src.Bounds()) Copy(dst, src) return dst }
func tToGray16(m image.Image) *image.Gray16 { if p, ok := m.(*image.Gray16); ok { return p } p := image.NewGray16(m.Bounds()) xdraw.Draw(p, p.Bounds(), m, image.Pt(0, 0), xdraw.Src) return p }
func Test_ZeroImg(t *testing.T) { zeroImg := image.NewGray16(image.Rect(0, 0, 0, 0)) m := Resize(0, 0, zeroImg, NearestNeighbor) if m.Bounds() != zeroImg.Bounds() { t.Fail() } }
func Test_CorrectResize(t *testing.T) { zeroImg := image.NewGray16(image.Rect(0, 0, 256, 256)) m := Resize(60, 0, zeroImg, NearestNeighbor) if m.Bounds() != image.Rect(0, 0, 60, 60) { t.Fail() } }
func TestSubImage(t *testing.T) { testData := []struct { desc string img draw.Image ok bool }{ { "sub image (Gray)", image.NewGray(image.Rect(0, 0, 10, 10)), true, }, { "sub image (Gray16)", image.NewGray16(image.Rect(0, 0, 10, 10)), true, }, { "sub image (RGBA)", image.NewRGBA(image.Rect(0, 0, 10, 10)), true, }, { "sub image (RGBA64)", image.NewRGBA64(image.Rect(0, 0, 10, 10)), true, }, { "sub image (NRGBA)", image.NewNRGBA(image.Rect(0, 0, 10, 10)), true, }, { "sub image (NRGBA64)", image.NewNRGBA64(image.Rect(0, 0, 10, 10)), true, }, { "sub image (fake)", fakeDrawImage{image.Rect(0, 0, 10, 10)}, false, }, } for _, d := range testData { simg, ok := getSubImage(d.img, image.Pt(3, 3)) if ok != d.ok { t.Errorf("test [%s] failed: expected %#v, got %#v", d.desc, d.ok, ok) } else if ok { simg.Set(5, 5, color.NRGBA{255, 255, 255, 255}) r, g, b, a := d.img.At(5, 5).RGBA() if r != 0xffff || g != 0xffff || b != 0xffff || a != 0xffff { t.Errorf("test [%s] failed: expected (0xffff, 0xffff, 0xffff, 0xffff), got (%d, %d, %d, %d)", d.desc, r, g, b, a) } } } }
func convertToGray16QuickDraw(src ImageReader) *image.Gray16 { dst := image.NewGray16(src.Bounds()) QuickRP( func(rect image.Rectangle) { draw.Draw(dst, rect, src, rect.Min, draw.Over) }, )(src.Bounds()) return dst }
// WriteGreyImagePng handles writing a Noiser out to a PNG image. It samples // the noise space in increments specified by noiseSampleDelta. The image is // generated using multiple goroutines to handle slower methods. It also // normalizes the image to provide full greyscale values. // // The minimum X and minimum Y determine the lower-left point in noise space to // begin sampling. The number of samples to do in the X and Y directions also // determines the width and height of the resulting image. Finally, the // noise sampling delta determines the distance between two sampled points in // noise space. Setting this parameter to one will yield a black image for // Perlin Noise. func WriteGreyImagePng(w io.Writer, noiser Noiser, minX, minY, numberSamplesX, numberSamplesY int, noiseSampleDelta float64) error { if numberSamplesX <= 0 || numberSamplesY <= 0 { return errors.New("invalid dimensions") } grays := make([][]float64, numberSamplesY) noiseY := float64(minY) done := make(chan struct{ MinValue, MaxValue float64 }) for y := 0; y < numberSamplesY; y++ { go func(y int, noiseY float64) { grays[y] = make([]float64, numberSamplesX) noiseX := float64(minX) minValue := 0.0 maxValue := 0.0 for x := 0; x < numberSamplesX; x++ { grays[y][x] = noiser.Noise(noiseX, noiseY) if x == 0 && y == 0 { minValue = grays[y][x] maxValue = minValue } else if grays[y][x] > maxValue { maxValue = grays[y][x] } else if grays[y][x] < minValue { minValue = grays[y][x] } noiseX += noiseSampleDelta } done <- struct{ MinValue, MaxValue float64 }{minValue, maxValue} }(y, noiseY) noiseY += noiseSampleDelta } minValue := 0.0 maxValue := 0.0 for y := 0; y < numberSamplesY; y++ { mm := <-done if y == 0 { minValue = mm.MinValue maxValue = mm.MaxValue } else if mm.MinValue < minValue { minValue = mm.MinValue } else if mm.MaxValue > maxValue { maxValue = mm.MaxValue } } img := image.NewGray16(image.Rect(0, 0, numberSamplesX, numberSamplesY)) for y := 0; y < numberSamplesY; y++ { for x := 0; x < numberSamplesX; x++ { frac := (grays[y][x] - minValue) / (maxValue - minValue) uIntVal := uint16(linearInterpolation(0, 65535, frac)) shade := color.Gray16{uIntVal} img.SetGray16(x, numberSamplesY-y-1, shade) } } return png.Encode(w, img) }
// Interpolate uint16/pixel images. func interpolate1x16(src *image.Gray16, dstW, dstH int) image.Image { srcRect := src.Bounds() srcW := srcRect.Dx() srcH := srcRect.Dy() ww, hh := uint64(dstW), uint64(dstH) dx, dy := uint64(srcW), uint64(srcH) n, sum := dx*dy, make([]uint64, dstW*dstH) for y := 0; y < srcH; y++ { pixOffset := src.PixOffset(0, y) for x := 0; x < srcW; x++ { // Get the source pixel. val64 := uint64(binary.BigEndian.Uint16([]byte(src.Pix[pixOffset+0 : pixOffset+2]))) pixOffset += 2 // Spread the source pixel over 1 or more destination rows. py := uint64(y) * hh for remy := hh; remy > 0; { qy := dy - (py % dy) if qy > remy { qy = remy } // Spread the source pixel over 1 or more destination columns. px := uint64(x) * ww index := (py/dy)*ww + (px / dx) for remx := ww; remx > 0; { qx := dx - (px % dx) if qx > remx { qx = remx } qxy := qx * qy sum[index] += val64 * qxy index++ px += qx remx -= qx } py += qy remy -= qy } } } dst := image.NewGray16(image.Rect(0, 0, dstW, dstH)) index := 0 for y := 0; y < dstH; y++ { pixOffset := dst.PixOffset(0, y) for x := 0; x < dstW; x++ { binary.BigEndian.PutUint16(dst.Pix[pixOffset+0:pixOffset+2], uint16(sum[index]/n)) pixOffset += 2 index++ } } return dst }
// ToGray16 converts the image to a 16-bit integer gray image. // Maps [0, 1] to [0, math.MaxUint16]. // Caps to [0, math.MaxUint16]. func ToGray16(f *Image) *image.Gray16 { g := image.NewGray16(image.Rect(0, 0, f.Width, f.Height)) for x := 0; x < f.Width; x++ { for y := 0; y < f.Height; y++ { v := round(math.MaxUint16 * f.At(x, y)) v = min(math.MaxUint16, max(0, v)) g.SetGray16(x, y, color.Gray16{uint16(v)}) } } return g }
func convertToGray16QuickAllPoints(src ImageReader) *image.Gray16 { dst := image.NewGray16(src.Bounds()) QuickRP( AllPointsRP( func(pt image.Point) { dst.Set(pt.X, pt.Y, src.At(pt.X, pt.Y)) }, ), )(src.Bounds()) return dst }
func ToImage(face eigenface.FaceVector) image.Image { bounds := image.Rect(0, 0, face.Width, face.Height) im := image.NewGray16(bounds) for y := 0; y < face.Height; y++ { for x := 0; x < face.Width; x++ { // ORL database images are 16-bit grayscale value := uint16(face.Pixels[(y*face.Width)+x]) im.SetGray16(x, y, color.Gray16{value}) } } return im }
func TestColorspaceLinearToSRGB(t *testing.T) { vals := []float32{ 0.00000, 0.34919, 0.48453, 0.58383, 0.66519, 0.73536, 0.79774, 0.85431, 0.90633, 0.95469, 1.00000, } imgs := []draw.Image{ image.NewGray(image.Rect(0, 0, 11, 11)), image.NewGray(image.Rect(0, 0, 111, 111)), image.NewGray16(image.Rect(0, 0, 11, 11)), image.NewGray16(image.Rect(0, 0, 1111, 1111)), } for _, img := range imgs { for i := 0; i <= 10; i++ { img.Set(i, 0, color.Gray{uint8(255 * float32(i) / 10.0)}) } img2 := image.NewGray(img.Bounds()) New(ColorspaceLinearToSRGB()).Draw(img2, img) if !img2.Bounds().Size().Eq(img.Bounds().Size()) { t.Errorf("ColorspaceLinearRGBToSRGB bad result size: expected %v got %v", img.Bounds().Size(), img2.Bounds().Size()) } for i := 0; i <= 10; i++ { expected := uint8(vals[i]*255.0 + 0.5) c := img2.At(i, 0).(color.Gray) if math.Abs(float64(c.Y)-float64(expected)) > 1 { t.Errorf("ColorspaceLinearRGBToSRGB bad color value at index %v expected %v got %v", i, expected, c.Y) } } } }
func TestColorspaceSRGBToLinear(t *testing.T) { vals := []float32{ 0.00000, 0.01002, 0.03310, 0.07324, 0.13287, 0.21404, 0.31855, 0.44799, 0.60383, 0.78741, 1.00000, } imgs := []draw.Image{ image.NewGray(image.Rect(0, 0, 11, 11)), image.NewGray(image.Rect(0, 0, 111, 111)), image.NewGray16(image.Rect(0, 0, 11, 11)), image.NewGray16(image.Rect(0, 0, 1111, 1111)), } for _, img := range imgs { for i := 0; i <= 10; i++ { img.Set(i, 0, color.Gray{uint8(255 * float32(i) / 10.0)}) } img2 := image.NewGray(img.Bounds()) New(ColorspaceSRGBToLinear()).Draw(img2, img) if !img2.Bounds().Size().Eq(img.Bounds().Size()) { t.Errorf("ColorspaceSRGBToLinear bad result size: expected %v got %v", img.Bounds().Size(), img2.Bounds().Size()) } for i := 0; i <= 10; i++ { expected := uint8(vals[i]*255.0 + 0.5) c := img2.At(i, 0).(color.Gray) if math.Abs(float64(c.Y)-float64(expected)) > 1 { t.Errorf("ColorspaceSRGBToLinear bad color value at index %v expected %v got %v", i, expected, c.Y) } } } }
func TestNewPixelGetter(t *testing.T) { var img image.Image var pg *pixelGetter img = image.NewNRGBA(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itNRGBA || pg.imgNRGBA == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter NRGBA") } img = image.NewNRGBA64(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itNRGBA64 || pg.imgNRGBA64 == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter NRGBA64") } img = image.NewRGBA(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itRGBA || pg.imgRGBA == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter RGBA") } img = image.NewRGBA64(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itRGBA64 || pg.imgRGBA64 == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter RGBA64") } img = image.NewGray(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itGray || pg.imgGray == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter Gray") } img = image.NewGray16(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itGray16 || pg.imgGray16 == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter Gray16") } img = image.NewYCbCr(image.Rect(0, 0, 1, 1), image.YCbCrSubsampleRatio422) pg = newPixelGetter(img) if pg.imgType != itYCbCr || pg.imgYCbCr == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter YCbCr") } img = image.NewUniform(color.NRGBA64{0, 0, 0, 0}) pg = newPixelGetter(img) if pg.imgType != itGeneric || pg.imgGeneric == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter Generic(Uniform)") } img = image.NewAlpha(image.Rect(0, 0, 1, 1)) pg = newPixelGetter(img) if pg.imgType != itGeneric || pg.imgGeneric == nil || !img.Bounds().Eq(pg.imgBounds) { t.Error("newPixelGetter Generic(Alpha)") } }
func convert_to_gray(img image.Image) image.Image { width, height := get_image_dims(img) gray_img := image.NewGray16(width, height) for x := 0; x < width; x++ { for y := 0; y < height; y++ { r, g, b, _ := img.At(x, y).RGBA() avg := (r + g + b) / 3.0 gray_img.Set(x, y, image.Gray16Color{uint16(avg)}) } } return gray_img }
func decodePlainGray16(r io.Reader, c PNMConfig) (image.Image, error) { m := image.NewGray16(image.Rect(0, 0, c.Width, c.Height)) var col uint16 for y := 0; y < c.Height; y++ { for x := 0; x < c.Width; x++ { if _, err := fmt.Fscan(r, &col); err != nil { return nil, err } m.Set(x, y, color.Gray16{col}) } } return m, nil }
func makeImages(r image.Rectangle) []image.Image { return []image.Image{ image.NewGray(r), image.NewGray16(r), image.NewNRGBA(r), image.NewNRGBA64(r), image.NewPaletted(r, somePalette), image.NewRGBA(r), image.NewRGBA64(r), image.NewYCbCr(r, image.YCbCrSubsampleRatio444), image.NewYCbCr(r, image.YCbCrSubsampleRatio422), image.NewYCbCr(r, image.YCbCrSubsampleRatio420), image.NewYCbCr(r, image.YCbCrSubsampleRatio440), } }
func imgType(im image.Image, w, h int) imageng { var scaled imageng switch im.ColorModel() { case image.RGBAColorModel: scaled = image.NewRGBA(w, h) case image.NRGBAColorModel: scaled = image.NewNRGBA(w, h) case image.GrayColorModel: scaled = image.NewGray(w, h) case image.Gray16ColorModel: scaled = image.NewGray16(w, h) default: scaled = image.NewRGBA64(w, h) } return scaled }
func GetChunkImage(chunk [][]float32) *image.Gray16 { h := len(chunk) w := len(chunk[0]) img := image.NewGray16(image.Rect(0, 0, h, w)) for x, r := range chunk { for y, v := range r { img.SetGray16(x, y, color.Gray16{MapFloat32HeightToGray(v)}) } } return img }