前言
Metal入门教程总结
正文
核心思路
首先,我们用直方图来表示一张图像:横坐标代表的是颜色值,纵坐标代表的是该颜色值在图像中出现次数。
如图,对于某些图像,可能出现颜色值集中分布在某个区间的情况。
直方图均衡化(Histogram Equalization) ,指的是对图像的颜色值进行重新分配,使得颜色值的分布更加均匀。
本文用compute shader对图像的颜色值进行统计,然后计算得出映射关系,由fragment shader进行颜色映射处理。
效果展示
具体步骤
1、Metal的render管道、compute管道配置;
同前文,不再赘述,详见Metal入门教程总结。
2、CPU进行直方图均衡化处理;
-
2.1 把UIImage转成Bytes;
-
2.2 颜色统计;
// CPU进行统计 Byte *color = (Byte *)spriteData; for (int i = 0; i < width * height; ++i) { for (int j = 0; j < LY_CHANNEL_NUM; ++j) { uint c = color[i * 4 + j]; ++cpuColorBuffer.channel[j][c]; } }
-
2.3 映射关系;
int rgb[3][LY_CHANNEL_SIZE], sum = (int)(width * height); int val[3] = {0}; // 颜色映射 for (int i = 0; i < 3; ++i) { for (int j = 0; j < LY_CHANNEL_SIZE; ++j) { val[i] += cpuColorBuffer.channel[i][j]; rgb[i][j] = val[i] * 1.0 * (LY_CHANNEL_SIZE - 1) / sum; } }
-
2.4 颜色值修改;
// 值修改 for (int i = 0; i < width * height; ++i) { for (int j = 0; j < LY_CHANNEL_NUM; ++j) { uint c = color[i * 4 + j]; color[i * 4 + j] = rgb[j][c]; } }
最后用处理之后的Bytes生成新图片。
3 GPU进行直方图均衡化处理;
-
3.1 compute shader进行颜色统计;
kernel voidgrayKernel(texture2d sourceTexture [[textureLYKernelTextureIndexSource]], // 纹理输入, device LYColorBuffer &out [[buffer(LYKernelBufferIndexOutput)]], // 输出的buffer uint2 grid [[thread_position_in_grid]]) // 格子索引{ // 边界保护 if(grid.x < sourceTexture.get_width() && grid.y < sourceTexture.get_height()) {