计算 GPU 上的彩色像素 - 理论

2024-02-02

我有一张 128 x 128 像素的图像。

它被分解为 8 x 8 的网格。

每个网格块包含 16 x 16 像素。

要求

我想计算我的图像包含多少个黑色像素。

直接的方法:

I could通过逐行、逐列检查整个图像并检查像素是否为黑色来实现此目的。

GPU方式

...但我想知道如果使用 GPU,我可以将图像分解为块/块并计算每个块中的所有像素,然后对结果求和。

例如:

如果你看一下图像的左上角:

第一个块“A1”(A 行,1 列)包含 16 x 16 像素的网格,我通过手动计数知道,有 16 个黑色像素。

第二块:'A2',(A行,2列)包含一个16 x 16像素的网格,我知道通过手动计数,有62个黑色像素。

此示例的所有其他块都是空白/空的。

如果我通过程序运行图像,我应该得到答案:16 + 62 = 78 黑色像素。

推理

据我了解,GPU 可以并行处理大量数据,有效地在分布在多个 GPU 线程的数据块上运行一个小程序。 我不担心速度/性能,我只是想知道 GPU 是否可以做到这一点?


事实上,通用 GPU(例如从 A8 开始的 Apple 设备中的 GPU)不仅有能力,而且旨在能够解决此类并行数据处理问题。

Apple 在其平台中使用 Metal 引入了数据并行处理,只需一些简单的代码,您就可以使用 GPU 解决像您这样的问题。即使这也可以使用其他框架来完成,我也包含了一些 Metal+Swift 案例的代码作为概念证明。

以下内容在 OS X Sierra 上作为 Swift 命令行工具运行,并使用 Xcode 9 构建(是的,我知道它是测试版)。您可以从我的网站获得完整的项目github 仓库 https://github.com/pevasquez/MetalCounter/tree/master.

As main.swift:

import Foundation
import Metal
import CoreGraphics
import AppKit

guard FileManager.default.fileExists(atPath: "./testImage.png") else {
    print("./testImage.png does not exist")
    exit(1)
}

let url = URL(fileURLWithPath: "./testImage.png")
let imageData = try Data(contentsOf: url)

guard let image = NSImage(data: imageData),
    let imageRef = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else {
    print("Failed to load image data")
    exit(1)
}

let bytesPerPixel = 4
let bytesPerRow = bytesPerPixel * imageRef.width

var rawData = [UInt8](repeating: 0, count: Int(bytesPerRow * imageRef.height))

let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue).union(.byteOrder32Big)
let colorSpace = CGColorSpaceCreateDeviceRGB()

let context = CGContext(data: &rawData,
                        width: imageRef.width,
                        height: imageRef.height,
                        bitsPerComponent: 8,
                        bytesPerRow: bytesPerRow,
                        space: colorSpace,
                        bitmapInfo: bitmapInfo.rawValue)

let fullRect = CGRect(x: 0, y: 0, width: CGFloat(imageRef.width), height: CGFloat(imageRef.height))
context?.draw(imageRef, in: fullRect, byTiling: false)

// Get access to iPhone or iPad GPU
guard let device = MTLCreateSystemDefaultDevice() else {
    exit(1)
}

let textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(
    pixelFormat: .rgba8Unorm,
    width: Int(imageRef.width),
    height: Int(imageRef.height),
    mipmapped: true)

let texture = device.makeTexture(descriptor: textureDescriptor)

let region = MTLRegionMake2D(0, 0, Int(imageRef.width), Int(imageRef.height))
texture.replace(region: region, mipmapLevel: 0, withBytes: &rawData, bytesPerRow: Int(bytesPerRow))

// Queue to handle an ordered list of command buffers
let commandQueue = device.makeCommandQueue()

// Buffer for storing encoded commands that are sent to GPU
let commandBuffer = commandQueue.makeCommandBuffer()

// Access to Metal functions that are stored in Shaders.metal file, e.g. sigmoid()
guard let defaultLibrary = device.makeDefaultLibrary() else {
    print("Failed to create default metal shader library")
    exit(1)
}

// Encoder for GPU commands
let computeCommandEncoder = commandBuffer.makeComputeCommandEncoder()

// hardcoded to 16 for now (recommendation: read about threadExecutionWidth)
var threadsPerGroup = MTLSize(width:16, height:16, depth:1)
var numThreadgroups = MTLSizeMake(texture.width / threadsPerGroup.width,
                                  texture.height / threadsPerGroup.height,
                                  1);

// b. set up a compute pipeline with Sigmoid function and add it to encoder
let countBlackProgram = defaultLibrary.makeFunction(name: "countBlack")
let computePipelineState = try device.makeComputePipelineState(function: countBlackProgram!)
computeCommandEncoder.setComputePipelineState(computePipelineState)


