如何模糊UIImage,但保留尖锐的物体边界?

我想对内容模糊的UIImage进行“智能”模糊处理,但边缘保持清晰。

例如,这是我的原始图像:

夏普原始图像

这是我想在应用这个模糊之后看到的东西:

模糊的图像

如何在UIImage上做这样的“智能”模糊处理?

你在这里寻找的模糊被称为双边模糊。 与标准高斯模糊不同,根据周围像素颜色与中心像素的相似程度,将中心像素颜色与周围像素颜色进行平均。 这模糊了物体的内部区域,但保留了一个清晰的轮廓。

在我的开源的GPUImage框架中,我有一个filter来完成这个操作,称为GPUImageBilateralFilter。 这是应用于图像时的输出(使用1.0的blurSize和1.6的distanceNormalizationFactor):

使用双边模糊过滤橙色

我的结果和你的目标有一些细微的差异,但这可能是由于我使用的具体比重。 通过在这里调整参数,你应该能够更接近于上述。

OpenCV也有双边模糊filter,你可以把源代码放到我的片段着色器中,如果你想在这个框架之外使用它,可以用它来构build自己的OpenGL ES实现:

uniform sampler2D inputImageTexture; const lowp int GAUSSIAN_SAMPLES = 9; varying highp vec2 textureCoordinate; varying highp vec2 blurCoordinates[GAUSSIAN_SAMPLES]; uniform mediump float distanceNormalizationFactor; void main() { lowp vec4 centralColor; lowp float gaussianWeightTotal; lowp vec4 sum; lowp vec4 sampleColor; lowp float distanceFromCentralColor; lowp float gaussianWeight; centralColor = texture2D(inputImageTexture, blurCoordinates[4]); gaussianWeightTotal = 0.18; sum = centralColor * 0.18; sampleColor = texture2D(inputImageTexture, blurCoordinates[0]); distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0); gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor); gaussianWeightTotal += gaussianWeight; sum += sampleColor * gaussianWeight; sampleColor = texture2D(inputImageTexture, blurCoordinates[1]); distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0); gaussianWeight = 0.09 * (1.0 - distanceFromCentralColor); gaussianWeightTotal += gaussianWeight; sum += sampleColor * gaussianWeight; sampleColor = texture2D(inputImageTexture, blurCoordinates[2]); distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0); gaussianWeight = 0.12 * (1.0 - distanceFromCentralColor); gaussianWeightTotal += gaussianWeight; sum += sampleColor * gaussianWeight; sampleColor = texture2D(inputImageTexture, blurCoordinates[3]); distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0); gaussianWeight = 0.15 * (1.0 - distanceFromCentralColor); gaussianWeightTotal += gaussianWeight; sum += sampleColor * gaussianWeight; sampleColor = texture2D(inputImageTexture, blurCoordinates[5]); distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0); gaussianWeight = 0.15 * (1.0 - distanceFromCentralColor); gaussianWeightTotal += gaussianWeight; sum += sampleColor * gaussianWeight; sampleColor = texture2D(inputImageTexture, blurCoordinates[6]); distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0); gaussianWeight = 0.12 * (1.0 - distanceFromCentralColor); gaussianWeightTotal += gaussianWeight; sum += sampleColor * gaussianWeight; sampleColor = texture2D(inputImageTexture, blurCoordinates[7]); distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0); gaussianWeight = 0.09 * (1.0 - distanceFromCentralColor); gaussianWeightTotal += gaussianWeight; sum += sampleColor * gaussianWeight; sampleColor = texture2D(inputImageTexture, blurCoordinates[8]); distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0); gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor); gaussianWeightTotal += gaussianWeight; sum += sampleColor * gaussianWeight; gl_FragColor = sum / gaussianWeightTotal; }