OpenCL 中使用 PyOpenCL 的快速二维直方图
Fast 2d histogram in OpenCL with PyOpenCL
我正在尝试在 Python 中对 HSV 图像做二维直方图,但即使使用 numpy 和 opencv 也不够快(我实际上是用视频做的,但考虑每个frame 只是一个图像)。
我正在寻找最饱和的色相值。目前我有以下代码,工作正常,但速度太慢。
hist, xbins, ybins = np.histogram2d(hsv_channels[0].ravel(), saturation_channel.ravel(), [180,256],[[0,180],[0,256]])
我希望改为使用 PyOpenCL 执行此操作,并将计算推送到 GPU,但除了 OpenCL 中的 hello world 程序。我找到了一些关于这样做的论文,但我不确定从哪里开始。
我该如何开始呢?
编辑:
我考虑得更多了。我想我想在GPU上做的步骤大致如下:
- 将图片转为一维数组(如果是10x10,转为100长数组)
- 上传图像到 GPU
- 将图像拆分为 n 个切片进行处理,其中 n 是并行计算单元的数量。或者每个都可以引用此数组上的特定范围。
- (Map) 对于每个计算单元,分配 180 个 'bins',每个可以包含 256 个其他 bin。每个的最里面的内容只是一个用于计数的整数。
- 对于每个色调(180 个分箱之一),计算每个饱和度水平(其他 256 个分箱)有多少该色调。对数组中可以指望的子部分执行此操作。
- 创建一组新的空垃圾箱。
- (Reduce) 对于所有这些 bin 计数,然后将它们合并在一起(添加值)。我不确定我是否需要等到它们全部完成,或者只是按顺序与上面的空垃圾箱合并。
- (确定最终答案)对于最后一组 bin,遍历它们并找到该色调的最大饱和度值,并将其存储。现在找到具有最大饱和度的色调。作为最终答案,return 这个色相 # 和这个最大饱和度 #。
不过,我对使用 PyOpenCL(或整个 OpenCL)的 GPU 了解不够,无法正确执行此操作。
如果您采用不同的方法,您可以将计算时间减少到 histogram2d 所用时间的 2% 左右。在 3143x2095 图像上,此方法花费了大约 5 毫秒,而 histogram2d 浪费了大约 280 毫秒。
import cv2
import numpy as np
from numpy import unravel_index
import time
img = cv2.imread('ducks.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
print hsv.shape
hue = hsv[:, :, 0]
sat = hsv[:, :, 1]
start = time.time()
max_index = unravel_index(sat.argmax(), sat.shape)
end = time.time()
print 'argmax time:', end - start
print sat[max_index]
print hue[max_index]
start = time.time()
hist, xbins, ybins = np.histogram2d(hue.ravel(), sat.ravel(), [180, 256], [[0, 180], [0, 256]])
end = time.time()
print 'histogram2d time:', end - start
输出:
(2095, 3143, 3)
argmax time: 0.00526285171509
255
39
histogram2d time: 0.288522958755
饱和度最大的像素多于1个的情况比较容易处理。
我正在尝试在 Python 中对 HSV 图像做二维直方图,但即使使用 numpy 和 opencv 也不够快(我实际上是用视频做的,但考虑每个frame 只是一个图像)。
我正在寻找最饱和的色相值。目前我有以下代码,工作正常,但速度太慢。
hist, xbins, ybins = np.histogram2d(hsv_channels[0].ravel(), saturation_channel.ravel(), [180,256],[[0,180],[0,256]])
我希望改为使用 PyOpenCL 执行此操作,并将计算推送到 GPU,但除了 OpenCL 中的 hello world 程序。我找到了一些关于这样做的论文,但我不确定从哪里开始。
我该如何开始呢?
编辑:
我考虑得更多了。我想我想在GPU上做的步骤大致如下:
- 将图片转为一维数组(如果是10x10,转为100长数组)
- 上传图像到 GPU
- 将图像拆分为 n 个切片进行处理,其中 n 是并行计算单元的数量。或者每个都可以引用此数组上的特定范围。
- (Map) 对于每个计算单元,分配 180 个 'bins',每个可以包含 256 个其他 bin。每个的最里面的内容只是一个用于计数的整数。
- 对于每个色调(180 个分箱之一),计算每个饱和度水平(其他 256 个分箱)有多少该色调。对数组中可以指望的子部分执行此操作。
- 创建一组新的空垃圾箱。
- (Reduce) 对于所有这些 bin 计数,然后将它们合并在一起(添加值)。我不确定我是否需要等到它们全部完成,或者只是按顺序与上面的空垃圾箱合并。
- (确定最终答案)对于最后一组 bin,遍历它们并找到该色调的最大饱和度值,并将其存储。现在找到具有最大饱和度的色调。作为最终答案,return 这个色相 # 和这个最大饱和度 #。
不过,我对使用 PyOpenCL(或整个 OpenCL)的 GPU 了解不够,无法正确执行此操作。
如果您采用不同的方法,您可以将计算时间减少到 histogram2d 所用时间的 2% 左右。在 3143x2095 图像上,此方法花费了大约 5 毫秒,而 histogram2d 浪费了大约 280 毫秒。
import cv2
import numpy as np
from numpy import unravel_index
import time
img = cv2.imread('ducks.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
print hsv.shape
hue = hsv[:, :, 0]
sat = hsv[:, :, 1]
start = time.time()
max_index = unravel_index(sat.argmax(), sat.shape)
end = time.time()
print 'argmax time:', end - start
print sat[max_index]
print hue[max_index]
start = time.time()
hist, xbins, ybins = np.histogram2d(hue.ravel(), sat.ravel(), [180, 256], [[0, 180], [0, 256]])
end = time.time()
print 'histogram2d time:', end - start
输出:
(2095, 3143, 3)
argmax time: 0.00526285171509
255
39
histogram2d time: 0.288522958755
饱和度最大的像素多于1个的情况比较容易处理。