Domanda

AGGIORNAMENTO: consultare la domanda aggiuntiva di seguito con più codice;

Sto cercando di codificare una categoria per offuscare un'immagine. Il mio punto di partenza è Il campione di Jeff Lamarche qui. Mentre questo (dopo le correzioni suggerite da altri) funziona bene, è un ordine di grandezza troppo lento per le mie esigenze - su un 3GS ci vogliono forse 3 secondi per fare una sfocatura decente e mi piacerebbe abbassarlo a meno di 0,5 Sec per uno schermo intero (più veloce è meglio).

Menziona il framework Accelerate come miglioramento delle prestazioni, quindi ho trascorso l'ultimo giorno a guardare questo, e in particolare VDSP_F3X3 che secondo la documenazione di Apple

Filtra un'immagine eseguendo una convoluzione bidimensionale con un kernel 3x3; singola precisione.

Perfetto - Ho una matrice di filtri adatta e ho un'immagine ... ma è qui che mi scontroso.

VDSP_F3X3 presuppone che i dati dell'immagine siano (float *) ma la mia immagine proviene;

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

E il contesto proviene da cgbitmapcontextCreate con kcgimagealpHapreMultitFirst, quindi il mio srcdata è davvero argb con 8 bit per componente.

Sospetto che ciò di cui ho veramente bisogno sia un contesto con i componenti float, ma Secondo la documentazione del quarzo qui, kcgbitmapfloatComponents è disponibile solo su Mac OS e non iOS :-(

Esiste un modo molto veloce che utilizza la struttura accelerata per convertire i componenti interi che ho nei componenti float di cui VDSP_F3X3 ha bisogno? Voglio dire, potrei farlo da solo, ma quando lo faccio, poi la convoluzione, e poi converti, sospetto che lo avrò reso ancora più lento di quanto non sia ora poiché potrei anche convocare come vado.

Forse ho l'approccio sbagliato?

Qualcuno ha qualche consiglio per me dopo aver fatto qualche elaborazione delle immagini su iPhone usando VDSP? La documentazione che posso trovare è molto orientata ai riferimento e non molto per i principianti quando si tratta di questo genere di cose.

Se qualcuno ha un riferimento per la sfocatura molto veloce (e l'alta qualità, non la risoluzione di riduzione e quindi le cose di salvataggio che ho visto e sembrano pantaloni) che sarebbe favolosa!

MODIFICARE:

Grazie @jason. L'ho fatto e funziona quasi, ma ora il mio problema è che sebbene l'immagine si sfocasse, su ogni invocazione che cambia ha lasciato 1 pixel. Sembra anche rendere l'immagine in bianco e nero, ma potrebbe essere qualcos'altro.

C'è qualcosa in questo codice che salta ovviamente errata? Non l'ho ancora ottimizzato ed è un po 'approssimativo, ma spero che il codice di convoluzione sia abbastanza chiaro.

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

Dovrei aggiungere che se commento la riga VDSP_CONV e cambio la riga a seguito;

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

Quindi, come previsto, il mio risultato è un clone della fonte originale. A colori e non spostati a sinistra. Questo implica per me che è la convoluzione che sta andando storto, ma non riesco a vedere dove :-(

Pensiero: in realtà pensando a questo, mi sembra che la convocazione debba sapere che i pixel di input sono in formato argb poiché altrimenti la convoluzione moltiplicherà i valori insieme senza alcuna conoscenza del loro significato (cioè è multiplo r * b ecc.) . Questo spiegherebbe perché ho un risultato B&W, ma non il turno. Ancora una volta, penso che potrebbe esserci di essere più della mia versione ingenua qui ...

Pensiero finale: penso che la sinistra mutevole sia un risultato naturale del filtro e devo guardare le dimensioni dell'immagine e possibilmente metterlo via ... quindi penso che il codice funzioni effettivamente ok dato quello che l'ho nutrito.

Nessuna soluzione corretta

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top