pyopencl中的中值过滤器脚本按程序工作,但在转换为函数时,大多数情况下返回零

2024-05-19 16:24:55 发布

您现在位置:Python中文网/ 问答频道 /正文

有许多pyopencl的教程脚本实现了一个内核掩码宽度为3的中值过滤器。我想扩展这段代码以允许改变过滤器的掩码宽度

我有两个测试实现,使用我可以编写的最简单的暴力排序算法。下面我共享的第一个文件是一个工作过程脚本。后者是从该脚本创建的函数。程序脚本在我可以访问的各种机器上最新版本的pyopencl(2019.1)上工作。该函数返回(大部分)零的数组

注1:中值滤波器的这种实现方式计算图像内部像素的中值,仅保留边界附近的像素。这个细节显示在问题中,因为显示在边界附近的线程只返回原始图像的像素值而没有问题。是靠近内部的线返回0

注2:您会注意到,我将源字符串分解为一个硬编码整数,将其传递到中值滤波器的掩码大小中(过程脚本中的第41行)。我了解到,我不允许在函数中简单地“创建”一个可以动态调整大小的数组。不过,用整数硬编码似乎效果不错(如果有人有什么建议,我会很高兴读到。我很清楚它看起来有多粗糙。)

注3:如果运行这些代码,可能需要操作设备的索引。当然,任何可以被scipy读取的光栅图形都可以正常工作

#procedural_median_filter.py
import pyopencl as cl
import numpy as np
import matplotlib.pyplot as plt 
from scipy.misc import imread, imsave

filter_radius = 5
img = imread('test.jpg',flatten=True).astype(np.float32)
plat = cl.get_platforms()
devices = plat[0].get_devices()
CPU = [devices[0]]
try:
    GPU = [devices[2]]
except IndexError:
    GPU = "none"
if GPU!= "none":
    ctx = cl.Context(GPU)
else:
    ctx = cl.Context(CPU)

queue = cl.CommandQueue(ctx)
mf = cl.mem_flags
src = """
__kernel void medianFilter(__global float *img, __global float *result, __global int *width, __global int *height, __global int *filter_radius)
{
     int w = *width;
     int h = *height;
     int rad = *filter_radius;
     int mask_size = (2*rad + 1)*(2*rad+1);
     int median_index = mask_size / 2;

     int posx = get_global_id(1);
     int posy = get_global_id(0);

     int i = w*posy + posx;
    // Keeping the edge pixels the same
    if( posx < rad || posy < rad || posx > w-rad || posy > h-rad){
        result[i] = img[i];
    }
    else{
        int mask[""" + str(int((2*filter_radius+1)**2)) + """];
        int mask_index = 0;
        int mask_position;

        for(int maski = -rad; maski < rad+1; maski++){
            for(int maskj = -rad; maskj < rad+1; maskj++){       
                mask_position = w*(posy - maskj) + (posx - maski);
                mask[mask_index] = img[mask_position];
                mask_index = mask_index +1;

            }
        }

        int keyval;
        int maskj;

        for(int maski = 1; maski< mask_size; maski++){
            for(maskj=maski+1; maskj< mask_size; maskj++){
                if(mask[maskj]<mask[maski]){
                    keyval = mask[maski];
                    mask[maski] = mask[maskj];
                    mask[maskj] = keyval;
                }
            }
        }
     result[i] = mask[median_index];  
    }
}
"""

prg = cl.Program(ctx, src).build()
img_g =  cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=img)
result_g = cl.Buffer(ctx, mf.WRITE_ONLY, img.nbytes)
width_g = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=np.int32(img.shape[1]))
height_g = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=np.int32(img.shape[0]))
radius_g = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf = np.int32(filter_radius))
prg.medianFilter(queue, img.shape, None , img_g, result_g, width_g, height_g, radius_g)
result = np.empty_like(img)
cl.enqueue_copy(queue, result, result_g)
plt.imsave('medianFilter-OpenCL.jpg',result,cmap='gray')

下面的函数将返回一个图像,其中边界像素(直到过滤半径的宽度)与原始图像相同,但内部将返回零

#median_filter_function.py
import pyopencl as cl
import numpy as np
def gpu_median_filtering(img,filter_radius):
    plat = cl.get_platforms()
    devices = plat[0].get_devices()
    CPU = [devices[0]]
    try:
        GPU = [devices[2]]
    except IndexError:
        GPU = "none"
    if GPU!= "none":
        ctx = cl.Context(GPU)
    else:
        ctx = cl.Context(CPU)

    queue = cl.CommandQueue(ctx)
    mf = cl.mem_flags
    src = """
    __kernel void medianFilter(__global float *img, __global float *result, __global int *width, __global int *height, __global int *filter_radius)
    {
        int w = *width;
        int h = *height;
        int rad = *filter_radius;
        int mask_size = (2*rad + 1)*(2*rad+1);
        int median_index = mask_size / 2;

        int posx = get_global_id(1);
        int posy = get_global_id(0);

        int i = w*posy + posx;
        // Keeping the edge pixels the same
        if( posx < rad || posy < rad || posx > w-rad || posy > h-rad){
            result[i] = img[i];
        }
        else{
            int mask[""" + str(int((2*filter_radius+1)**2)) + """];
            int mask_index = 0;
            int mask_position;

            for(int maski = -rad; maski < rad+1; maski++){
                for(int maskj = -rad; maskj < rad+1; maskj++){       
                    mask_position = w*(posy - maskj) + (posx - maski);
                    mask[mask_index] = img[mask_position];
                    mask_index = mask_index +1;

                }
            }

            int keyval;
            int maskj;

            for(int maski = 1; maski< mask_size; maski++){
                for(maskj=maski+1; maskj< mask_size; maskj++){
                    if(mask[maskj]<mask[maski]){
                        keyval = mask[maski];
                        mask[maski] = mask[maskj];
                        mask[maskj] = keyval;
                    }
                }
            }
        result[i] = mask[median_index];  
        }
    }
    """

    prg = cl.Program(ctx, src).build()
    img_g =  cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=img)
    result_g = cl.Buffer(ctx, mf.WRITE_ONLY, img.nbytes)
    width_g = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=np.int32(img.shape[1]))
    height_g = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=np.int32(img.shape[0]))
    radius_g = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf = np.int32(filter_radius))
    prg.medianFilter(queue, img.shape, None , img_g, result_g, width_g, height_g, radius_g)
    result = np.empty_like(img)
    cl.enqueue_copy(queue, result, result_g)
    return result

谢谢你的时间


Tags: imgindexclnpmaskresultfilterglobal