将RGBA图像高效地转换为RGB字节数组

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

Convert RBGA image to RGB byte array in effcient way

问题

我有一个C库和一个函数,它期望一个指向字节数组的指针,该数组包含一个以RGB格式表示的24位位图。Alpha通道不重要,可以截断。我尝试了类似这样的代码:

func load(filePath string) *image.RGBA {
    imgFile, err := os.Open(filePath)
    if err != nil {
        fmt.Printf("无法读取文件 %v\n", err)
    }
    defer imgFile.Close()

    img, _, err := image.Decode(imgFile)
    if err != nil {
        fmt.Printf("无法解码文件 %v\n", err)
    }
    return img.(*image.RGBA)
}

img := load("myimg.png")

bounds := img.Bounds()
width, height := bounds.Max.X, bounds.Max.Y

// 转换为RGB?可能不需要...
newImg := image.NewNRGBA(image.Rect(0, 0, width, height))
draw.Draw(newImg, newImg.Bounds(), img, bounds.Min, draw.Src)
// 将图像指针传递给C函数。
C.PaintOnImage(unsafe.Pointer(&newImg.Pix[0]), C.int(newImg.Bounds().Dy()), C.int(newImg.Bounds().Dx())

然而,似乎NRGBA也是基于每像素4个字节的。我可以通过使用GoCV来解决这个问题,但对于这么简单的任务来说,这似乎有点过度。在Go中有没有一种简单高效的方法来做到这一点?

英文:

I have a C library and function that expects a pointer to byte array that contains a 24 bit bitmap in RGB format. Alpha channel is not important and can be truncated. I've tried something like this:

func load(filePath string) *image.RGBA {
	imgFile, err := os.Open(filePath)
	if err != nil {
		fmt.Printf("Cannot read file %v\n", err)
	}
	defer imgFile.Close()

	img, _, err := image.Decode(imgFile)
	if err != nil {
		fmt.Printf("Cannot decode file %v\n", err)
	}
	return img.(*image.RGBA)
}

	img := load("myimg.png")

	bounds := img.Bounds()
	width, height := bounds.Max.X, bounds.Max.Y

    // Convert to RGB? Probably not...
	newImg := image.NewNRGBA(image.Rect(0, 0, width, height))
	draw.Draw(newImg, newImg.Bounds(), img, bounds.Min, draw.Src)
    // Pass image pointer to C function.
    C.PaintOnImage(unsafe.Pointer(&newImg.Pix[0]), C.int(newImg.Bounds().Dy()), C.int(newImg.Bounds().Dx())

However, it seems that NRGBA is also built on 4 bytes per pixel. I could solve this probably by using GoCV but this seems like overkill for such simple task. Is there a way to do this in a simple and efficient manner in Go?

答案1

得分: 0

标准库中没有RGB图像类型,但你可以很容易地组装RGB数组:

bounds := img.Bounds()
rgb := make([]byte, bounds.Dx()*bounds.Dy()*3)
idx := 0
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
    for x := bounds.Min.X; x < bounds.Max.X; x++ {
        offs := img.PixOffset(x, y)
        copy(rgb[idx:], img.Pix[offs:offs+3])
        idx += 3
    }
}

img.Pix 数据保存了4字节的RGBA值。上面的代码只是复制了所有像素的前3字节RGB值。

由于Pix数组中的行是连续的,你可以通过每行只调用一次PixOffset并且每个像素前进4字节来改进上面的代码。手动复制3字节可能比调用copy()函数更快(如果对你很重要,可以进行基准测试):

bounds := img.Bounds()
rgb := make([]byte, bounds.Dx()*bounds.Dy()*3)
idx := 0

for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
    offs := img.PixOffset(bounds.Min.X, y)
    for x := bounds.Min.X; x < bounds.Max.X; x++ {
        rgb[idx+0] = img.Pix[offs+0]
        rgb[idx+1] = img.Pix[offs+1]
        rgb[idx+2] = img.Pix[offs+2]
        idx += 3
        offs += 4
    }
}
英文:

There is no RGB image type in the standard library, but you can assemble your RGB array pretty easily:

bounds := img.Bounds()
rgb := make([]byte, bounds.Dx()*bounds.Dy()*3)
idx := 0
for y := bounds.Min.Y; y &lt; bounds.Max.Y; y++ {
	for x := bounds.Min.X; x &lt; bounds.Max.X; x++ {
		offs := img.PixOffset(x, y)
		copy(rgb[idx:], img.Pix[offs:offs+3])
		idx += 3
	}
}

The img.Pix data holds the 4-byte RGBA values. The code above just copies the leading 3-byte RGB values of all pixels.

Since lines are continuous in the Pix array, you can improve the above code by only calling PixOffset onces per line, and advance by 4 bytes for every pixel. Also manually copying 3 bytes may be faster than calling copy() (benchmark if it matters to you):

bounds := img.Bounds()
rgb := make([]byte, bounds.Dx()*bounds.Dy()*3)
idx := 0

for y := bounds.Min.Y; y &lt; bounds.Max.Y; y++ {
	offs := img.PixOffset(bounds.Min.X, y)
	for x := bounds.Min.X; x &lt; bounds.Max.X; x++ {
		rgb[idx+0] = img.Pix[offs+0]
		rgb[idx+1] = img.Pix[offs+1]
		rgb[idx+2] = img.Pix[offs+2]
		idx += 3
		offs += 4
	}
}

huangapple
  • 本文由 发表于 2023年1月13日 18:03:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/75107616.html
匿名

发表评论

匿名网友

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

确定