PyOpenCL示例-03.图片操作

Python是目前较流行的一种科学计算语言。语法简洁,上手快,易于维护的优点。但其运算速度是真心的慢。那我们能否利用Python的简洁+OpenCL的运算能力呢?答案是可以的,那就是PyOpenCL。”


>>预备知识

OpenCL的内存对象被分为两类,而这两类内存对象的具体位置、布局以及格式由参数来定义。这两类内存对象是buffer和image。


buffer内存对象以传统CPU的意义看,buffer对象是一维数组,类似C程序中的malloc函数。buffer对象支持的数据类型可以是任意标题、向量以及用户自定义的数据类型。buffer对象中存储 的数据是连续的,这就使OpenCL Kernel可以用C程序员熟悉的指针随机访问方式来读取它们。


image内存对象image对象采用的是不同的方法。因为GPU是为处理图像任务而设计的,所以对图像数据的访问进行了深入优化。image与buffer主要区别:

  • 对设备代码是不可见的,不能通过指针直接访问。
  • 多维结构。
  • 仅限于图像数据相关数据类型,而不能自由实现任意数据类型。

在处理图像数据时。用image内存较buffer内存更有效率。这节我们学习如何用image内存处理数据。把一张彩色图片转换成灰度图。

>>实现代码

这里将实现一个将彩色图片转换成灰度图的程序。

main.py主程序

import pyopencl as cl
import numpy as np
from PIL import Image

def RoundUp(groupSize, imgSize):  
    r = imgSize % groupSize;  
    if r == 0:  
        return imgSize
    else:  
        return imgSize + groupSize - r


if __name__ == '__main__':

    #step 1:选择并创建上下文
    ctx = cl.create_some_context() 

    #step 2:创建命令队列
    queue = cl.CommandQueue(ctx)

    #加载并创建CL程序
    f_cl = open("gray.cl","r")
    f_buf = f_cl.read()

    # 通过字符串内容编译OpenCL的Program
    prg = cl.Program(ctx, f_buf).build()

    src = Image.open('bg.png')               
    dst = Image.new('RGBA',src.size,(0,0,0))

    #获得OpenCL内存标志集
    mf = cl.mem_flags

    # OpenCL处理的图片文件格式RGBA,unit8
    imageFormat = cl.ImageFormat(cl.channel_order.RGBA,cl.channel_type.UNSIGNED_INT8)

    # 将图片从Host复制到Device
    img_in = cl.Image(ctx,mf.READ_ONLY | mf.COPY_HOST_PTR,imageFormat,src.size,None,src.tobytes())
    img_out = cl.Image(context=ctx,flags=mf.WRITE_ONLY,format=imageFormat,shape=src.size)    


    # 根据图片大小定义WorkSize
    localWorkSize = ( 8, 8 )  
    globalWorkSize = ( RoundUp(localWorkSize[0], src.size[0]),  
                        RoundUp(localWorkSize[1],src.size[1]))

    # 执行Kernel
    prg.gray_filter(queue,globalWorkSize,localWorkSize,img_in,img_out)

    buffer = np.zeros(src.size[0] * src.size[1] * 4, np.uint8)  
    origin = ( 0, 0, 0 )  
    region = ( src.size[0], src.size[1], 1 )  
      
    # 将处理好的图片从设备复制到HOST 
    cl._enqueue_read_image(queue, img_out,origin, region, buffer).wait()

    # 保存图片
    dist = Image.frombytes("RGBA",src.size, buffer.tobytes())
    dist.save('gray.png')
    dist.show()

gray.cl内核程序

__kernel void gray_filter(__read_only image2d_t in_img,
                          __write_only image2d_t out_img)
{

    const sampler_t sampler = CLK_FILTER_NEAREST |
                              CLK_NORMALIZED_COORDS_FALSE |
                              CLK_ADDRESS_CLAMP;

    int col = get_global_id(0);
    int row = get_global_id(1);

    int2 coord = (int2)(col,row);     
    uint4 pixel = read_imageui(in_img,sampler,coord);    

    uint v = pixel.x*0.299f + pixel.y*0.587f + pixel.z*0.114f;        
    write_imageui(out_img,coord,(uint4)(v,v,v,255));

}

运行结果

PyOpenCL示例-03.图片操作
滚动到顶部