当前位置: 首页 > 面试题库 >

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

茹航
2023-03-14
问题内容

我想打开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.Imageimage.Image是一个接口,用于定义图像的只读视图:它不提供更改/绘制图像的方法。

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

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

如果(图像的动态类型)确实具有Set()方法,则可以使用类型断言并使用其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,但是在其At(x, y int) color.Color方法(返回/提供像素的颜色)中,您将返回如果该图像将是可变的,并在不更改图像的情况下返回原始图像的像素。

image.Image利用 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()方法中是不切实际的。为此,我们可以扩展我们MyImgSet()实现,以存储要更改的像素。示例实现:

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)点,在这种情况下,需要进行一些调整才能使其工作。



 类似资料:
  • 对于给定的多色PNG(带透明度),最好的/快速的惯用方式是什么: 创建一个重复的 关于SO有几个相关的问题,但是我还没有找到有效的方法。

  • 问题内容: 我想从我的Fluke机器人那里得到一张图像,并确定图像中每个像素的颜色。然后,如果像素大部分为红色,请将其更改为完全绿色。如果像素大部分是绿色,请将其更改为完全蓝色。如果像素大部分是蓝色,请将其更改为完全红色。这是我能够做的,但是我无法使它工作以获取必须更改的图像。没有语法错误,这只是语义上的麻烦。我正在使用python。 我尝试的代码: 我也保存了如下图片: 问题答案: 我假设您正在

  • 本文向大家介绍iOS 更改图像的颜色,包括了iOS 更改图像的颜色的使用技巧和注意事项,需要的朋友参考一下 示例            

  • 我从服务器接收图像,然后根据用户选择的颜色,图像颜色将发生变化。 我尝试了以下方法: 我得到了与我的目标相反的结果(UIImage外部的白色是用所选颜色着色的)。 出了什么问题? 在这个问题上我也需要这样做,提供的解决方案不能解决我的问题。如何更改iOS和WatchKit中的图像颜色

  • 问题内容: 我需要在python中更改图像的像素颜色。除了像素值(255,0,0)红色外,我需要将每个像素颜色值更改为黑色(0,0,0)。我尝试了以下代码,但没有帮助。 问题答案: 参见此Wikibook:https : //zh.wikibooks.org/wiki/Python_Imaging_Library/Editing_Pixels 修改该代码以适合您的问题:

  • 问题内容: 对于给定的多色PNG (具有透明度),什么是最好的/快速惯用的方法: 创建一个副本 在副本中找到所有黑色像素并将其更改为红色 (返回修改后的副本) 关于SO有一些相关的问题,但我一直无法找到可行的方法。 问题答案: 您必须提取图像的像素缓冲区,然后可以循环浏览,并根据需要更改像素。最后,从缓冲区创建一个新图像。 在Swift 3中,这看起来像: