image - 使用 image/jpeg 编码会导致图像饱和/像素错误

标签 image go image-processing

我遇到这个问题已经有一段时间了:我正在创建一个模块来处理图像,我的功能之一是遍历图像的每个像素并反转颜色。该函数在编码 .png 图像时返回预期结果,但它使 .jpeg/jpg 图像“饱和”。

处理 .png 图像时的示例(正确):/image/0r0Go.png

处理 .jpeg 图像时的示例(错误):/image/I7hNM.jpg

我正在研究,我发现最接近我的问题的是 Go 存储库中的这个问题,尽管它不是答案:https://github.com/golang/go/issues/23936

// InvertColors function

func InvertColors(img image.Image) image.Image {
    bounds := img.Bounds()
    width := bounds.Max.X
    height := bounds.Max.Y
    inverted := image.NewRGBA(bounds)

    for y := bounds.Min.Y; y < height; y++ {
        for x := bounds.Min.X; x < width; x++ {
            r, g, b, a := img.At(x, y).RGBA()
            c := color.RGBA{uint8(255 - r), uint8(255 - g), uint8(255 - b), uint8(a)}

            inverted.SetRGBA(x, y, c)
        }
    }

    return inverted
}

// main example
func main() {
    link := "https://i.imgur.com/n5hsdl4.jpg"
    img, err := GetImageFromURL(link)
    if err != nil {
        panic(err)
    }

    buf := new(bytes.Buffer)
    Encode(buf, img, "jpg")
    ioutil.WriteFile("temp.jpg", buf.Bytes(), 0666)

    invImg := InvertColors(img)
    buf = new(bytes.Buffer)
    Encode(buf, invImg, "jpg")
    ioutil.WriteFile("temp2.jpg", buf.Bytes(), 0666)
}

// GetImageFromURL 
func GetImageFromURL(link string) (image.Image, error) {
    _, format, err := ParseURL(link)
    if err != nil {
        return nil, err
    }

    req, err := http.NewRequest("GET", link, nil)
    if err != nil {
        return nil, err
    }

    // Required to make a request.
    req.Close = true
    req.Header.Set("Content-Type", "image/"+format)

    res, err := http.DefaultClient.Do(req)
    if err != nil {
        return nil, err
    }
    defer res.Body.Close()

    b, err := ioutil.ReadAll(res.Body)
    if err != nil {
        return nil, err
    }

    img, err := Decode(bytes.NewReader(b), format)
    if err != nil {
        return nil, err
    }

    return img, nil
}

func ParseURL(link string) (u *url.URL, format string, err error) {
    u, err = url.Parse(link)
    if err != nil {
        return u, "", err
    }

    format = u.Path[len(u.Path)-4:]
    if strings.Contains(format, ".") {
        format = strings.Split(format, ".")[1]
    }

    if format != "png" && format != "jpg" && format != "jpeg" {
        return u, "", fmt.Errorf("Unsupported format: %s", format)
    }

    return u, format, nil
}

func Decode(r io.Reader, format string) (img image.Image, err error) {
    if format == "png" {
        img, err = png.Decode(r)
        if err != nil {
            return nil, err
        }

    } else if format == "jpg" || format == "jpeg" {
        img, err = jpeg.Decode(r)
        if err != nil {
            return nil, err
        }

    } else {
        return nil, fmt.Errorf("Unsupported format: %s", format)
    }

    return img, nil
}

最佳答案

您的代码中有两个与颜色处理相关的错误(其中第二个可能不相关)。

首先,RGBA() 方法返回 16 位 R、G、B、A,但您将它们视为 8 位值。

第二,color.RGBA 值是 alpha 预乘的,因此 (R, G, B, A) 的逆是 (A-R, A-G, A-B,A)而不是(MAX-R,MAX-G,MAX-B,A)。这可能不相关,因为看起来您的图片没有任何重要的 Alpha。

修复代码的一种方法是替换它:

r, g, b, a := img.At(x, y).RGBA()
c := color.RGBA{uint8(255 - r), uint8(255 - g), uint8(255 - b), uint8(a)}

这样:

r, g, b, a := img.At(x, y).RGBA()
c := color.RGBA{uint8((a - r)>>8), uint8((a - g)>>8), uint8((a - b)>>8), uint8(a>>8)}

(请注意,您可能会发现首先将图像转换为 image.NRGBA (如果还没有),然后迭代存储(非 alpha 预乘)RGBA 的底层字节 slice 图像 channel 比使用 imagecolor 包提供的更抽象的接口(interface)要快得多。)

关于image - 使用 image/jpeg 编码会导致图像饱和/像素错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72926524/

相关文章:

CSS:调整div中4个图像的位置

CSS : Background image not rescaling on mobile

api - 我可以在我的 Go 程序中直接使用 go-ipfs 吗?

asp.net-mvc - 调整 Azure Blob 存储中的图像大小

image - bwboundaries 获取图像边界

java - 组件位置 (Vaadin)

java - 二维图像中的 Gabor 小波

go - Windows 10 上未定义的 : syscall. Mmap

go - 将接口(interface)与 nil 进行比较

Python:在黑色边框中反射图像