<2022-04-21 周四>
如何写ScaleImage()的硬件加速函数(二)
搞了一天也没有搞出来kernel函数怎么写,还得仔细分析一下ScaleImage()函数流程:
- 从
GraphicsMagick的ScaleImage()入手,它比ImageMagick好懂。 - 大循环的第一个
if-else分支处理Y方向,即垂直方向,它用到两个动态数组x_vector和y_vector,它们的长度相等,都是原图的宽度,y_scale小于1是缩小,y_scale大于1是放大,不管是放大还是缩小,都会先读一行原图像素放到x_vector中。 - 如果是缩小的话,各像素乘以
y_scale的结果存放到y_vector中,可能会继续读取下一行原图进行累积计算。 - 如果是放大的话,会将
y_vector+y_span*x_vector的结果放到一个临时变量pixel中,之所以要放到pixel中是因为要处理计算结果大于255.0的情况,且可能y_vector在这里首次被使用,所以它申请内存时必须初始始化为0,所以它用的是MagickAllocateClearedArray()函数。
y_vector=MagickAllocateClearedArray(DoublePixelPacket *,
image->columns,sizeof(DoublePixelPacket));
pixel的结果是存到s中,而s=scanline;,且scanline=x_vector;,所以到这里x_vector存放的是Y方向的处理结果。- 然后这里到第二个
if-else分支,即处理X方向,代码同第一个if-else分支大同小异,但要注意else,它有一个稍大的循环。最终结果存在t即scale_scanline中。 scale_scanline是以一个以目标宽度为长度的动态数组。
我尝试写的kernel函数模仿了ScaleImage()的很多代码,实际上不能工作,以试着重新理解opencl的方式,理解work-group和work-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()的x和y坐标要从work-item的视角看work-group,目前只能以x*filteredColumns/inputColumns和y*filteredRows/inputRows来代替,以验证我对work-group和work-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变量,可以学ImageMagick的AccelerateContrastImage()函数,在ComputeContrastImage()中直接调用kernel函数,这样可以少一层函数调用。
commit:fake run: AccelerateScaleImage(), still trying, with a little bit of progress。
475

被折叠的 条评论
为什么被折叠?



