从 Golang image.Image 检索像素数据时,img.At() 或 rgba.Pix() 更快/更好吗?

2023-12-19

阅读来自的答案从 golang image.Image 获取像素数组 https://stackoverflow.com/questions/33186783/get-a-pixel-array-from-from-golang-image-image,我看到像素RGBA检索有两种方法,通过img.At() and rgba.Pix().

使用哪个更好?是否应该始终使用其中一种,或者是否存在应使用其中一种而不是另一种的情况,反之亦然?


如果您的程序将进行需要大多数(如果不是全部)像素数据的计算,那么rgba.Pix()显着优于img.At()。如果您只需要图像中单个或几个像素的像素数据,请使用img.At()(计算的开销rgba.Pix()在这种情况下,先决条件太高)。

以下是各种测试负载的结果,每个负载的持续时间是 10 个样本的平均值。

Method 1x1 1000x667 3840x2160 1000x667 + computation 1000x667 only 5x5 accessed
img.At() 195ns 30.211071ms 294.885396ms 853.345043ms 42.431μs
rgba.Pix() 719ns 7.786029ms 77.700552ms 836.480063ms 6.791461ms

我们可以看到如何对于微小的 1x1 图像以及我们将 for 循环限制为上限 5 的图像,使用img.At()导致更快的执行时间。但是,对于获取每个像素的用例,rgba.Pix()带来更好的性能。随着总时间的增加以及之间的差异,我们对每个像素进行的计算越多,这种性能的改进就越不明显。img.At() and rgba.Pix()变得不那么明显,如“1000x667 + 计算”在上表中。

这是使用的测试代码:

func main() {
    resp, err := http.Get("IMAGE URL GOES HERE")
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    img, _, err := image.Decode(resp.Body)
    if err != nil {
        panic(err)
    }

    var start time.Time
    var duration time.Duration
    samples := 10
    var sum time.Duration

    fmt.Println("Samples: ", samples)
    sum = time.Duration(0)
    for i := 0; i < samples; i++ {
        start = time.Now()
        usingAt(img)
        duration = time.Since(start)
        sum += duration
    }
    fmt.Println("*** At avg: ", sum/time.Duration(samples))

    sum = time.Duration(0)
    for i := 0; i < samples; i++ {
        start = time.Now()
        usingPix(img)
        duration = time.Since(start)
        sum += duration
    }
    fmt.Println("*** Pix avg: ", sum/time.Duration(samples))
}

func usingAt(img image.Image) {
    bounds := img.Bounds()
    width, height := bounds.Max.X, bounds.Max.Y

    for y := 0; y < height; y++ {
        for x := 0; x < width; x++ {
            r, g, b, _ := img.At(x, y).RGBA()
            _ = uint8(r >> 8)
            _ = uint8(g >> 8)
            _ = uint8(b >> 8)
        }
    }
}

func usingPix(img image.Image, targetColor colorful.Color) {
    bounds := img.Bounds()
    width, height := bounds.Max.X, bounds.Max.Y

    rgba := image.NewRGBA(bounds)
    draw.Draw(rgba, bounds, img, bounds.Min, draw.Src)
    for y := 0; y < height; y++ {
        for x := 0; x < width; x++ {
            index := (y*width + x) * 4
            pix := rgba.Pix[index : index+4]
            _ = pix[0]
            _ = pix[1]
            _ = pix[2]
        }
    }
}

1000x667 仅 5x5 访问取代了height and width在 for 循环中使用 5 和 5,限制访问的像素数量。

