gpt4 book ai didi

image - 更改单个像素的颜色 - Golang 图像

转载 作者:IT老高 更新时间:2023-10-28 13:08:55 26 4
gpt4 key购买 nike

我想打开 jpeg 图像文件,对其进行编码,更改一些像素颜色,然后按原样保存。

我想做这样的事情

imgfile, err := os.Open("unchanged.jpeg")
defer imgfile.Close()
if err != nil {
fmt.Println(err.Error())
}

img,err := jpeg.Decode(imgfile)
if err != nil {
fmt.Println(err.Error())
}
img.Set(0, 0, color.RGBA{85, 165, 34, 1})
img.Set(1,0,....)

outFile, _ := os.Create("changed.jpeg")
defer outFile.Close()
jpeg.Encode(outFile, img, nil)

我只是想不出一个可行的解决方案,因为我在编码图像文件后得到的默认图像类型没有 Set 方法。

谁能解释一下如何做到这一点?非常感谢。

最佳答案

解码成功时image.Decode() (以及特定的解码函数,如 jpeg.Decode() )返回值 image.Image . image.Image 是一个定义图像只读 View 的接口(interface):它不提供更改/绘制图像的方法。

image 包提供了几个 image.Image 实现,允许您更改/绘制图像,通常使用 Set(x, y int, c color.Color) 方法。

image.Decode() 但是不保证返回的图像将是 image 包中定义的任何图像类型,甚至不保证动态类型的图像有一个 Set() 方法(它可以,但不能保证)。注册的自定义图像解码器可能会返回一个 image.Image 值作为自定义实现(意味着不是 image 包中定义的图像类型)。

如果(动态类型的)图像确实有 Set() 方法,您可以使用 type assertion并使用它的 Set() 方法来绘制它。可以这样做:

type Changeable interface {
Set(x, y int, c color.Color)
}

imgfile, err := os.Open("unchanged.jpg")
if err != nil {
panic(err.Error())
}
defer imgfile.Close()

img, err := jpeg.Decode(imgfile)
if err != nil {
panic(err.Error())
}

if cimg, ok := img.(Changeable); ok {
// cimg is of type Changeable, you can call its Set() method (draw on it)
cimg.Set(0, 0, color.RGBA{85, 165, 34, 255})
cimg.Set(0, 1, color.RGBA{255, 0, 0, 255})
// when done, save img as usual
} else {
// No luck... see your options below
}

如果图像没有 Set() 方法,您可以选择通过实现实现 image.Image 的自定义类型来“覆盖其 View ”,但是在其 At(x, y int) color.Color 方法(返回/提供像素的颜色)中,如果图像可以更改,则返回您将设置的新颜色,并返回像素您不会更改图像的原始图像。

实现 image.Image 接口(interface)最容易使用 embedding 完成,因此您只需要实现所需的更改。可以这样做:

type MyImg struct {
// Embed image.Image so MyImg will implement image.Image
// because fields and methods of Image will be promoted:
image.Image
}

func (m *MyImg) At(x, y int) color.Color {
// "Changed" part: custom colors for specific coordinates:
switch {
case x == 0 && y == 0:
return color.RGBA{85, 165, 34, 255}
case x == 0 && y == 1:
return color.RGBA{255, 0, 0, 255}
}
// "Unchanged" part: the colors of the original image:
return m.Image.At(x, y)
}

使用它:非常简单。像你一样加载图像,但在保存时,提供我们的 MyImg 类型的值,它将在编码器询问时提供更改的图像内容(颜色):

jpeg.Encode(outFile, &MyImg{img}, nil)

如果您必须更改许多像素,则将所有像素都包含在 At() 方法中是不切实际的。为此,我们可以扩展我们的 MyImg 以拥有我们的 Set() 实现来存储我们想要更改的像素。示例实现:

type MyImg struct {
image.Image
custom map[image.Point]color.Color
}

func NewMyImg(img image.Image) *MyImg {
return &MyImg{img, map[image.Point]color.Color{}}
}

func (m *MyImg) Set(x, y int, c color.Color) {
m.custom[image.Point{x, y}] = c
}

func (m *MyImg) At(x, y int) color.Color {
// Explicitly changed part: custom colors of the changed pixels:
if c := m.custom[image.Point{x, y}]; c != nil {
return c
}
// Unchanged part: colors of the original image:
return m.Image.At(x, y)
}

使用它:

// Load image as usual, then

my := NewMyImg(img)
my.Set(0, 0, color.RGBA{85, 165, 34, 1})
my.Set(0, 1, color.RGBA{255, 0, 0, 255})

// And when saving, save 'my' instead of the original:
jpeg.Encode(outFile, my, nil)

如果您必须更改许多像素,那么创建一个支持更改其像素的新图像可能会更有利可图,例如image.RGBA ,在其上绘制原始图像,然后继续更改您想要的像素。

要将图像绘制到另一个图像上,您可以使用 image/draw包。

cimg := image.NewRGBA(img.Bounds())
draw.Draw(cimg, img.Bounds(), img, image.Point{}, draw.Over)

// Now you have cimg which contains the original image and is changeable
// (it has a Set() method)
cimg.Set(0, 0, color.RGBA{85, 165, 34, 255})
cimg.Set(0, 1, color.RGBA{255, 0, 0, 255})

// And when saving, save 'cimg' of course:
jpeg.Encode(outFile, cimg, nil)

以上代码仅用于演示。在“真实”图像中,Image.Bounds() 可能会返回一个不是从 (0;0) 点开始的矩形,在这种情况下需要进行一些调整让它发挥作用。

关于image - 更改单个像素的颜色 - Golang 图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36573413/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com