Beispiel #1
0
//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
}
Beispiel #2
0
func (g *generator) buildTerrain(mpath minecraft.Path, level *level, terrain, biomes, plants *image.Paletted, height, water *image.Gray, c chan paint) error {
	b := terrain.Bounds()
	proceed := make(chan uint8, 10)
	errChan := make(chan error, 1)
	go func() {
		defer close(proceed)
		cc := newCache(g.Terrain.Blocks)
		for j := 0; j < b.Max.Y; j += 16 {
			chunkZ := int32(j >> 4)
			for i := 0; i < b.Max.X; i += 16 {
				chunkX := int32(i >> 4)
				h := int32(meanHeight(height.SubImage(image.Rect(i, j, i+16, j+16)).(*image.Gray)))
				wh := int32(meanHeight(water.SubImage(image.Rect(i, j, i+16, j+16)).(*image.Gray)))
				var t uint8
				if wh >= h<<1 { // more water than land...
					c <- paint{
						color.RGBA{0, 0, 255, 255},
						chunkX, chunkZ,
					}
					t = uint8(len(g.Terrain.Blocks) - 1)
					h = wh
				} else {
					t = modeTerrain(terrain.SubImage(image.Rect(i, j, i+16, j+16)).(*image.Paletted), len(g.Terrain.Palette))
					c <- paint{
						g.Terrain.Palette[t],
						chunkX, chunkZ,
					}
				}
				if err := mpath.SetChunk(cc.getFromCache(chunkX, chunkZ, t, h)); err != nil {
					errChan <- err
					return
				}
				proceed <- t
			}
		}
	}()
	ts := make([]uint8, 0, 1024)
	for i := 0; i < (b.Max.X>>4)+2; i++ {
		ts = append(ts, <-proceed) // get far enough ahead so all chunks are surrounded before shaping, to get correct lighting
	}
	select {
	case err := <-errChan:
		return err
	default:
	}
	for j := int32(0); j < int32(b.Max.Y); j += 16 {
		chunkZ := j >> 4
		for i := int32(0); i < int32(b.Max.X); i += 16 {
			chunkX := i >> 4
			var totalHeight int32
			ot := ts[0]
			ts = ts[1:]
			oy, _ := level.GetHeight(i, j)
			for x := i; x < i+16; x++ {
				for z := j; z < j+16; z++ {
					if biomes != nil {
						level.SetBiome(x, z, g.Biomes.Values[biomes.ColorIndexAt(int(x), int(z))])
					}
					h := int32(height.GrayAt(int(x), int(z)).Y)
					totalHeight += h
					wl := int32(water.GrayAt(int(x), int(z)).Y)
					y := oy
					if h > y {
						y = h
					}
					if wl > y {
						y = wl
					}
					for ; y > h && y > wl; y-- {
						level.SetBlock(x, y, z, minecraft.Block{})
					}
					if plants != nil {
						p := g.Plants.Blocks[plants.ColorIndexAt(int(x), int(z))]
						py := int32(1)
						for ; py <= int32(p.Level); py++ {
							level.SetBlock(x, y+py, z, p.Base)
						}
						level.SetBlock(x, y+py, z, p.Top)
					}
					for ; y > h; y-- {
						level.SetBlock(x, y, z, minecraft.Block{ID: 9})
					}
					t := terrain.ColorIndexAt(int(x), int(z))
					tb := g.Terrain.Blocks[t]
					for ; y > h-int32(tb.Level); y-- {
						level.SetBlock(x, y, z, tb.Top)
					}
					if t != ot {
						h = 0
					} else {
						h = oy
					}
					for ; y >= h; y-- {
						level.SetBlock(x, y, z, tb.Base)
					}
				}
			}
			c <- paint{
				color.Alpha{uint8(totalHeight >> 8)},
				chunkX, chunkZ,
			}
			select {
			case p, ok := <-proceed:
				if ok {
					ts = append(ts, p)
				}
			case err := <-errChan:
				return err
			}
		}
	}
	return nil
}
Beispiel #3
0
func blobAt(x, y int, img *image.Gray, vis []bool) *Blob {
	if img.GrayAt(x, y) == white {
		return nil
	}

	width := img.Bounds().Max.X
	height := img.Bounds().Max.Y

	r := image.Rect(x, y, x, y)
	q := newQueue()
	q.q(point{x, y})

	for q.length != 0 {
		p := q.dq()
		if vis[p.x+width*p.y] {
			continue
		}
		vis[p.x+width*p.y] = true
		if p.x > r.Max.X {
			r.Max.X = p.x
		}
		if p.x < r.Min.X {
			r.Min.X = p.x
		}
		if p.y > r.Max.Y {
			r.Max.Y = p.y
		}
		if p.y < r.Min.Y {
			r.Min.Y = p.y
		}

		// Up
		if p.y-1 >= 0 {
			if !vis[p.x+(p.y-1)*width] && img.GrayAt(p.x, p.y-1) == black {
				q.q(point{p.x, p.y - 1})
			}
		}
		// Right
		if p.x+1 < width {
			if !vis[p.x+1+p.y*width] && img.GrayAt(p.x+1, p.y) == black {
				q.q(point{p.x + 1, p.y})
			}
		}
		// Down
		if p.y+1 < height {
			if !vis[p.x+(p.y+1)*width] && img.GrayAt(p.x, p.y+1) == black {
				q.q(point{p.x, p.y + 1})
			}
		}
		// Left
		if p.x-1 >= 0 {
			if !vis[p.x-1+p.y*width] && img.GrayAt(p.x-1, p.y) == black {
				q.q(point{p.x - 1, p.y})
			}
		}
	}

	r.Max.Y += 1
	r.Max.X += 1

	return &Blob{Bounds: r, Img: img.SubImage(r)}
}