// set the input texture for the countBlack() function, e.g. inArray
// atIndex: 0 here corresponds to texture(0) in the countBlack() function
computeCommandEncoder.setTexture(texture, index: 0)

// create the output vector for the countBlack() function, e.g. counter
// atIndex: 1 here corresponds to buffer(0) in the Sigmoid function
var counterBuffer = device.makeBuffer(length: MemoryLayout<UInt32>.size,
                                        options: .storageModeShared)
computeCommandEncoder.setBuffer(counterBuffer, offset: 0, index: 0)

computeCommandEncoder.dispatchThreadgroups(numThreadgroups, threadsPerThreadgroup: threadsPerGroup)

computeCommandEncoder.endEncoding()
commandBuffer.commit()
commandBuffer.waitUntilCompleted()

// a. Get GPU data
// outVectorBuffer.contents() returns UnsafeMutablePointer roughly equivalent to char* in C
var data = NSData(bytesNoCopy: counterBuffer.contents(),
                  length: MemoryLayout<UInt32>.size,
                  freeWhenDone: false)
// b. prepare Swift array large enough to receive data from GPU
var finalResultArray = [UInt32](repeating: 0, count: 1)

// c. get data from GPU into Swift array
data.getBytes(&finalResultArray, length: MemoryLayout<UInt>.size)

print("Found \(finalResultArray[0]) non-white pixels")

// d. YOU'RE ALL SET!

另外,在Shaders.metal:

#include <metal_stdlib>
using namespace metal;

kernel void
countBlack(texture2d<float, access::read> inArray [[texture(0)]],
           volatile device uint *counter [[buffer(0)]],
           uint2 gid [[thread_position_in_grid]]) {

    // Atomic as we need to sync between threadgroups
    device atomic_uint *atomicBuffer = (device atomic_uint *)counter;
    float3 inColor = inArray.read(gid).rgb;
    if(inColor.r != 1.0 || inColor.g != 1.0 || inColor.b != 1.0) {
        atomic_fetch_add_explicit(atomicBuffer, 1, memory_order_relaxed);
    }
}

我通过这个问题了解了一些有关 Metal 和数据并行计算的知识,因此大部分代码都是从网上文章中用作样板并进行编辑的。请花时间访问下面提到的来源以获取更多示例。另外,代码几乎是针对这个特定问题进行硬编码的,但是您在调整它时应该不会遇到很多麻烦。

Sources:

http://flexmonkey.blogspot.com.ar/2016/05/histogram-equalization-with-metal.html http://flexmonkey.blogspot.com.ar/2016/05/histogram-equalisation-with-metal.html

http://metalbyexample.com/introduction-to-compute/ http://metalbyexample.com/introduction-to-compute/

http://memkite.com/blog/2014/12/15/data-parallel-programming-with-metal-and-swift-for-iphoneipad-gpu/ http://memkite.com/blog/2014/12/15/data-parallel-programming-with-metal-and-swift-for-iphoneipad-gpu/

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

