1

这是Donovan 和 Kernighan的 The Go Programming Language中的一个练习:

练习 3.6:超级采样是一种通过计算每个像素内多个点的颜色值并取平均值来减少像素化影响的技术。最简单的方法是将每个像素分成四个“子像素”。实施它。

这是我的解决方案:

// 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
}

但是,我的解决方案的结果似乎并没有减少像素化的影响:

在此处输入图像描述

我的解决方案错了吗?

4

3 回答 3

2

go中,当您通过 获得RGBA 值时Color.RGBA(),每个颜色分量(RGBA)都用16 位无符号表示,因此范围在0-0xffff(0-65535)之间。但是,当您将图像保存为 PNG 时,每个分量都在0-0xff(0-255) 之间。您需要使用以下公式正确按比例缩小每个颜色分量:

//e.g. red component
r := ((r1+r2+r3+r4)/4)*(255/65535) => (r1+r2+r3+r4)/1028

在您的情况下,正确的公式是:

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)}

更新:
输出图像看起来像
超采样 Madlebrot 图像

于 2017-07-14T06:02:08.593 回答
0

在这种情况下,您可以通过执行右移操作将值从 uint32 转换为 uint8:

 r := r >> 8

这将加快计算时间。

另请参阅: 为什么 golang RGBA.RGBA() 方法使用 | 和 <<?

于 2017-08-22T00:45:59.977 回答
0

如果添加两个 uint8,则会溢出内存。例如 :
var a, b uint8 = 200 , 100 fmt.Printf(a+b) // result = 44 (300-256)

只需将您的 uint8 转换为 int 之前将它们添加在一起:
var a, b uint8 = 200 , 100 fmt.Printf(int(a)+int(b)) // result = 300

在你的情况下:
var a, b uint8 = 200 , 100 fmt.Printf(uint8((int(a)+int(b)/2)) // result = 150

于 2019-04-29T16:14:41.627 回答