1000x667 + 计算实际上通过比较每个像素与目标颜色的颜色距离来使用 RGB 值色彩缤纷 https://github.com/lucasb-eyer/go-colorful的DE2000计算。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 Golang image.Image 检索像素数据时,img.At() 或 rgba.Pix() 更快/更好吗? 的相关文章

  • 有没有办法在 VSCode 中保存时运行 go 测试,并将其输出到终端?

    现在我有几个项目在VSCode中运行 运行起来相当繁琐go test每次我编写新代码时 我宁愿立即看看我是否破坏了某些东西 我知道在 Javascript 中我可以在每次保存文件时运行测试 并将输出发送到终端 现在我正在使用 保存时运行 h
  • 如何在特定文件夹中运行 shell 命令

    我可以用这个out err exec Command git log Output 获取将在与可执行位置相同的路径中运行的命令的输出 如何指定要在哪个文件夹中运行命令 exec Command https golang org pkg os
  • 匿名结构和空结构

    http play golang org p vhaKi5uVmm http play golang org p vhaKi5uVmm package main import fmt var battle make chan string
  • GoLang ssh:尽管将其设置为 nil,但仍出现“必须指定 HosKeyCallback”错误

    我正在尝试使用 GoLang 连接到远程服务器 在客户端配置中 除了用户和密码之外 我将 HostKeyCallback 设置为 nil 以便它接受每个主机 config ssh ClientConfig User user HostKey
  • 在 Go 中初始化嵌入结构

    我有以下内容struct其中包含一个net http Request type MyRequest struct http Request PathParams map string string 现在我想初始化匿名内部结构http Req
  • 复杂数据类型作为 Go 中映射的键

    我正在尝试在 Go 中创建一个由大整数作为键的映射 effective Go 明确指出 结构体 数组和切片不能用作映射键 因为这些类型上没有定义相等性 这是有道理的 我当然可以将大整数转换为字符串并使用字符串作为键 但我在这里寻找更通用的解
  • 正确的文件扩展名或缩写是什么。 golang 的文本/模板?

    我正在考虑为其创建语法荧光笔 但我不知道这种特定类型模板的常规缩写 In 例子之一 http golang org pkg text template example Template helpers从文本 模板 godoc 中 它们引用
  • 将 time.Time 转换为字符串

    我正在尝试将数据库中的一些值添加到 string在围棋中 其中一些是时间戳 我收到错误 无法在数组元素中使用 U Created date 类型 time Time 作为类型字符串 我可以转换吗time Time to string typ
  • 直接从一个通道发送到另一个通道

    当从一个通道直接发送到另一个通道时 我偶然发现了令人惊讶的行为 package main import fmt func main my chan make chan string chan of chans make chan chan
  • 如何同时使用 LoadHTMLGlob 和 LoadHTMLFiles

    我想要来自不同子目录的分隔符逻辑模板templates文件夹 下面是我的templates文件夹 templates authentication login gohtml logout gohtml index gohtml profil
  • 在 Gorilla Mux 中嵌套子路由器

    我一直在使用gorilla mux https github com gorilla mux满足我的路由需求 但我注意到一个问题 当我嵌套多个子路由器时它不起作用 这是示例 func main r mux NewRouter StrictS
  • select 语句是否保证通道选择的顺序?

    继从这个答案 https stackoverflow com a 25795236 274460 如果一个 goroutine 在两个通道上进行选择 是否保证通道的选择顺序与其发送的顺序相同 我对发送者是单线程的情况特别感兴趣 例如 是否保
  • 如何读取大型平面文件

    我有一个平面文件 其中包含 339276 行文本 大小为 62 1 MB 我试图读入所有行 根据我所拥有的某些条件解析它们 然后将它们插入数据库 我最初尝试使用 bufio Scan 循环和 bufio Text 来获取该行 但缓冲区空间不
  • 解压文件的简单方法

    有没有一种简单的方法可以用 Go 解压文件 现在我的代码是 func Unzip src dest string error r err zip OpenReader src if err nil return err defer r Cl
  • 错误:标准包中非标准导入“gopkg.in/yaml.v2”

    我正在尝试从以下位置导入 go yamlhttps github com go yaml yaml https github com go yaml yaml 并且我发现了一个 Google 没有提供帮助的错误 I ran go get g
  • 关闭长度未知的通道

    当不了解频道时我无法关闭频道 length package main import fmt time func gen ch chan int var i int for time Sleep time Millisecond 10 ch
  • Go 编译器有窗口化设置选项吗?

    我正在使用 Go 6g 编译 GTK 应用程序 我想知道是否有编译器 链接器选项使其成为 Windows 可执行文件而不是控制台可执行文件 MinGW 有一个 mwindows 选项来实现此目的 目前我必须使用十六进制编辑器手动更改 PE
  • 关于编写惯用的 Golang 的建议

    我正在掌握 Golang 的做事方式 首先是一些示例代码 package main import log os func logIt s string f os OpenFile errors log os O RDWR os O CREA
  • “http:多个response.WriteHeader调用”有什么不好的影响?

    尽管我发现 http 多个响应 WriteHeader 调用 例外 但我的服务器表现良好 此异常不会导致我的服务器出现恐慌或行为异常 我进行了很多搜索 但只找到了如何解决这个问题 没有文档描述异常的不良影响 有人可以帮我找出为什么 http
  • 云存储 API 的错误导入“系统调用”

    我正在按照以下说明进行操作https cloud google com appengine docs go googlecloudstorageclient download开始将一些代码从现已弃用的文件 API 迁移到新的 Cloud S

随机推荐