计算 GPU 上的彩色像素 - 理论 的相关文章

  • SwiftUI TabbedView 仅显示第一个选项卡的内容

    我正在尝试建立一个TabbedView使用以下简单代码 TabbedView Text Hello world tabItemLabel Text Hello Text Foo bar tabItemLabel Text Foo 运行时 两
  • 我可以在 R 中并行读取 1 个大 CSV 文件吗? [复制]

    这个问题在这里已经有答案了 我有一个很大的 csv 文件 需要很长时间才能阅读 我可以使用 parallel 或相关的包在 R 中并行读取此内容吗 我尝试过使用 mclapply 但它不起作用 根据OP的评论 fread来自data tab
  • iOS 意外的平台状况(预期的“os”、“arch”或“swift”)-可达性

    我刚刚更新了我的 pod 更新后Reachability导致错误 意外的平台状况 预期的 os arch 或 swift I tried to build and clean but it does not work what s the
  • Swift iOS 9.2 中的每日本地通知

    尝试快速发送每日本地通知 然而 由于某种原因 它只是每分钟发送一次 我希望第一个通知在应用程序打开后 30 分钟发送 然后每天重复此通知 在 swift fie 中我有以下代码 每日通知代码 同时在应用程序委托中添加部分 让 Date NS
  • 数组扩展以按值删除对象

    extension Array func removeObject
  • 如何缓存单元格并重用每个单元格中嵌入了 avplayers 的集合视图中的单元格?

    基本上我想做的是缓存单元格并让视频继续播放 当用户滚动回到单元格时 视频应该只从播放的位置显示 问题是玩家被移除并且单元格最终出现在随机单元格上 而不是其指定区域 您需要有两个视频才能正常工作 我从这里下载了视频https commonda
  • Xcode 8.2 更新后二进制文件无效

    我今天尝试在更新到 Xcode 8 2 后向我的应用程序推送更新 但收到无效的二进制错误 我以前从未见过这个 我的应用程序的 iOS 部署目标是 iOS 9 0 有谁见过这个错误或知道如何修复它 这是电子邮件的内容 解释了二进制文件的无效内
  • 使用本地化故事板进行即时本地化

    我正在开发一个应用程序 它有一个切换按钮可以在英语和阿拉伯语之间切换 并且应该是动态的 我正在使用该方法https github com maximbilan ios language manager https github com ma
  • JavaScript 与 WKWebView 的同步本机通信

    使用 WKWebView 可以在 JavaScript 和 Swift Obj C 本机代码之间进行同步通信吗 这些是我尝试过但失败的方法 方法 1 使用脚本处理程序 WKWebView接收JS消息的新方式是使用委托方法userConten
  • Swift 3 中的 NSFetchedResultsController 删除缓存

    目前正在迁移到 swift 3 无法完全弄清楚解析器想要什么NSFetchedResultsController deleteCache withName rootCache 使用这种语法 我得到一个 Type String 构建时出现不符
  • iOS 以编程方式撤销位置服务权限

    有没有一个功能CLLocationManager or UIApplication撤销位置权限类似功能unregisterForRemoteNotifications撤销推送通知权限 The stopUpdatingLocationCLLo
  • 如何在 Swift 中证明 String 类型的“写时复制”

    正如标题所说 我试图证明自己 Swift 中的 String 支持 COW copy on write 但我找不到证据 在尝试以下代码后 我在数组和字典上证明了 COW func address of object UnsafeRawPoi
  • swift 中带有字符的单引号

    我已经完成了 C C Java 这些语言告诉我字符用单引号括起来 主要是在遵守正确的语法时 但字符串是双引号的 Swift 的语法是否只允许字符位于单引号内 或者提供这种语法背后有一些有效的原因 逻辑 let char1 Character
  • 为什么使用自动布局时视图的框架宽度始终为 600 x 600

    我正在制作一个基本的扫雷应用程序 用于快速练习 娱乐 我想让板的尺寸 10 个图块宽 适应任何 iOS 屏幕 为此 我通过获取tileContainer view frame width和 10来设置每个图块的大小 我的问题是 tileCo
  • Swift:如何审查/过滤输入的脏话等文本?

    我只是想看看是否有一种既定的方法可以做到这一点 或者如何去做 我有一个文本字段 它本质上充当我的 iOs 应用程序中的表单 用户可以在其中发布内容 我不能让用户发布脏话 不恰当的废话 所以我想过滤掉他们输入的字符串包含这些单词之一的内容并显
  • IBDesignable 和 UITableViewCell

    我正在尝试利用 XCode 6 中 Swift 的 IBDesignable 功能来创建 UITableViewCell 的子类 我在 WWDC 演示和网络上看到 您可以使用框架来创建视图 UIView 的子类 然后可以将其用于自定义 UI
  • 在选择器视图中为行实现的标题没有改变字体?

    我尝试更改选择器视图中标题的字体 但由于某种原因我不能 我可以更改标题的颜色 但字体保持不变 func pickerView pickerView UIPickerView attributedTitleForRow row Int for
  • IOS Swift 从数组中搜索表

    我刚刚开始学习 swift 我正在研究 tableview 和 searchbar 功能 下面我有我的数组 它是水果列表 var fruits String Apple Green Pear Green Banana Yellow Oran
  • NSRange 到 Range

    我怎样才能转换NSRange to Range
  • iOS Swift 中断键盘事件

    我在拦截键盘事件时遇到问题 我已将我的 iOS 与 SteelSeries Free 游戏手柄控制器 连接 当连接到 iOS 时 它将被检测为蓝牙键盘 这是在我打开Notes时测试的 按下游戏手柄上的任何按钮都会写一个字母 我需要拦截此按钮

