Question

Mise à jour: veuillez consulter la question supplémentaire ci-dessous avec plus de code;

J'essaie de coder une catégorie pour brouiller une image. Mon point de départ est L'échantillon de Jeff Lamarche ici. Alors que cela (après les correctifs suggérés par d'autres) fonctionne bien, c'est un ordre de grandeur trop lent pour mes exigences - sur un 3GS, il faut peut-être 3 secondes pour faire un flou décent et j'aimerais que cela soit à moins de 0,5 SEC pour un plein écran (plus rapide, c'est mieux).

Il mentionne le cadre d'accélération comme une amélioration des performances, j'ai donc passé le dernier jour à examiner cela, et en particulier VDSP_F3X3 qui, selon la documentation Apple

Filtre une image en effectuant une convolution bidimensionnelle avec un noyau 3x3; précision unique.

Parfait - j'ai une matrice de filtre appropriée, et j'ai une image ... mais c'est là que je suis perplexe.

VDSP_F3X3 suppose que les données d'image sont (float *) mais mon image vient de;

srcData = (unsigned char *)CGBitmapContextGetData (context);

Et le contexte provient de CGBitMapContextCreate avec KCGIMAGEALPHAPREMultipliedFirst, donc mon srcdata est vraiment Argb avec 8 bits par composant.

Je soupçonne que ce dont j'ai vraiment besoin est un contexte avec des composants flottants, mais Selon la documentation de quartz ici, kcgbitmapfloatComponents n'est disponible que sur Mac OS et non iOS :-(

Existe-t-il un moyen très rapide en utilisant le cadre d'accélération de la conversion des composants entiers que j'ai dans les composants flottants dont VDSP_F3X3 a besoin? Je veux dire que je pourrais le faire moi-même, mais au moment où je fais ça, puis à la convolution, puis en revenir, je soupçonne que j'aurai rendu encore plus lent que maintenant car je pourrais aussi bien convaincre que je vais.

Peut-être que j'ai la mauvaise approche?

Quelqu'un a-t-il des conseils pour moi d'avoir effectué un traitement d'image sur l'iPhone en utilisant VDSP? La documentation que je peux trouver est très orientée vers la référence et pas très conviviale en matière de débutant en ce qui concerne ce genre de chose.

Si quelqu'un a une référence pour un flou très rapide (et une qualité de haute qualité, pas la résolution de réduction, puis de sauver les trucs que j'ai vus et regarde des pantalons) qui seraient fabuleux!

ÉDITER:

Merci @jason. J'ai fait cela et cela fonctionne presque, mais maintenant mon problème est que bien que l'image se brouille, à chaque invocation, il se déplace laisse 1 pixel. Cela semble également rendre l'image en noir et blanc, mais cela pourrait être autre chose.

Y a-t-il quelque chose dans ce code qui saute comme évidemment incorrect? Je ne l'ai pas encore optimisé et c'est un peu rude, mais j'espère que le code Convolution est assez clair.

CGImageRef CreateCGImageByBlurringImage(CGImageRef inImage, NSUInteger pixelRadius, NSUInteger gaussFactor)
{
unsigned char *srcData, *finalData;

CGContextRef context = CreateARGBBitmapContext(inImage);
if (context == NULL) 
    return NULL;

size_t width = CGBitmapContextGetWidth(context);
size_t height = CGBitmapContextGetHeight(context);
size_t bpr = CGBitmapContextGetBytesPerRow(context);

int componentsPerPixel = 4; // ARGB

CGRect rect = {{0,0},{width,height}}; 
CGContextDrawImage(context, rect, inImage); 

// Now we can get a pointer to the image data associated with the bitmap
// context.

srcData = (unsigned char *)CGBitmapContextGetData (context);

if (srcData != NULL)
{

    size_t dataSize = bpr * height;
    finalData = malloc(dataSize);
    memcpy(finalData, srcData, dataSize);

    //Generate Gaussian kernel

    float *kernel;  

    // Limit the pixelRadius

    pixelRadius = MIN(MAX(1,pixelRadius), 248);
    int kernelSize = pixelRadius * 2 + 1;

    kernel = malloc(kernelSize * sizeof *kernel);

    int gauss_sum =0;

    for (int i = 0; i < pixelRadius; i++)
    {
        kernel[i] = 1 + (gaussFactor*i);
        kernel[kernelSize - (i + 1)] = 1 + (gaussFactor * i);
        gauss_sum += (kernel[i] + kernel[kernelSize - (i + 1)]);
    }

    kernel[(kernelSize - 1)/2] = 1 + (gaussFactor*pixelRadius);

    gauss_sum += kernel[(kernelSize-1)/2];

    // Scale the kernel

    for (int i=0; i<kernelSize; ++i) {
        kernel[i] = kernel[i]/gauss_sum;
    }

    float * srcAsFloat,* resultAsFloat;

    srcAsFloat = malloc(width*height*sizeof(float)*componentsPerPixel);
    resultAsFloat = malloc(width*height*sizeof(float)*componentsPerPixel);

   // Convert uint source ARGB to floats

    vDSP_vfltu8(srcData,1,srcAsFloat,1,width*height*componentsPerPixel);

    // Convolve (hence the -1) with the kernel

    vDSP_conv(srcAsFloat, 1, &kernel[kernelSize-1],-1, resultAsFloat, 1, width*height*componentsPerPixel, kernelSize);

    // Copy the floats back to ints

    vDSP_vfixu8(resultAsFloat, 1, finalData, 1, width*height*componentsPerPixel);

    free(resultAsFloat);
    free(srcAsFloat);

}

size_t bitmapByteCount = bpr * height;

CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, finalData, bitmapByteCount, &providerRelease);

CGImageRef cgImage = CGImageCreate(width, height, CGBitmapContextGetBitsPerComponent(context),
                                   CGBitmapContextGetBitsPerPixel(context), CGBitmapContextGetBytesPerRow(context), CGBitmapContextGetColorSpace(context), CGBitmapContextGetBitmapInfo(context), 
                                   dataProvider, NULL, true, kCGRenderingIntentDefault);

CGDataProviderRelease(dataProvider);
CGContextRelease(context); 


return cgImage;
}

Je dois ajouter que si je commençais la ligne VDSP_CONV et changez la ligne suivante en;

       vDSP_vfixu8(srcAsFloat, 1, finalData, 1, width*height*componentsPerPixel);

Ensuite, comme prévu, mon résultat est un clone de la source d'origine. En couleur et non déplacée à gauche. Cela m'implique que c'est la convolution qui va mal, mais je ne vois pas où :-(

Pensée: En fait, en y réfléchissant, il me semble que le Convolve doit savoir que les pixels d'entrée sont au format Argb car sinon la convolution multipliera les valeurs avec aucune connaissance sur leur signification (c'est-à-dire qu'elle sera multiple r * b, etc.) . Cela expliquerait pourquoi j'obtiens un résultat en noir et blanc, mais pas le changement. Encore une fois, je pense qu'il pourrait y avoir plus que ma version naïve ici ...

Réflexion finale: je pense que la gauche changeante est un résultat naturel du filtre et j'ai besoin de regarder les dimensions de l'image et peut-être de le remplir ... donc je pense que le code fonctionne bien étant donné ce que je l'ai nourri.

Pas de solution correcte

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top