func mapToColor(o map[string]interface{}) color.Color { var c color.RGBA // Because JavaScript switch x := o["r"].(type) { case int64: c.R = uint8(colorF(float64(x))) case float64: c.R = uint8(colorF(x)) } switch x := o["g"].(type) { case int64: c.G = uint8(colorF(float64(x))) case float64: c.G = uint8(colorF(x)) } switch x := o["b"].(type) { case int64: c.B = uint8(colorF(float64(x))) case float64: c.B = uint8(colorF(x)) } c.A = 0xff return c }
func (cf *ColorFinder) findMainColor(colorMap *map[color.RGBA]colorStats, shift uint, targetColor *shiftedRGBA) shiftedRGBA { colorWeights := make(map[shiftedRGBA]float64) bounds := cf.img.Bounds() stepLength := stepLength(bounds) for y := bounds.Min.Y; y < bounds.Max.Y; y += stepLength { for x := bounds.Min.X; x < bounds.Max.X; x += stepLength { r, g, b, a := cf.img.At(x, y).RGBA() color := color.RGBA{} color.R = uint8(r >> shiftRGB) color.G = uint8(g >> shiftRGB) color.B = uint8(b >> shiftRGB) color.A = uint8(a >> shiftRGB) if rgbMatchesTargetColor(targetColor, &color) { increaseColorWeight(&colorWeights, colorMap, &color, shift) } } } maxColor := shiftedRGBA{} maxWeight := 0.0 for sRGB, weight := range colorWeights { if weight > maxWeight { maxColor = sRGB maxWeight = weight } } return maxColor }
func superSampling(inputImage image.Image) image.Image { rect := inputImage.Bounds() width := rect.Size().X height := rect.Size().Y rect2 := image.Rect(rect.Min.X, rect.Min.Y, rect.Max.X-1, rect.Max.Y-1) rgba := image.NewRGBA(rect2) for x := 0; x < width-1; x++ { for y := 0; y < height-1; y++ { var col color.RGBA // 座標(x,y)のR, G, B, α の値を取得 r00, g00, b00, a00 := inputImage.At(x, y).RGBA() r01, g01, b01, a01 := inputImage.At(x, y+1).RGBA() r10, g10, b10, a10 := inputImage.At(x+1, y).RGBA() r11, g11, b11, a11 := inputImage.At(x+1, y+1).RGBA() col.R = uint8((uint(uint8(r00)) + uint(uint8(r01)) + uint(uint8(r10)) + uint(uint8(r11))) / 4) col.G = uint8((uint(uint8(g00)) + uint(uint8(g01)) + uint(uint8(g10)) + uint(uint8(g11))) / 4) col.B = uint8((uint(uint8(b00)) + uint(uint8(b01)) + uint(uint8(b10)) + uint(uint8(b11))) / 4) col.A = uint8((uint(uint8(a00)) + uint(uint8(a01)) + uint(uint8(a10)) + uint(uint8(a11))) / 4) rgba.Set(x, y, col) } } return rgba.SubImage(rect) }
// Convert a []float64 to an image, reading data with the format specified in // chans (e.g. RGBA, BGRA, BRG, RRR). If a component is not specified in the func FromSliceChans(img *Image, chans string, fill float64, data []float64) { surf := img.Surf cm := surf.ColorModel() b := surf.Bounds() minX, maxX := b.Min.X, b.Max.X minY, maxY := b.Min.Y, b.Max.Y k := 0 nc := len(chans) const mk = 0xff dfill := clamp8(fill) & mk for i := minY; i < maxY; i++ { for j := minX; j < maxX; j++ { outCol := color.RGBA{dfill, dfill, dfill, dfill} for c := 0; c < nc; c++ { switch chans[c] { case 'r', 'R': outCol.R = clamp8(data[k+c]) & mk case 'g', 'G': outCol.G = clamp8(data[k+c]) & mk case 'b', 'B': outCol.B = clamp8(data[k+c]) & mk case 'a', 'A': outCol.A = clamp8(data[k+c]) & mk default: // Just skip the channel } } k += nc img.Surf.Set(j, i, cm.Convert(outCol)) } } }
func main() { img := shapes.FilledImage(500, 300, image.White) fill := color.RGBA{200, 200, 200, 255} for i := 0; i < 10; i++ { width, height := 50+(20*i), 30+(10*i) rect, err := shapes.New("rectangle", shapes.Option{Fill: fill, Rect: image.Rect(0, 0, width, height), Filled: true}) if err != nil { log.Fatal(err) } x := 10 + (20 * i) for j := i / 2; j >= 0; j-- { rect.Draw(img, x+j, (x/2)+j) } fill.R -= uint8(i * 5) fill.G = fill.R fill.B = fill.R } shapes.SaveImage(img, "rectangle.png") }
func (cf *ColorFinder) buildColorMap() *map[color.RGBA]colorStats { colorMap := make(map[color.RGBA]colorStats) bounds := cf.img.Bounds() for y := bounds.Min.Y; y < bounds.Max.Y; y++ { for x := bounds.Min.X; x < bounds.Max.X; x++ { r, g, b, a := cf.img.At(x, y).RGBA() rgb := color.RGBA{} rgb.R = uint8(r >> shiftRGB) rgb.G = uint8(g >> shiftRGB) rgb.B = uint8(b >> shiftRGB) rgb.A = uint8(a >> shiftRGB) colrStats, exist := colorMap[rgb] if exist { colrStats.count++ } else { colrStats := colorStats{count: 1, weight: weight(&rgb)} if colrStats.weight <= 0 { colrStats.weight = 1e-10 } colorMap[rgb] = colrStats } } } return &colorMap }
// Return the complementary color func Complementary(v color.RGBA) [2]color.RGBA { var result color.RGBA result.R = 255 - v.R result.G = 255 - v.G result.B = 255 - v.B result.A = v.A return [2]color.RGBA{v, result} }
// Apply the given color mapping to the specified image buffers. func Apply(from, to *Rule, src, dst draw.Image) { var x, y int var r, g, b, a uint32 var sc color.Color var dc color.RGBA var pix pixel rect := src.Bounds() for y = 0; y < rect.Dy(); y++ { for x = 0; x < rect.Dx(); x++ { sc = src.At(x, y) r, g, b, a = sc.RGBA() pix.r = uint8(r >> 8) pix.g = uint8(g >> 8) pix.b = uint8(b >> 8) pix.a = uint8(a >> 8) // Check if the pixel matches the filter rule. if !(match(pix.r, from.R) && match(pix.g, from.G) && match(pix.b, from.B) && match(pix.a, from.A)) { dst.Set(x, y, sc) continue } // Compute three different types of grayscale conversion. // These can be applied by named references. pix.average = uint8(((r + g + b) / 3) >> 8) pix.lightness = uint8(((min(min(r, g), b) + max(max(r, g), b)) / 2) >> 8) // For luminosity it is necessary to apply an inverse of the gamma // function for the color space before calculating the inner product. // Then you apply the gamma function to the reduced value. Failure to // incorporate the gamma function can result in errors of up to 20%. // // For typical computer stuff, the color space is sRGB. The right // numbers for sRGB are approx. 0.21, 0.72, 0.07. Gamma for sRGB // is a composite function that approximates exponentiation by 1/2.2 // // This is a rather expensive operation, but gives a much more accurate // and satisfactory result than the average and lightness versions. pix.luminosity = gammaSRGB( 0.212655*invGammaSRGB(pix.r) + 0.715158*invGammaSRGB(pix.g) + 0.072187*invGammaSRGB(pix.b)) // Transform color. dc.R = transform(&pix, pix.r, to.R) dc.G = transform(&pix, pix.g, to.G) dc.B = transform(&pix, pix.b, to.B) dc.A = transform(&pix, pix.a, to.A) // Set new pixel. dst.Set(x, y, dc) } } }
func setAlpha(c color.RGBA, a uint8) color.RGBA { if c.A == 0 { return c } c.R = mult(c.R, a, c.A) c.G = mult(c.G, a, c.A) c.B = mult(c.B, a, c.A) c.A = a return c }
// SetAll sets the given values for the channels func (d *Dioder) SetAll(colorSet color.RGBA) { d.ColorConfiguration = colorSet //Red colorSet.R = calculateOpacity(colorSet.R, colorSet.A) d.SetChannelInteger(colorSet.R, d.PinConfiguration.Red) //Green colorSet.G = calculateOpacity(colorSet.G, colorSet.A) d.SetChannelInteger(colorSet.G, d.PinConfiguration.Green) //Blue colorSet.B = calculateOpacity(colorSet.B, colorSet.A) d.SetChannelInteger(colorSet.B, d.PinConfiguration.Blue) }
func drawworld2(translate *noise.Translate, w *worldgen2.World, img draw.Image) { w.Log = false bounds := img.Bounds() for y := bounds.Min.Y; y < bounds.Max.Y; y++ { for x := bounds.Min.X; x < bounds.Max.X; x++ { var c color.RGBA c.A = 255 posx, posy := translate.Into(float64(x), float64(y)) per := w.GetHeight_Island(posx, posy) if per < 0 { v := uint8(255 - 127*(-per)) c.R = 0 c.G = 0 c.B = v } else if per < 0.00002 { v := uint8(255 - 2550*per) c.R = v c.G = v c.B = 0 } else if per > 0.34 { v := uint8(220 * (per)) c.R = v c.G = v c.B = v } else { //v := uint8(255-per*255) v := uint8(255 - per*300) c.R = 0 c.G = v c.B = 0 } img.Set(x, y, c) } } w.Log = true }
func parseColors(args []*ast.BasicLit) (color.RGBA, error) { ints := make([]uint8, 4) var ret color.RGBA var u uint8 for i := range args { v := args[i] switch v.Kind { case token.FLOAT: f, err := strconv.ParseFloat(args[i].Value, 8) if err != nil { return ret, err } // Has to be alpha, or bust u = uint8(f * 100) case token.INT: i, err := strconv.Atoi(v.Value) if err != nil { return ret, err } u = uint8(i) case token.COLOR: if i != 0 { return ret, fmt.Errorf("hex is only allowed as the first argumetn found: % #v", v) } var err error ret, err = ast.ColorFromHexString(v.Value) if err != nil { return ret, err } // This is only allowed as the first argument i = i + 2 default: log.Fatalf("unsupported kind %s % #v\n", v.Kind, v) } ints[i] = u } if ints[0] > 0 { ret.R = ints[0] } if ints[1] > 0 { ret.G = ints[1] } if ints[2] > 0 { ret.B = ints[2] } if ints[3] > 0 { ret.A = ints[3] } return ret, nil }
func imfilterMerg(filter [][]float32, fX, fY, x, y, xoffset, yoffset int, rgbFunc func(xpos, ypos int) (r0, g0, b0, a0 uint8), mergFunc func(a, b float32) float32) color.RGBA { _, _, _, a := rgbFunc(x, y) newColor := color.RGBA{R: 0, G: 0, B: 0, A: a} for xx := 0; xx < fX; xx++ { for yy := 0; yy < fY; yy++ { r, g, b, _ := rgbFunc(x+xx-xoffset, y+yy-yoffset) newColor.R = oneColorCorrect(float32(newColor.R) + mergFunc(filter[xx][yy], float32(r))) if r != g { newColor.G = oneColorCorrect(float32(newColor.G) + mergFunc(filter[xx][yy], float32(g))) } else { newColor.G = newColor.R } switch b { case r: newColor.B = newColor.R case g: newColor.B = newColor.G default: newColor.B = oneColorCorrect(float32(newColor.B) + mergFunc(filter[xx][yy], float32(b))) } } } return newColor }
func blend(orig image.Image) (m image.Image) { // deviation range dev := uint16(50 << 8) c := new(color.RGBA) c.A = 255 bounds := orig.Bounds() // iterations for i := 0; i < 10; i++ { newm := image.NewRGBA(bounds) for y := bounds.Min.Y; y < bounds.Max.Y; y++ { for x := bounds.Min.X; x < bounds.Max.X; x++ { var r, g, b, ct uint32 _r, _g, _b, _ := orig.At(x, y).RGBA() for i := -1; i < 2; i++ { for j := -1; j < 2; j++ { rt, gt, bt, _ := orig.At(x+i, y+j).RGBA() if uint16(rt-_r) > dev || uint16(gt-_g) > dev || uint16(bt-_b) > dev { continue } r += rt g += gt b += bt ct++ } } c.R = uint8((r / ct) >> 8) c.G = uint8((g / ct) >> 8) c.B = uint8((b / ct) >> 8) newm.Set(x, y, c) } } m = newm } return }
func main() { img := shapes.FilledImage(420, 220, image.White) fill := color.RGBA{200, 200, 200, 0xFF} // light gray for i := 0; i < 10; i++ { width, height := 40+(20*i), 20+(10*i) rectangle := shapes.Rectangle{fill, image.Rect(0, 0, width, height), true} x := 10 + (20 * i) for j := i / 2; j >= 0; j-- { rectangle.Draw(img, x+j, (x/2)+j) } fill.R -= uint8(i * 5) fill.G = fill.R fill.B = fill.R } shapes.SaveImage(img, "rectangle.png") }
func DrawImage(src image.Image, dest draw.Image, tr MatrixTransform, op draw.Op, filter ImageFilter) { bounds := src.Bounds() x0, y0, x1, y1 := float64(bounds.Min.X), float64(bounds.Min.Y), float64(bounds.Max.X), float64(bounds.Max.Y) tr.TransformRectangle(&x0, &y0, &x1, &y1) var x, y, u, v float64 var c1, c2, cr color.Color var r, g, b, a, ia, r1, g1, b1, a1, r2, g2, b2, a2 uint32 var color color.RGBA for x = x0; x < x1; x++ { for y = y0; y < y1; y++ { u = x v = y tr.InverseTransform(&u, &v) if bounds.Min.X <= int(u) && bounds.Max.X > int(u) && bounds.Min.Y <= int(v) && bounds.Max.Y > int(v) { c1 = dest.At(int(x), int(y)) switch filter { case LinearFilter: c2 = src.At(int(u), int(v)) case BilinearFilter: c2 = getColorBilinear(src, u, v) case BicubicFilter: c2 = getColorBicubic(src, u, v) } switch op { case draw.Over: r1, g1, b1, a1 = c1.RGBA() r2, g2, b2, a2 = c2.RGBA() ia = M - a2 r = ((r1 * ia) / M) + r2 g = ((g1 * ia) / M) + g2 b = ((b1 * ia) / M) + b2 a = ((a1 * ia) / M) + a2 color.R = uint8(r >> 8) color.G = uint8(g >> 8) color.B = uint8(b >> 8) color.A = uint8(a >> 8) cr = color default: cr = c2 } dest.Set(int(x), int(y), cr) } } } }
// linterp performs linear interpolation between the first (p[0]) and // the last (pal[len(p) - 1]) colors in palette "pal". It fills the // remaining (pal[1:len(p) - 1]) palette slots with the intepolated // colors. Colors in slots pal[0] and pal[len(p) - 1] MUST be of type // color.RGBA. The remaining slots will also be filled with colors of // type color.RGBA func linterp(pal color.Palette) { n := len(pal) if n <= 2 { return } s, e := pal[0].(color.RGBA), pal[n-1].(color.RGBA) dr := int(e.R) - int(s.R) dg := int(e.G) - int(s.G) db := int(e.B) - int(s.B) da := int(e.A) - int(s.A) for i := 1; i < n-1; i++ { c := color.RGBA{} c.R = uint8(int(s.R) + i*dr/(n-1)) c.G = uint8(int(s.G) + i*dg/(n-1)) c.B = uint8(int(s.B) + i*db/(n-1)) c.A = uint8(int(s.A) + i*da/(n-1)) pal[i] = c } }
//Takes a list of words (i.e. from a book), finds words that match the search term, //and creates an image based on the usage of those words with each pixel representing //the specified number of words (sectionSize). The channel will be sent a value of 1 //upon the successful completion of the task func CreateImage(words []string, searchTerm string, sectionSize int, quit chan int) { searchTerms := strings.Fields(searchTerm) imageHeight := 20 //Setup the image totalWords := len(words) imageWidth := int(math.Ceil(float64(totalWords) / float64(sectionSize))) newImg := image.NewRGBA(image.Rect(0, 0, imageWidth, imageHeight)) usedInSection := make([]bool, imageWidth, imageWidth) usedCount := 0 for index, word := range words { section := int(math.Floor(float64(index) / float64(sectionSize))) for _, term := range searchTerms { if word == term { usedInSection[section] = true usedCount++ break } } } fmt.Println("The terms", searchTerm, "were found", usedCount, "times") for x := 0; x < imageWidth; x++ { color := color.RGBA{255, 255, 255, 255} if usedInSection[x] == true { color.R = 0 color.G = 0 color.B = 0 } for y := 0; y < imageHeight; y++ { newImg.SetRGBA(x, y, color) } } SaveImage(searchTerm+".png", newImg) quit <- 1 }
// colorOpColor combines two colors with the requested operation // applying appropriate overflows as Sass expects func colorOpColor(tok token.Token, x, y *BasicLit, combine bool) (*BasicLit, error) { colX, err := ColorFromHexString(x.Value) if err != nil { return nil, err } colY, err := ColorFromHexString(y.Value) if err != nil { return nil, err } var z color.RGBA z.R = overflowMath(tok, colX.R, colY.R) z.G = overflowMath(tok, colX.G, colY.G) z.B = overflowMath(tok, colX.B, colY.B) s := colorToHex(z) return &BasicLit{ Kind: token.COLOR, Value: LookupColor(s), }, nil }
func main() { start := time.Now() const pictureSize = 5000 img := image.NewRGBA(image.Rect(0, 0, pictureSize, pictureSize)) f, err := os.OpenFile("mandel.png", os.O_WRONLY|os.O_CREATE, 0666) if err != nil { fmt.Printf("Can't create picture file\n") } deltaX := math.Abs(float64(-2.0-1.0)) / float64(pictureSize) deltaY := math.Abs(float64(-1.0-1.0)) / float64(pictureSize) cx := float64(-2.0) for x := 0; x < pictureSize; x++ { cx += deltaX cy := float64(-1.0) for y := 0; y < pictureSize; y++ { cy += deltaY iter := PointIteration(cx, cy, 255.0, 255) col := color.RGBA{255, iter, iter, iter} col.A = 255 col.R = iter col.G = iter col.B = iter img.Set(x, y, col) } } w := bufio.NewWriter(f) png.Encode(w, img) w.Flush() fmt.Printf("Seconds needed %d\n", time.Now().Sub(start)) }
func (bilinear) RGBA(src *image.RGBA, x, y float64) color.RGBA { p := findLinearSrc(src.Bounds(), x, y) // Array offsets for the surrounding pixels. off00 := offRGBA(src, p.low.X, p.low.Y) off01 := offRGBA(src, p.high.X, p.low.Y) off10 := offRGBA(src, p.low.X, p.high.Y) off11 := offRGBA(src, p.high.X, p.high.Y) var fr, fg, fb, fa float64 fr += float64(src.Pix[off00+0]) * p.frac00 fg += float64(src.Pix[off00+1]) * p.frac00 fb += float64(src.Pix[off00+2]) * p.frac00 fa += float64(src.Pix[off00+3]) * p.frac00 fr += float64(src.Pix[off01+0]) * p.frac01 fg += float64(src.Pix[off01+1]) * p.frac01 fb += float64(src.Pix[off01+2]) * p.frac01 fa += float64(src.Pix[off01+3]) * p.frac01 fr += float64(src.Pix[off10+0]) * p.frac10 fg += float64(src.Pix[off10+1]) * p.frac10 fb += float64(src.Pix[off10+2]) * p.frac10 fa += float64(src.Pix[off10+3]) * p.frac10 fr += float64(src.Pix[off11+0]) * p.frac11 fg += float64(src.Pix[off11+1]) * p.frac11 fb += float64(src.Pix[off11+2]) * p.frac11 fa += float64(src.Pix[off11+3]) * p.frac11 var c color.RGBA c.R = uint8(fr + 0.5) c.G = uint8(fg + 0.5) c.B = uint8(fb + 0.5) c.A = uint8(fa + 0.5) return c }
func (me *renderTile) getSample(x, y, z int, col *color.RGBA) { if (x >= SceneSize) || (y >= SceneSize) || (z >= SceneSize) { col.R, col.G, col.B, col.A = 0, 0, 0, 0 } else if colorCube { if (num.IsEveni(x) && num.IsEveni(y)) || ((z > 0) && num.IsEveni(z)) { col.R, col.G, col.B, col.A = uint8(x/2), uint8(y/2), uint8(z/2), 255 } else { col.R, col.G, col.B, col.A = uint8(x), uint8(y), uint8(z), 255 } } else { me.voxel = Scene[x][y][z] if me.voxel.A >= 1 { if correctAlpha { me.mixCol(col, &me.voxel, col) } else { col.R = mixRGB(col.R, me.voxel.R, col.A, me.voxel.A) // num.Mixb(me.voxel.R, me.voxel.A, col.R) col.G = mixRGB(col.G, me.voxel.G, col.A, me.voxel.A) // num.Mixb(me.voxel.G, me.voxel.A, col.G) col.B = mixRGB(col.B, me.voxel.B, col.A, me.voxel.A) // num.Mixb(me.voxel.B, me.voxel.A, col.B) col.A = mixA(col.A, me.voxel.A) // num.Mixb(1, col.A, me.voxel.A) } } } }
func main() { in := flag.String("i", "none", "input file") out := flag.String("o", "out.png", "output file") flag.Parse() if *in == "none" { return } bin := read(*in) binLength := len(bin) width := 384 height := len(bin) / width rect := image.Rect(0, 0, width, height) img := image.NewRGBA(rect) p := 0 for y := 0; y < height; y++ { for x := 0; x < width; x++ { var c color.RGBA for addr := p; addr < p+3 && addr < binLength; addr++ { if addr%3 == 0 { c.R = uint8(bin[addr]) } else if addr%3 == 1 { c.G = uint8(bin[addr]) } else if addr%3 == 2 { c.B = uint8(bin[addr]) } c.A = 0xff } p += 3 img.Set(x, y, c) } } f, _ := os.OpenFile(*out, os.O_CREATE|os.O_WRONLY, 0666) png.Encode(f, img) }
func featurize(orig image.Image) image.Image { // deviation range color_dev := uint16(20 << 8) feature_dev := 4 bounds := orig.Bounds() fmt.Println(bounds) // initialize the array of pixels traversed ex := make([][]bool, bounds.Max.X+1) for i := 0; i < bounds.Max.X+1; i++ { ex[i] = make([]bool, bounds.Max.Y+1) } // array of features // feature is an array of arrays [x,y] var features [][][2]int feature_i := 0 // recursively investigate all neighbors of supplied pixel // and build feature arrays // some shenanigans to make anonymous functions recurisively callable var discover func(x int, y int) discover = func(x int, y int) { // add this pixel to the current feature features[feature_i] = append(features[feature_i], [2]int{x, y}) // fmt.Println(x,y) ex[x][y] = true // grab the rgb for the supplied pixel _r, _g, _b, _ := orig.At(x, y).RGBA() for i := -1; i < 2; i++ { for j := -1; j < 2; j++ { xx, yy := x+i, y+j // check if it's within our bounds and if it's been processed already if xx < 0 || yy < 0 || xx > bounds.Max.X || yy > bounds.Max.Y || ex[xx][yy] == true { continue } rt, gt, bt, _ := orig.At(xx, yy).RGBA() // check the color range against our deviation spec if uint16(rt-_r) > color_dev || uint16(gt-_g) > color_dev || uint16(bt-_b) > color_dev { continue } discover(xx, yy) } } } // run through each pixel and build features for y := bounds.Min.Y; y < bounds.Max.Y; y++ { for x := bounds.Min.X; x < bounds.Max.X; x++ { // skip if already processed if ex[x][y] == true { continue } // fmt.Println(x,y) features = append(features, [][2]int{}) discover(x, y) feature_i++ } } newm := image.NewRGBA(bounds) c := new(color.RGBA) c.A = 255 for f := 0; f < len(features); f++ { // if the feature is large enough // average all pixel colors in it // and set all pixels to that color if len(features[f]) > feature_dev { var r, g, b, ct uint64 for p := 0; p < len(features[f]); p++ { rt, gt, bt, _ := orig.At(features[f][p][0], features[f][p][1]).RGBA() r += uint64(rt) g += uint64(gt) b += uint64(bt) ct++ } c.R = uint8((r / ct) >> 8) c.G = uint8((g / ct) >> 8) c.B = uint8((b / ct) >> 8) for p := 0; p < len(features[f]); p++ { newm.Set(features[f][p][0], features[f][p][1], c) } } else { // write the pixel out as-is for p := 0; p < len(features[f]); p++ { r, g, b, _ := orig.At(features[f][p][0], features[f][p][1]).RGBA() c.R = uint8(r >> 8) c.G = uint8(g >> 8) c.B = uint8(b >> 8) newm.Set(features[f][p][0], features[f][p][1], c) } } } return newm }
func main() { flag.Parse() // Set initial values. shades_per_iteration = float64(max_color) / float64(*max_iterations) var ( mset_x_total float64 = 3.5 mset_y_total float64 = 2.0 ) mset_x_min := *mset_x_ctr - (mset_x_total / 2) mset_x_max := *mset_x_ctr + (mset_x_total / 2) mset_y_min := *mset_y_ctr - (mset_y_total / 2) mset_y_max := *mset_y_ctr + (mset_y_total / 2) // Set coordinates according to xoom factor. mset_y_total = (mset_y_max - mset_y_min) / *zoom mset_x_total = (mset_x_max - mset_x_min) / *zoom mset_x_min = *mset_x_ctr - (mset_x_total / 2) mset_x_max = *mset_x_ctr + (mset_x_total / 2) mset_y_min = *mset_y_ctr - (mset_y_total / 2) mset_y_max = *mset_y_ctr + (mset_y_total / 2) mset_ratio := mset_x_total / mset_y_total img_ratio := float64(*img_width) / float64(*img_height) if mset_ratio > img_ratio { // The image is taller than the default mandelbrot set. // Therefore, the limiting dimension is the height of the mandelbrot set. // Don't touch the Y figures. // Reset the X limits. mset_y_total = mset_y_max - mset_y_min mset_x_total = mset_y_total * img_ratio mset_x_min = *mset_x_ctr - (mset_x_total / 2) mset_x_max = *mset_x_ctr + (mset_x_total / 2) } else { // The image is flatter than the default mandelbrot set. // Therefore, the limiting dimension is the width of the mandelbrot set. // Don't touch the X figures. // Reset the Y limits. mset_x_total = mset_x_max - mset_x_min mset_y_total = mset_x_total / img_ratio mset_y_min = *mset_y_ctr - (mset_y_total / 2) mset_y_max = *mset_y_ctr + (mset_y_total / 2) } // Set slope of conversion lines. // m = rise/run m_x = mset_x_total / float64(*img_width) m_y = mset_y_total / float64(*img_height) b_x = mset_x_min b_y = mset_y_min img := image.NewRGBA(image.Rect(0, 0, *img_width, *img_height)) // img := image.NewGray16(image.Rect(0, 0, *img_width, *img_height)) // img := image.NewGray(image.Rect(0, 0, *img_width, *img_height)) var ( c int64 c_max int64 = 0 clr color.RGBA // clr color.Gray16 // clr color.Gray // i int64 i_max int64 = 0 mpt MPT ) // mpt = new(MPT) for x := 0; x < *img_width; x++ { log.Printf("Percent Complete: %.1f", float64(x)/float64(*img_width)*100) for y := 0; y < *img_height; y++ { x_, y_ := getCoord(x, y) mpt.X0 = x_ mpt.Y0 = y_ mpt.X = 0 mpt.Y = 0 mpt.N = 0 mpt.iterate() factor_iterations := float64(mpt.N) / float64(*max_iterations) // This is a decimal revealing the scale based on iterations. factor_radius := math.Log2(mpt.R) / 2 c = int64((factor_iterations + factor_radius) * float64(*max_iterations) * shades_per_iteration) // c = max_color - c clr.G = uint8(c) clr.B = uint8(c >> 8) clr.R = uint8(c >> 16) clr.A = 255 // log.Printf("C: %b\n", c) // log.Printf("R: %b\n", color.R) // log.Printf("G: %b\n", color.G) // log.Printf("B: %b\n", color.B) // clr.Y = uint8(c) // The golange image is inverted on the y-axis compared to typical cartesian systems. img.Set(x, *img_height-y, clr) } } log.Printf("img_width: %d\n", *img_width) log.Printf("img_height: %d\n", *img_height) log.Printf("mset_x_min: %0.2f\n", mset_x_min) log.Printf("mset_x_max: %0.2f\n", mset_x_max) log.Printf("mset_x_total: %0.2f\n", mset_x_total) log.Printf("mset_y_min: %0.2f\n", mset_y_min) log.Printf("mset_y_max: %0.2f\n", mset_y_max) log.Printf("mset_y_total: %0.2f\n", mset_y_total) log.Printf("m_x: %0.8f\n", m_x) log.Printf("m_y: %0.8f\n", m_y) log.Printf("i_max: %d\n", i_max) log.Printf("c_max: %d\n", c_max) log.Println("Encoding image.") buffer := new(bytes.Buffer) if err := png.Encode(buffer, img); err != nil { log.Fatal(err.Error()) } log.Println("Writing image.") if err := ioutil.WriteFile(fmt.Sprintf("/Users/jackman/Pictures/mandelbrot(%.4f,%.4f)z%.1f[%dx%dz]x%d.png", *mset_x_ctr, *mset_y_ctr, *zoom, *img_width, *img_height, *max_iterations), buffer.Bytes(), 0644); err != nil { log.Fatal(err.Error()) } }
// Find returns the dominant color in img. func Find(img image.Image) color.RGBA { // Shrink image for faster processing. img = resize.Thumbnail(resizeTo, resizeTo, img, resize.NearestNeighbor) bounds := img.Bounds() width, height := bounds.Dx(), bounds.Dy() rnd := rand.New(rand.NewSource(0)) randomPoint := func() (x, y int) { x = bounds.Min.X + rnd.Intn(width) y = bounds.Min.Y + rnd.Intn(height) return } // Pick a starting point for each cluster. clusters := make(kMeanClusterGroup, 0, nCluster) for i := 0; i < nCluster; i++ { // Try up to 10 times to find a unique color. If no unique color can be // found, destroy this cluster. colorUnique := false for j := 0; j < maxSample; j++ { ri, gi, bi, a := img.At(randomPoint()).RGBA() // Ignore transparent pixels. if a == 0 { continue } r, g, b := uint8(ri/255), uint8(gi/255), uint8(bi/255) // Check to see if we have seen this color before. colorUnique = !clusters.ContainsCentroid(r, g, b) // If we have a unique color set the center of the cluster to // that color. if colorUnique { c := new(kMeanCluster) c.SetCentroid(r, g, b) clusters = append(clusters, c) break } } if !colorUnique { break } } convergence := false for i := 0; i < nIterations && !convergence && len(clusters) != 0; i++ { for x := bounds.Min.X; x < bounds.Max.X; x++ { for y := bounds.Min.Y; y < bounds.Max.Y; y++ { ri, gi, bi, a := img.At(x, y).RGBA() // Ignore transparent pixels. if a == 0 { continue } r, g, b := uint8(ri/255), uint8(gi/255), uint8(bi/255) // Figure out which cluster this color is closest to in RGB space. closest := clusters.Closest(r, g, b) closest.AddPoint(r, g, b) } } // Calculate the new cluster centers and see if we've converged or not. convergence = true for _, c := range clusters { convergence = convergence && c.CompareCentroidWithAggregate() c.RecomputeCentroid() } } // Sort the clusters by population so we can tell what the most popular // color is. sort.Sort(byWeight(clusters)) // Loop through the clusters to figure out which cluster has an appropriate // color. Skip any that are too bright/dark and go in order of weight. var col color.RGBA for i, c := range clusters { r, g, b := c.Centroid() // Sum the RGB components to determine if the color is too bright or too dark. var summedColor uint16 = uint16(r) + uint16(g) + uint16(b) if summedColor < maxBrightness && summedColor > minDarkness { // If we found a valid color just set it and break. We don't want to // check the other ones. col.R = r col.G = g col.B = b col.A = 0xFF break } else if i == 0 { // We haven't found a valid color, but we are at the first color so // set the color anyway to make sure we at least have a value here. col.R = r col.G = g col.B = b col.A = 0xFF } } return col }