如何使用Go编程语言读取彩色的PNG文件并将其输出为灰度图像?

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

how to read a png file in color and output as gray scale using the Go programming language?

问题

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

英文:

How do I read in a color .png file in the Go programming language, and output it as an 8-bit grayscale image?

答案1

得分: 14

下面的程序接受一个输入文件名和一个输出文件名。它打开输入文件,解码它,将其转换为灰度图像,然后将其编码到输出文件中。

这个程序不是特定于PNG格式的,但是要支持其他文件格式,你需要导入正确的图像包。例如,要添加JPEG支持,你可以在导入列表中添加_ "image/jpeg"

如果你只想支持PNG格式,那么你可以直接使用image/png.Decode而不是image.Decode

package main

import (
	"image"
	"image/png" // 使用image包注册PNG格式
	"os"
)

func main() {
	infile, err := os.Open(os.Args[1])
	if err != nil {
		// 用真正的错误处理替换这部分
		panic(err.String())
	}
	defer infile.Close()

	// Decode会自动确定文件中的图像类型。
	// 我们只需要确保导入了我们想要的所有图像包。
	src, _, err := image.Decode(infile)
	if err != nil {
		// 用真正的错误处理替换这部分
		panic(err.String())
	}

	// 创建一个新的灰度图像
	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)
		}
	}

	// 将灰度图像编码到输出文件中
	outfile, err := os.Create(os.Args[2])
	if err != nil {
		// 用真正的错误处理替换这部分
		panic(err.String())
	}
	defer outfile.Close()
	png.Encode(outfile, gray)
}
英文:

The program below takes an input file name and an output file name. It opens the input file, decodes it, converts it to grayscale, then encodes it to the output file.

Thie program isn't specific to PNGs, but to support other file formats you'd have to import the correct image package. For example, to add JPEG support you could add to the imports list _ &quot;image/jpeg&quot;.

If you only want to support PNG, then you can use image/png.Decode directly instead of image.Decode.

package main

import (
	&quot;image&quot;
	&quot;image/png&quot; // register the PNG format with the image package
	&quot;os&quot;
)

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 &lt; w; x++ {
		for y := 0; y &lt; 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)
}

答案2

得分: 14

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

每次访问Converted时都会进行转换,如果图像将被多次查看,可能会稍微降低性能,但另一方面它很酷且可组合。

package main

import (
	"image"
	_ "image/jpeg" // 注册JPEG格式
	"image/png"    // 注册PNG格式
	"image/color"
	"log"
	"os"
)

// Converted 实现了image.Image接口,所以你可以假装它是转换后的图像。
type Converted struct {
	Img image.Image
	Mod color.Model
}

// 我们返回新的颜色模型...
func (c *Converted) ColorModel() color.Model{
	return c.Mod
}

// ...但保留原始边界
func (c *Converted) Bounds() image.Rectangle{
	return c.Img.Bounds()
}

// At将调用转发给原始图像,然后请求颜色模型进行转换。
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("需要两个参数")}
	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)
	}

	// 由于Converted实现了image,现在这是一张灰度图像
	gr := &Converted{img, color.GrayModel}
	// 或者像这样将其转换为黑白图像。
	// 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)
}
英文:

I had this problem myself and came up with a slightly different solution. I introduced a new type, Converted, which implements image.Image. Converted consists of the original image and the color.Model.

Converted does the conversion every time it is accessed, which could give
slightly worse performance if the image will be viewed multiple times, but on the other hand it is cool and composable.

package main
import (
&quot;image&quot;
_ &quot;image/jpeg&quot; // Register JPEG format
&quot;image/png&quot;    // Register PNG  format
&quot;image/color&quot;
&quot;log&quot;
&quot;os&quot;
)
// 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(&quot;Needs two arguments&quot;)}
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 := &amp;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 := &amp;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)
}

答案3

得分: 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 {
		// 替换这部分为真正的错误处理
		panic(err.Error())
	}
	defer infile.Close()

	// Decode会自动确定文件中的图像类型。
	// 我们只需要确保导入了我们想要的所有图像包。
	src, _, err := image.Decode(infile)
	if err != nil {
		// 替换这部分为真正的错误处理
		panic(err.Error())
	}

	// 创建一个新的灰度图像
	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)
		}
	}

	// 将灰度图像编码为输出文件
	outfilename := "result.png"
	outfile, err := os.Create(outfilename)
	if err != nil {
		// 替换这部分为真正的错误处理
		panic(err.Error())
	}
	defer outfile.Close()
	png.Encode(outfile, gray)
}

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

英文:

@EvanShaw 's snippet does not work now,(may be some golang API has change) I adapt it as below. sadly does output a grayscale image but the content is messy, currently I don't know why. I provide it here for your reference.

	package main
import (
&quot;image&quot;
&quot;image/color&quot;
&quot;image/png&quot;
&quot;math&quot;
&quot;os&quot;
)
func main() {
filename := &quot;dir/to/myfile/somefile.png&quot;
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 &lt; w; x++ {
for y := 0; y &lt; 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 := &quot;result.png&quot;
outfile, err := os.Create(outfilename)
if err != nil {
// replace this with real error handling
panic(err.Error())
}
defer outfile.Close()
png.Encode(outfile, gray)
}

and by the way, golang wouldn't able to automatically decode image file, we need to directly use image type's Decode method.

答案4

得分: 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()
// 必须明确使用jpeg.Decode(),否则会遇到未知格式错误
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)
}
英文:

Luckily I found this, and it works!
https://godoc.org/github.com/harrydb/go/img/grayscale#Convert

A fully working example as follows:

package main
import (
&quot;github.com/harrydb/go/img/grayscale&quot;
&quot;image/jpeg&quot;
&quot;image/png&quot;
&quot;os&quot;
)
func main() {
filename := &quot;dir/to/myfile/afile.jpg&quot;
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 := &quot;result.png&quot;
outfile, err := os.Create(outfilename)
if err != nil {
panic(err.Error())
}
defer outfile.Close()
png.Encode(outfile, gray)
}

答案5

得分: -5

简单的方法是使用英特尔的OpenCV库(开源)。谷歌一下如何使用OpenCV读取图像,你会得到详细的信息。

英文:

Easy way is use Intel OpenCV library (opensource).Google how to use opencv to read images. You will get details.

huangapple
  • 本文由 发表于 2012年1月2日 11:06:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/8697095.html
匿名

发表评论

匿名网友

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

确定