Beispiel #1
0
func ImageEnhanceGrey(img *image.Gray, enhanceDegress float32, enhanceOffset float32) *image.RGBA {
	rgbFunc := func(xpos, ypos int) (r0, g0, b0, a0 uint8) {
		gray := img.GrayAt(xpos, ypos)
		return gray.Y, gray.Y, gray.Y, gray.Y
	}
	imgEnhanced := imenhance(enhanceDegress, enhanceOffset, [3]bool{true, true, true}, false, img.Rect, rgbFunc)
	return imgEnhanced
}
Beispiel #2
0
func emptyCol(m *image.Gray, r image.Rectangle, x int) bool {
	for y := r.Min.Y; y < r.Max.Y; y++ {
		if m.GrayAt(x, y).Y > 0 {
			return false
		}
	}
	return true
}
Beispiel #3
0
func emptyRow(m *image.Gray, r image.Rectangle, y int) bool {
	for x := r.Min.X; x < r.Max.X; x++ {
		if m.GrayAt(x, y).Y > 0 {
			return false
		}
	}
	return true
}
Beispiel #4
0
func meanHeight(g *image.Gray) uint8 {
	b := g.Bounds()
	var total uint64
	for i := b.Min.X; i < b.Max.X; i++ {
		for j := b.Min.Y; j < b.Max.Y; j++ {
			total += uint64(g.GrayAt(i, j).Y)
		}
	}
	return uint8(total / uint64((b.Dx() * b.Dy())))
}
Beispiel #5
0
// Transforms gray input image color depth to the palette defined in p
// The algorithm simply assigns the nearest palette color to each pixel,
// without distributing error in any way, so expect color banding
func ditheringAverage(img *image.Gray, p *color.Palette) {
	size := img.Bounds()
	for y := size.Min.Y; y < size.Max.Y; y++ {
		for x := size.Min.X; x < size.Max.X; x++ {
			c1 := img.GrayAt(x, y)
			c2 := p.Convert(c1).(color.Gray)
			img.SetGray(x, y, c2)
		}
	}
}
Beispiel #6
0
////////////////////////////////////////////////////////////////////////////////
// Does a top to bottom, left to right scan of img starting at x,y. When a    //
// black pixel is encountered, the scan stops and the position is returned    //
////////////////////////////////////////////////////////////////////////////////
func nextPixel(x, y int, img *image.Gray, vis []bool) (int, int) {
	offset := img.Bounds().Max.X
	for cy := y; cy < img.Bounds().Max.Y; cy++ {
		start := 0
		if cy == y {
			start = x
		}
		for cx := start; cx < img.Bounds().Max.X; cx++ {
			if !vis[cx+cy*offset] && img.GrayAt(cx, cy) == black {
				return cx, cy
			}
		}
	}
	return -1, -1
}
Beispiel #7
0
func ImageFilterGrey(img *image.Gray, filter [][]float32, lowQuality bool) *image.RGBA {
	if lowQuality {
		imgAva := ImageEnhanceGrey(img, filter[0][0], 0)
		return imfilter(filter, img.Rect, func(xpos, ypos int) (r0, g0, b0, a0 uint8) {
			gray := imgAva.RGBAAt(xpos, ypos)
			return gray.R, gray.R, gray.R, gray.A
		}, func(filterValue, colorValue float32) float32 {
			return colorValue
		})
	}
	return imfilter(filter, img.Rect, func(xpos, ypos int) (r0, g0, b0, a0 uint8) {
		gray := img.GrayAt(xpos, ypos)
		return gray.Y, gray.Y, gray.Y, gray.Y
	}, func(filterValue, colorValue float32) float32 {
		return filterValue * colorValue
	})
}
Beispiel #8
0
// RecogniseDigit takes 28x28 gray image and tries to recognise a digit
// panics if image has wrong size
func RecogniseDigit(img image.Gray, threshold uint8) (int, float64) {
	if img.Bounds().Max.X != 28 || img.Bounds().Max.Y != 28 {
		panic("Image size is invalid, use 28x28.")
	}

	input := make([]float64, 28*28, 28*28)
	pos := 0
	for x := 0; x < 28; x++ {
		for y := 0; y < 28; y++ {
			val := img.GrayAt(x, y).Y
			if val < threshold {
				val = 255 - val
			} else {
				val = 0
			}

			img.SetGray(x, y, color.Gray{Y: val})
			input[pos] = float64(val) / 255
			pos++
		}
	}
	digit, confidence := argmax(nn.Evaluate(input))
	return digit, confidence
}
Beispiel #9
0
func drawDroplet(img *image.Gray, x, y, r, h float64) {
	ri := int(r + 1)
	xi := int(x + 0.5)
	yi := int(y + 0.5)
	for i := yi - ri; i <= yi+ri; i++ {
		for j := xi - ri; j <= xi+ri; j++ {
			if i < 0 || i >= img.Rect.Dy() || j < 0 || j >= img.Rect.Dx() {
				continue
			}

			di := float64(i) - y
			dj := float64(j) - x
			if rr := di*di + dj*dj; rr <= r*r {
				vprev := img.GrayAt(j, i).Y
				v := 100*h/r*math.Pow(1-rr/r/r, 1.0)/math.Sqrt(1-di/r) + float64(vprev)
				if v > 255 {
					v = 255
				}

				img.SetGray(j, i, color.Gray{uint8(v)})
			}
		}
	}
}
Beispiel #10
0
// Dithering algorithms
// Dithering is the process of reducing the colorspace of an image to a more
// restricted palette. Since the Game Boy Printer only has a 2bit colorspace
// available, it's important that some dithering algorithms are implemented to
// deal with the fact. Depending on the properties of the dithering algorithm
// detail may or may not be preserved as well. Using simple techniques like
// average dithering will yield results with lots of color banding, while employing
// error diffusion techniques such as Floyd Steinberg will produce smoother
// results (color banding is replaced by the introduction of noise)
// The wikipedia article (http://en.wikipedia.org/wiki/Dither) is quite interesting
// and talks about some dithering algorithms, some of which are implemented here.
// Floyd Steinberg is an error diffusion dithering algorithm that adds the error
// of each color conversion to the neighbours of each pixel. This way it's possible
// to achieve a finer graded dithering
func ditheringFloydSteinberg(img *image.Gray, p *color.Palette) {
	size := img.Bounds()
	for y := size.Min.Y; y < size.Max.Y; y++ {
		for x := size.Min.X; x < size.Max.X; x++ {
			c1 := img.GrayAt(x, y)
			c2 := p.Convert(c1).(color.Gray)
			delta := int(c1.Y) - int(c2.Y)
			switch {
			case x+1 < size.Max.X && y < size.Max.Y:
				img.SetGray(x+1, y, color.Gray{uint8(int(img.GrayAt(x+1, y).Y) + delta*7/16)})
				fallthrough
			case x < size.Max.X && y+1 < size.Max.Y:
				img.SetGray(x, y+1, color.Gray{uint8(int(img.GrayAt(x, y+1).Y) + delta*5/16)})
				fallthrough
			case x-1 >= size.Min.X && y+1 < size.Max.Y:
				img.SetGray(x-1, y+1, color.Gray{uint8(int(img.GrayAt(x-1, y+1).Y) + delta*3/16)})
				fallthrough
			case x+1 < size.Max.X && y+1 < size.Max.Y:
				img.SetGray(x+1, y+1, color.Gray{uint8(int(img.GrayAt(x+1, y+1).Y) + delta*1/16)})
			}
			img.Set(x, y, c2)
		}
	}
}
Beispiel #11
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 #12
0
func TestDecode(t *testing.T) {
	var j *image.Gray
	i, _, _ := Decode("../att_faces/s1/1.png")
	j = i.(*image.Gray)
	fmt.Println(j.GrayAt(0, 0).Y)
}
Beispiel #13
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)}
}