如何通过在每个像素内计算几个点的颜色值并取平均值来减少像素化效果?

huangapple go评论88阅读模式
英文:

How to reduce the effect of pixelation by computing the color value at several points within each pixel and taking the average?

问题

这是《The Go Programming Language》一书中的一个练习,题目是实现超采样技术来减少像素化效果。超采样是通过在每个像素内计算多个点的颜色值并取平均值来实现的。最简单的方法是将每个像素分成四个“子像素”。以下是你的解决方案:

// Mandelbrot emits a PNG image of the Mandelbrot fractal.
package main

import (
    "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
}

然而,你的解决方案似乎没有减少像素化效果。你的解决方案是否有问题?

英文:

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 (
//&quot;fmt&quot;
&quot;image&quot;
&quot;image/color&quot;
&quot;image/png&quot;
&quot;math/cmplx&quot;
&quot;os&quot;
)
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 &lt; sheight; py++ {
y := float64(py) / sheight * (ymax - ymin) + ymin
for px := 0; px &lt; 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 &lt; height; j++ {
for i := 0; i &lt; 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 &lt; iterations; n++ {
v = v*v + z
if cmplx.Abs(v) &gt; 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?

答案1

得分: 2

go语言中,当你通过Color.RGBA()获取RGBA值时,每个颜色分量(RGBA)都用16位无符号表示,因此范围在0-0xffff(0-65535)之间。然而,当你将图像保存为PNG格式时,每个分量的范围在0-0xff(0-255)之间。你需要使用以下公式正确缩放每个颜色分量:

//例如,红色分量
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)}

更新:
输出图像如下:
如何通过在每个像素内计算几个点的颜色值并取平均值来减少像素化效果?

英文:

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) =&gt; (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
如何通过在每个像素内计算几个点的颜色值并取平均值来减少像素化效果?

答案2

得分: 0

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

r := r >> 8

这将加快计算速度。

另请参考:
https://stackoverflow.com/questions/35374300/why-does-golang-rgba-rgba-method-use-and

英文:

You can convert values from uint32 to uint8 in this case by performing right shift operation:

 r := r &gt;&gt; 8

This will speed up computation time.

See also:
https://stackoverflow.com/questions/35374300/why-does-golang-rgba-rgba-method-use-and

答案3

得分: 0

如果你将两个uint8相加,会导致内存溢出。例如:

var a, b uint8 = 200, 100
fmt.Printf(a+b) // 结果为44 (300-256)

在将它们相加之前,将你的uint8转换为int:

var a, b uint8 = 200, 100
fmt.Printf(int(a)+int(b)) // 结果为300

在你的情况下:

var a, b uint8 = 200, 100
fmt.Printf(uint8((int(a)+int(b)/2)) // 结果为150
英文:

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

huangapple
  • 本文由 发表于 2017年7月14日 11:49:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/45094282.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定