doutan8775 2017-09-26 23:19
浏览 353
已采纳

Go的PNG编码速度很慢

I'm acquiring frames from my built in webcam with go-opencv. The time it takes to acquire an image from the camera is ~50ms. The time to encode the PNG is ~300ms. Encoding a JPEG is 3x faster, but still horribly slow.

Why is this running so slowly?

Note: I've written similar code against NodeJS, executed on the same machine, and have absolutely no problem hitting 30fps w/ additional image processing. For me, this removes hardware issues from the equation.

My code looks like this:

import (
    "fmt"
    "image/png"

    "github.com/lazywei/go-opencv/opencv"
)

camera := opencv.NewCameraCapture(0)
if camera == nil {
    panic("Unable to open camera.")
}
defer camera.Release()

for {
    if camera.GrabFrame() {
        img := camera.RetrieveFrame(1)
        if img != nil {
            frame := img.ToImage()
            buffer := new(bytes.Buffer)
            png.Encode(buffer, frame)
        } else {
            fmt.Println("Unable to capture frame")
        }
    }

}
  • 写回答

2条回答 默认 最新

  • doumang20060820 2017-09-27 13:33
    关注

    Disabling compression improves encoding performance by an order of magnitude on my machine. That may be a start if you don't want to look for png packages outside the standard library.

    I also tried the BufferPool (new in Go 1.9), but it didn't make a difference compared to an encoder with a nil BufferPool. Perhaps I did it wrong. The docs are unfortunately very, erm, concise.

    package main
    
    import (
        "bytes"
        "image"
        "image/png"
        "os"
        "testing"
    )
    
    func BenchmarkPNG_Encode(b *testing.B) {
        img, buf := loadImage(b)
    
        b.ResetTimer()
    
        for i := 0; i < b.N; i++ {
                buf.Reset()
                png.Encode(buf, img)
        }
    }
    
    func BenchmarkPNG_Encoder(b *testing.B) {
        img, buf := loadImage(b)
        enc := &png.Encoder{}
    
        b.ResetTimer()
    
        for i := 0; i < b.N; i++ {
                buf.Reset()
                enc.Encode(buf, img)
        }
    }
    
    func BenchmarkPNG_Encoder_NoCompression(b *testing.B) {
        img, buf := loadImage(b)
        enc := &png.Encoder{
                CompressionLevel: png.NoCompression,
        }
    
        b.ResetTimer()
    
        for i := 0; i < b.N; i++ {
                buf.Reset()
                enc.Encode(buf, img)
        }
    }
    
    func loadImage(b *testing.B) (image.Image, *bytes.Buffer) {
        // foo.png PNG 1920x1053 1920x1053+0+0 8-bit sRGB 251KB 0.000u 0:00.000
        f, err := os.Open("foo.png")
        if err != nil {
                b.Fatal(err)
        }
    
        img, err := png.Decode(f)
        if err != nil {
                b.Fatal(err)
        }
        f.Close()
    
        buf := &bytes.Buffer{}
        // grow the buffer once
        (&png.Encoder{CompressionLevel: png.NoCompression}).Encode(buf, img)
    
        return img, buf
    }
    

    Again, this was on my machine with a roughly 1920x1080 pixel image -- a random screenshot; not sure how much this will differ from, say, a photo. YMMV.

    $ go test -v -bench . -benchmem 
    goos: linux
    goarch: amd64
    BenchmarkPNG_Encode-8                         10         119289121 ns/op          884964 B/op         38 allocs/op
    BenchmarkPNG_Encoder-8                        10         118001658 ns/op          884932 B/op         37 allocs/op
    BenchmarkPNG_Encoder_NoCompression-8         100          13050664 ns/op          807156 B/op        212 allocs/op
    

    It's interesting that no compression causes many more allocations than with compression though.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 Python3.5 相关代码写作
  • ¥20 测距传感器数据手册i2c
  • ¥15 RPA正常跑,cmd输入cookies跑不出来
  • ¥15 求帮我调试一下freefem代码
  • ¥15 matlab代码解决,怎么运行
  • ¥15 R语言Rstudio突然无法启动
  • ¥15 关于#matlab#的问题:提取2个图像的变量作为另外一个图像像元的移动量,计算新的位置创建新的图像并提取第二个图像的变量到新的图像
  • ¥15 改算法,照着压缩包里边,参考其他代码封装的格式 写到main函数里
  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)