Reputation: 319
This is an exercise from The Go Programming Language by Donovan & Kernighan:
Exercise 3.6: Supersampling is a technique to reduce the effect of pixelation by computing the color value at several points within each pixel and taking the average. The simplest method is to divide each pixel into four "subpixels". Implement it.
Here is my solution:
// Mandelbrot emits a PNG image of the Mandelbrot fractal.
package main
import (
//"fmt"
"image"
"image/color"
"image/png"
"math/cmplx"
"os"
)
func main() {
const (
xmin, ymin, xmax, ymax = -2, -2, +2, +2
width, height = 1024, 1024
swidth, sheight = width * 2, height * 2
)
var superColors [swidth][sheight]color.Color
for py := 0; py < sheight; py++ {
y := float64(py) / sheight * (ymax - ymin) + ymin
for px := 0; px < swidth; px++ {
x := float64(px) / swidth * (xmax - xmin) + xmin
z := complex(x, y)
superColors[px][py] = mandelbrot(z)
}
}
img := image.NewRGBA(image.Rect(0, 0, width, height))
for j := 0; j < height; j++ {
for i := 0; i < width; i++ {
si, sj := 2*i, 2*j
r1, g1, b1, a1 := superColors[si][sj].RGBA()
r2, g2, b2, a2 := superColors[si+1][sj].RGBA()
r3, g3, b3, a3 := superColors[si+1][sj+1].RGBA()
r4, g4, b4, a4 := superColors[si][sj+1].RGBA()
avgColor := color.RGBA{
uint8((r1 + r2 + r3 + r4) / 4),
uint8((g1 + g2 + g3 + g4) / 4),
uint8((b1 + b2 + b3 + b4) / 4),
uint8((a1 + a2 + a3 + a4) / 4)}
img.Set(i, j, avgColor)
}
}
png.Encode(os.Stdout, img)
}
func mandelbrot(z complex128) color.Color {
const iterations = 200
const contrast = 15
var v complex128
for n := uint8(0); n < iterations; n++ {
v = v*v + z
if cmplx.Abs(v) > 2 {
return color.Gray{255 - contrast*n}
}
}
return color.Black
}
However, the result of my solution seems that it doesn't reduce the effect of pixelation:
Is my solution wrong?
Upvotes: 1
Views: 364
Reputation: 21
If you add two uint8, it's overflow the memory. For example :
var a, b uint8 = 200 , 100
fmt.Printf(a+b) // result = 44 (300-256)
Just convert your uint8 to int before to add them together :
var a, b uint8 = 200 , 100
fmt.Printf(int(a)+int(b)) // result = 300
and in your case :
var a, b uint8 = 200 , 100
fmt.Printf(uint8((int(a)+int(b)/2)) // result = 150
Upvotes: 0
Reputation: 367
You can convert values from uint32 to uint8 in this case by performing right shift operation:
r := r >> 8
This will speed up computation time.
See also: Why does golang RGBA.RGBA() method use | and <<?
Upvotes: 0
Reputation: 6454
In go
, when you obtained the RGBA values through Color.RGBA()
, each color component (R
, G
, B
, A
) is represented by 16-bit unsigned, thus the range is between 0-0xffff
(0-65535). However, when you save the image to PNG, each component is between 0-0xff
(0-255). You need to correctly scale down each color component using the following formula:
//e.g. red component
r := ((r1+r2+r3+r4)/4)*(255/65535) => (r1+r2+r3+r4)/1028
In your case, the correct formula is:
avgColor := color.RGBA{
uint8((r1 + r2 + r3 + r4) / 1028),
uint8((g1 + g2 + g3 + g4) / 1028),
uint8((b1 + b2 + b3 + b4) / 1028),
uint8((a1 + a2 + a3 + a4) / 1028)}
UPDATE:
Output image looks like
Upvotes: 2