Comment est-ce que je brouille un UIImage, mais préserve des limites d'object pointues?

Je voudrais effectuer un flou "intelligent" sur un UIImage, où le contenu est flou, mais les bords restnt nets.

Par exemple, voici mon image originale:

Image originale pointue

et voici ce que j'aimerais voir après l'application de ce flou:

Image floue

Comment puis-je faire un flou "intelligent" comme celui-ci sur un UIImage?

Le flou que vous cherchez ici s'appelle un flou bilatéral. Contrairement à un flou gaussien standard, les colors de pixel environnantes sont moyennées avec la couleur de pixel centrale en fonction de leur similitude avec le pixel central. Ceci brouille les régions intérieures des objects, mais conserve un contour net.

Dans mon framework GPUImage open source, j'ai un filter qui fait cela, appelé GPUImageBilateralFilter. C'est la sortie de cela lorsqu'il est appliqué à votre image (en utilisant un blurSize de 1.0 et un distanceNormalizationFactor de 1.6):

Orange filtrée en utilisant un flou bilatéral

Il y a de légères différences entre mon résultat et votre cible, mais c'est probablement dû aux pondérations spécifiques que j'utilise. En ajustant les parameters ici, vous devriez être en mesure d'get plus proche de ce qui précède.

OpenCV a également des filters de flou bilatéraux, et vous pouvez prendre le code source dans mon fragment shader et l'utiliser pour build votre propre implémentation OpenGL ES si vous souhaitez l'utiliser en dehors de cette structure:

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; }