C++实现Bokeh散景模糊亮部无弥散圆,如何调整亮度采样权重?
散景模糊(Bokeh Blur)亮度权重设置问题
我们需要对图像执行Bokeh blur,我测试了如下代码,但无法在亮部点位上得到Circle of Confusion(弥散圆)效果。
void bokeh(unsigned char *Input, unsigned char *Output, int Width, int Height, int Stride, int Radius) { int Channels = Stride / Width; int rsq = fmax(1, sqrtf(Radius)); for (int y = 0; y < Height; y++) { unsigned char * LinePD = Output + y*Stride; for (int x = 0; x < Width; x++) { unsigned int sum[3] = { 0 }; unsigned int weightsum = 0; for (int ny = std::max(0, y - Radius); ny < std::min(y + Radius, Height); ny++) { const unsigned char * sampleLine = Input + ny*Stride; for (int nx = std::max(0, x - Radius); nx < std::min(x + Radius, Width); nx++) { if (sqrtf(nx - x) + sqrtf(ny - y) < rsq) { const unsigned char * sample = sampleLine + nx*Channels; const unsigned char&R = sample[0]; const unsigned char&G = sample[1]; const unsigned char&B = sample[2]; float weight = sqrtf((unsigned char)((21627 * R + 21627 * G + 21627 * B) >> 16)); for (int c = 0; c < Channels; c++) { sum[c] += weight*sample[c]; } weightsum += weight; } } } for (int c = 0; c < Channels; c++) { LinePD[c] = ClampToByte(sum[c] / weightsum); } LinePD += Channels; } } }
原图如下:
当前运行结果如下:
我期望得到如下所示的圆形散景效果:
我尝试将sqrtf(nx - x) + sqrtf(ny - y) < rsq
替换为powf(nx - x, 2.0) + powf(ny - y, 2.0) < powf(Radius, 2)
同时将float weight = sqrtf((unsigned char)((21627 * R + 21627 * G + 21627 * B) >> 16));
替换为float weight = (R + G + B)*1.0f/3.0f;
后得到了如下的散景模糊效果:
请问如何正确设置基于亮度的采样权重?
修正方案
1. 优化采样区域判断逻辑
原判断逻辑存在计算错误:坐标差可能为负数,开根号会得到NaN,导致采样区域完全不符合预期。你修改后的圆形采样逻辑是对的,可进一步优化性能,避免重复调用高开销的powf函数:
// 外层循环提前计算半径平方 int radius_sq = Radius * Radius; // 内层采样判断替换为整数平方计算 int dx = nx - x; int dy = ny - y; if (dx*dx + dy*dy < radius_sq)
2. 修正亮度计算规则
标准sRGB空间转人眼感知亮度的公式为L = 0.299*R + 0.587*G + 0.114*B,原代码三个通道系数完全相同,不符合亮度感知特性。
3. 正确设置亮度权重
散景效果要求亮部贡献远高于暗部,需要对亮度做非线性放大,拉开亮暗权重差才能得到明显的弥散圆效果。原代码对亮度开根号会压缩亮暗差,属于反向操作,正确写法如下:
// 计算标准亮度,范围0~255 float lum = 0.299f * R + 0.587f * G + 0.114f * B; // 平方放大亮部权重,需要更突出的散景可换成三次方lum*lum*lum float weight = lum * lum;
同时注意把sum数组改为float类型,避免unsigned int溢出导致颜色异常。
内容的提问来源于stack exchange,提问作者Chifred
相关产品推荐
相关产品推荐

