go - 如何通过计算每个像素内几个点的颜色值并取平均值来减少像素化的影响?

标签 go mandelbrot pixelate

这是来自 The Go Programming Language 的练习,作者是 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.

这是我的解决方案:

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

然而,我的解决方案的结果似乎并没有降低像素化的影响:

enter image description here

我的解决方案错了吗?

最佳答案

go 中,当您通过 Color.RGBA() 获取 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)}

更新:
输出图像看起来像
Supersampled Madlebrot image

关于go - 如何通过计算每个像素内几个点的颜色值并取平均值来减少像素化的影响?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45094282/

相关文章:

dataframe - dataframe-go:如何使用<>运算符进行过滤?

xml - 戈朗 : Compare XML structures

GO - binary.PutUvarint 当数值大于 127 时加 1

c - C 的 Mandelbrot 递归函数

javascript - 在计算 mandelbrot 集迭代时遇到问题

go - Golang 中是否有命令行工具来仅检查我的源代码的语法?

c++ - 使用 pthread 创建 mandelbrot 图像

ios - UIImageView 中自定义 UITableCiewCell 尺寸和分辨率

python - 如何在 Python 中使用 OpenCV 对图像进行像素化?