GraphicsMagick 的 OpenCL 开发记录(二十八)

文章目录

  • 如何写`ScaleImage()`的硬件加速函数(二)

<2022-04-21 周四>

如何写ScaleImage()的硬件加速函数(二)

搞了一天也没有搞出来kernel函数怎么写,还得仔细分析一下ScaleImage()函数流程:

  1. GraphicsMagickScaleImage()入手,它比ImageMagick好懂。
  2. 大循环的第一个if-else分支处理Y方向,即垂直方向,它用到两个动态数组x_vectory_vector,它们的长度相等,都是原图的宽度,y_scale小于1是缩小,y_scale大于1是放大,不管是放大还是缩小,都会先读一行原图像素放到x_vector中。
  3. 如果是缩小的话,各像素乘以y_scale的结果存放到y_vector中,可能会继续读取下一行原图进行累积计算。
  4. 如果是放大的话,会将y_vector+y_span*x_vector的结果放到一个临时变量pixel中,之所以要放到pixel中是因为要处理计算结果大于255.0的情况,且可能y_vector在这里首次被使用,所以它申请内存时必须初始始化为0,所以它用的是MagickAllocateClearedArray()函数。
y_vector=MagickAllocateClearedArray(DoublePixelPacket *,
                                    image->columns,sizeof(DoublePixelPacket));
  1. pixel的结果是存到s中,而s=scanline;,且scanline=x_vector;,所以到这里x_vector存放的是Y方向的处理结果。
  2. 然后这里到第二个if-else分支,即处理X方向,代码同第一个if-else分支大同小异,但要注意else,它有一个稍大的循环。最终结果存在tscale_scanline中。
  3. scale_scanline是以一个以目标宽度为长度的动态数组。

我尝试写的kernel函数模仿了ScaleImage()的很多代码,实际上不能工作,以试着重新理解opencl的方式,理解work-groupwork-item,仅有的收获在:

STRINGIFY(
__kernel // __attribute__((reqd_work_group_size(256, 1, 1)))
  void ScaleFilter(const __global CLQuantum *inputImage, const unsigned int matte_or_cmyk,
    const unsigned int inputColumns, const unsigned int inputRows, __global CLQuantum *filteredImage,
    const unsigned int filteredColumns, const unsigned int filteredRows,
    const float resizeFilterScale,
    __local CLQuantum *inputImageCache, const int numCachedPixels,
    const unsigned int pixelPerWorkgroup, const unsigned int pixelChunkSize,
    __local float4 *outputPixelCache, __local float *densityCache, __local float *gammaCache)
{
  const int x=get_global_id(0);
  const int y=get_global_id(1);
  const unsigned int columns=get_global_size(0);
  int cy=y;

  float4 pixel=ReadAllChannels(inputImage,4,columns,x,cy);

  pixel/=4.5;
  WriteAllChannels(filteredImage,4,filteredColumns,
    x*filteredColumns/inputColumns,y*filteredRows/inputRows,pixel);
}
)

似乎生成的图片没有变形,我加了pixel/=4.5;这行代码是为了调试方便,它的效果是使图片变暗。仅此简单的代码也能完成缩放功能(备注:缩小没问题,放大不行),但是WriteAllChannels()xy坐标要从work-item的视角看work-group,目前只能以x*filteredColumns/inputColumnsy*filteredRows/inputRows来代替,以验证我对work-groupwork-item的理解,从上面的代码看,我似乎理解了一些。

参照下面的ImageMagick代码理解:

__kernel void Contrast(__global CLQuantum *image,
  const unsigned int number_channels,const int sign)
{
  const int x=get_global_id(0);
  const int y=get_global_id(1);
  const unsigned int columns=get_global_size(0);

  float4 pixel=ReadAllChannels(image,number_channels,columns,x,y);
  if (number_channels < 3)
    pixel.y=pixel.z=pixel.x;

  pixel=ConvertRGBToHSB(pixel);
  float brightness=pixel.z;
  brightness+=0.5f*sign*(0.5f*(sinpi(brightness-0.5f)+1.0f)-brightness);
  brightness=clamp(brightness,0.0f,1.0f);
  pixel.z=brightness;
  pixel=ConvertHSBToRGB(pixel);

  WriteAllChannels(image,number_channels,columns,x,y,pixel);
}
)

此外我觉得没有必要学AccelerateResizeImage()函数去增加filteredImageBuffer变量,可以学ImageMagickAccelerateContrastImage()函数,在ComputeContrastImage()中直接调用kernel函数,这样可以少一层函数调用。

commit:fake run: AccelerateScaleImage(), still trying, with a little bit of progress。

你可能感兴趣的:(GraphicsMagick,的,OpenCL,开发,GraphicsMagick,ImageMagick,OpenCL,c++)