随机推荐

  • 暂时使用另一个功能分支的提交

    我的 git 流程如下所示 x x feature branch a master x x develop x x feature branch b 目前有一个提交和 PRbranch a to develop 我先等一下branch aP
  • 钥匙串无法正确导入 p12 并且系统钥匙串看起来很混乱

    I have p12 file of ios Development certificate I want to import it into my login keychain But when I double tap it goes
  • R ggplot2拼凑公共轴标签

    根据下面的代码和数据 是否可以拥有通用的图例标签而无需删除xlab and ylab来自ggplot代码使用patchwork 我之所以问这个问题是因为我有很多ggplots所以我觉得删除它并不理想xlab and ylab从每个ggplo
  • 如何在我的应用程序中显示网页?

    我需要从服务器端发送简单网页 带有图像 mht 或压缩网页文件夹 并在没有浏览器控制的情况下将其显示在我的 Android 应用程序的 UI 上 有人可以建议我如何在 Android 设备上继续执行此操作 要在应用程序中显示网页 有两种方法
  • 通过 POST 抓取 Bandcamp 粉丝收藏

    我一直在尝试抓取 Bandcamp 粉丝页面以获取他们购买的专辑列表 但我在有效地做到这一点时遇到了困难 我用 Selenium 写了一些东西 但它有点慢 所以我想学习一个解决方案 可以向网站发送 POST 请求并从那里解析 JSON 这是
  • 在 R 中打印 h2o 模型的“漂亮”表格

    有多个包用于R这有助于从统计模型输出中打印 漂亮 表格 LaTeX HTML TEXT 并轻松比较替代模型规范的结果 其中一些包是apsrtable xtable memisc texreg outreg and stargazer 示例请
  • 装饰器将函数状态从方法更改为函数

    更新 回答下面的内联问题 我有一个检查程序 一个目标是装饰器中的逻辑知道它正在装饰的函数是类方法还是常规函数 这以一种奇怪的方式失败了 以下是在 Python 2 6 中运行的代码 def decorate f print decorato
  • 使用 MapKit 将视图居中到用户位置的按钮

    MapKit 中是否有一个专用按钮可以将相机置于用户位置的中心 或者我是否必须手动创建按钮和切换mapView showsUserLocation true 这种方式运行良好 Swift 并且可以自定义按钮 class YourViewCo
  • Git 切换分支

    git 有一些东西我还没有搞懂 是分支 假设我有一个本地存储库A我从远程克隆的B 所以现在A检查主分支 所以当我从A它去B master B只是 github 上的一个克隆 C 为了保持同步 我时不时地从其他地方拉取C主分支 But now
  • 向 pentaho design studio 添加 jdbc 驱动程序并配置数据源

    我刚刚将 pentaho 的设计工作室集成到 BI 服务器中 有谁知道如何添加 mysql jdbc 驱动程序 我需要连接才能定义关系操作流程 在我的研究中我发现 http wiki bizcubed com au xwiki bin vi
  • js-bson 错误 - OpenShift 上的 Mosca(MQTT 代理)

    我一直在 OpenShift 上使用 NodeJS 进行一些工作 当我尝试在 Node 实例中运行 Mosca 服务器时遇到问题 我收到的错误如下 Error var lib openshift 5547bd284382ec394a0000
  • 获取Oracle子查询中order by后的第一行

    我有一个表学生 id 姓名 部门 年龄 分数 我想找到每个部门得分最高 在最年轻的学生中 的最年轻的学生 在 SQL Server 中 我可以使用以下 SQL select from student s1 where s1 id in se
  • 我应该避免 typedef,尝试使用原始名称并尽可能进行强制转换吗?

    我不确定这里的词汇 但希望我能让人理解 当我使用不太扎实的 C 知识来研究 winapi 时 我发现了很多 typedef 的东西 对我来说 这些东西似乎使问题变得过于复杂 并添加了我必须记住的另一件事 例如 UINT代替unsigned
  • 在python中创建用户定义类的对象集

    table set class GlobeLearningTable object def init self mac port dpid self mac mac self port port self dpid dpid def add
  • Android:动态创建控件和方向变化

    目前我正在开发一个动态创建控件的 Android 应用程序 每次用户单击按钮时 按钮下方都会出现一个新的 EditText 并且用户可以与 EditText 进行交互 但是 如果屏幕方向发生变化 用户创建的 EditText 也会消失 用户
  • 来自plotly的三元图

    在此输入图像描述 https i stack imgur com lyUJu png 我想在三元图中添加线条 水平 垂直 以突出显示某些部分 可以帮我吗 三元图 代码如下 fig px scatter ternary df a df a b
  • 根据 big-o 表示法进行评级的算法是否会受到并行性的影响?

    我刚刚读了一篇关于矩阵乘法突破的文章 O n 2 373 的算法 但我猜矩阵乘法是可以并行化的 那么 如果我们开始生产千核处理器 这会变得无关紧要吗 事情会发生怎样的变化 并行执行不会改变特定算法的复杂性的基本原理 充其量 您只是花费一些给
  • 验证模型属性 WCF Web APi

    我有一组使用 WCF Web Api 托管的服务 我需要做的是验证应用程序模型内的属性 例如 在 MVC 3 中 我像这样装饰模型中的属性 StringLength 30 public string UserName get set 然后在
  • 如何计算SQL中不同项目的数量

    数据库结构 Clubs ID ClubName Teams ID TeamName ClubID Players ID Name Registrations PlayerID TeamID Start date End date Seaso
  • 计算 GPU 上的彩色像素 - 理论

    我有一张 128 x 128 像素的图像 它被分解为 8 x 8 的网格 每个网格块包含 16 x 16 像素 要求 我想计算我的图像包含多少个黑色像素 直接的方法 I could通过逐行 逐列检查整个图像并检查像素是否为黑色来实现此目的