11

如何在 Go 编程语言中读取彩色 .png 文件,并将其输出为 8 位灰度图像?

4

5 回答 5

14

下面的程序采用输入文件名和输出文件名。它打开输入文件,对其进行解码,将其转换为灰度,然后将其编码为输出文件。

该程序并非特定于 PNG,但要支持其他文件格式,您必须导入正确的图像包。例如,要添加 JPEG 支持,您可以添加到 imports list _ "image/jpeg"

如果你只想支持 PNG,那么你可以直接使用image/png.Decode代替image.Decode

package main

import (
    "image"
    "image/png" // register the PNG format with the image package
    "os"
)

func main() {
    infile, err := os.Open(os.Args[1])
    if err != nil {
        // replace this with real error handling
        panic(err.String())
    }
    defer infile.Close()

    // Decode will figure out what type of image is in the file on its own.
    // We just have to be sure all the image packages we want are imported.
    src, _, err := image.Decode(infile)
    if err != nil {
        // replace this with real error handling
        panic(err.String())
    }

    // Create a new grayscale image
    bounds := src.Bounds()
    w, h := bounds.Max.X, bounds.Max.Y
    gray := image.NewGray(w, h)
    for x := 0; x < w; x++ {
        for y := 0; y < h; y++ {
            oldColor := src.At(x, y)
            grayColor := image.GrayColorModel.Convert(oldColor)
            gray.Set(x, y, grayColor)
        }
    }

    // Encode the grayscale image to the output file
    outfile, err := os.Create(os.Args[2])
    if err != nil {
        // replace this with real error handling
        panic(err.String())
    }
    defer outfile.Close()
    png.Encode(outfile, gray)
}
于 2012-01-02T03:30:10.820 回答
11

我自己也遇到了这个问题,并提出了一个稍微不同的解决方案。我介绍了一种新类型Converted,它实现了image.Image. Converted由原始图像和color.Model.

Converted每次访问时都会进行转换,这可能会导致性能稍差,但另一方面它很酷且可组合。

package main

import (
    "image"
    _ "image/jpeg" // Register JPEG format
    "image/png"    // Register PNG  format
    "image/color"
    "log"
    "os"
)

// Converted implements image.Image, so you can
// pretend that it is the converted image.
type Converted struct {
    Img image.Image
    Mod color.Model
}

// We return the new color model...
func (c *Converted) ColorModel() color.Model{
    return c.Mod
}

// ... but the original bounds
func (c *Converted) Bounds() image.Rectangle{
    return c.Img.Bounds()
}

// At forwards the call to the original image and
// then asks the color model to convert it.
func (c *Converted) At(x, y int) color.Color{
    return c.Mod.Convert(c.Img.At(x,y))
}

func main() {
    if len(os.Args) != 3 { log.Fatalln("Needs two arguments")}
    infile, err := os.Open(os.Args[1])
    if err != nil {
        log.Fatalln(err)
    }
    defer infile.Close()

    img, _, err := image.Decode(infile)
    if err != nil {
        log.Fatalln(err)
    }

    // Since Converted implements image, this is now a grayscale image
    gr := &Converted{img, color.GrayModel}
    // Or do something like this to convert it into a black and
    // white image.
    // bw := []color.Color{color.Black,color.White}
    // gr := &Converted{img, color.Palette(bw)}


    outfile, err := os.Create(os.Args[2])
    if err != nil {
        log.Fatalln(err)
    }
    defer outfile.Close()

    png.Encode(outfile,gr)
}
于 2013-06-12T22:22:40.580 回答
1

@EvanShaw 的片段现在不起作用,(可能是一些 golang API 发生了变化)我将其改编如下。可悲的是确实输出了灰度图像,但内容很乱,目前我不知道为什么。我在这里提供给你参考。

    package main

    import (
        "image"
        "image/color"
        "image/png"
        "math"
        "os"
    )

    func main() {
        filename := "dir/to/myfile/somefile.png"
        infile, err := os.Open(filename)
        if err != nil {
            // replace this with real error handling
            panic(err.Error())
        }
        defer infile.Close()

        // Decode will figure out what type of image is in the file on its own.
        // We just have to be sure all the image packages we want are imported.
        src, _, err := image.Decode(infile)
        if err != nil {
            // replace this with real error handling
            panic(err.Error())
        }

        // Create a new grayscale image
        bounds := src.Bounds()
        w, h := bounds.Max.X, bounds.Max.Y
        gray := image.NewGray(image.Rectangle{image.Point{0, 0}, image.Point{w, h}})
        for x := 0; x < w; x++ {
            for y := 0; y < h; y++ {
                oldColor := src.At(x, y)
                r, g, b, _ := oldColor.RGBA()
                avg := 0.2125*float64(r) + 0.7154*float64(g) + 0.0721*float64(b)
                grayColor := color.Gray{uint8(math.Ceil(avg))}
                gray.Set(x, y, grayColor)
            }
        }

        // Encode the grayscale image to the output file
        outfilename := "result.png"
        outfile, err := os.Create(outfilename)
        if err != nil {
            // replace this with real error handling
            panic(err.Error())
        }
        defer outfile.Close()
        png.Encode(outfile, gray)
    }

顺便说一句,golang不能自动解码图像文件,我们需要直接使用图像类型的Decode方法。

于 2014-11-17T13:58:02.570 回答
0

幸运的是,我找到了这个,并且它有效! https://godoc.org/github.com/harrydb/go/img/grayscale#Convert

一个完整的工作示例如下:

package main

import (
    "github.com/harrydb/go/img/grayscale"
    "image/jpeg"
    "image/png"
    "os"
)

func main() {
    filename := "dir/to/myfile/afile.jpg"
    infile, err := os.Open(filename)
    if err != nil {
        panic(err.Error())
    }
    defer infile.Close()

    // Must specifically use jpeg.Decode() or it 
    // would encounter unknown format error
    src, err := jpeg.Decode(infile)
    if err != nil {
        panic(err.Error())
    }



    gray := grayscale.Convert(src, grayscale.ToGrayLuminance)

    outfilename := "result.png"
    outfile, err := os.Create(outfilename)
    if err != nil {
        panic(err.Error())
    }
    defer outfile.Close()
    png.Encode(outfile, gray)
}
于 2014-11-17T14:38:02.180 回答
-5

简单的方法是使用英特尔 OpenCV 库(开源)。谷歌如何使用 opencv 读取图像。您将获得详细信息。

于 2012-01-02T08:06:09.583 回答