Pregunta

Actualización: consulte la pregunta adicional a continuación con más código;

Estoy tratando de codificar una categoría para difuminar una imagen. Mi punto de partida es Muestra de Jeff Lamarche aquí. Si bien esto (después de las soluciones sugeridas por otros) funciona bien, es un orden de magnitud demasiado lento para mis requisitos: en un 3GS tarda unos 3 segundos en hacer un desenfoque decente y me gustaría obtener esto a menos de 0.5 Sec para una pantalla completa (más rápido es mejor).

Menciona el marco de aceleración como una mejora del rendimiento, así que pasé el último día mirando esto, y en particular VDSP_F3X3 que según la documentación de Apple

Filtra una imagen realizando una convolución bidimensional con un núcleo 3x3; precisión simple.

Perfecto: tengo una matriz de filtro adecuada, y tengo una imagen ... pero aquí es donde me quedo perplejo.

VDSP_F3X3 supone que los datos de la imagen son (flotante *) pero mi imagen proviene de;

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

Y el contexto proviene de CGBITMAPContextCreate con KcgimagealPhapremultipliedFirst, por lo que mi srcData está realmente argb con 8 bits por componente.

Sospecho que lo que realmente necesito es un contexto con componentes flotantes, pero Según la documentación de cuarzo aquí, KCGBITMAPFLOATCOMPONENTS solo está disponible en Mac OS y no en iOS :-(

¿Hay una manera realmente rápida utilizando el marco de aceleración de la conversión de los componentes enteros que tengo en los componentes flotantes que necesita VDSP_F3X3? Quiero decir que podría hacerlo yo mismo, pero para cuando hago eso, luego la convolución, y luego convertir de regreso, sospecho que lo haré aún más lento de lo que es ahora, ya que podría complacerlo como voy.

¿Quizás tengo el enfoque incorrecto?

¿Alguien tiene algunos consejos para mí haber hecho algún procesamiento de imágenes en el iPhone usando VDSP? La documentación que puedo encontrar está muy orientada a referencia y no es muy amigable con los novatos cuando se trata de este tipo de cosas.

Si alguien tiene una referencia para un desenfoque realmente rápido (y de alta calidad, no la resolución de reducción y luego las cosas de rescala que he visto y parezco pantalones) ¡eso sería fabuloso!

EDITAR:

Gracias @Jason. He hecho esto y casi está funcionando, pero ahora mi problema es que, aunque la imagen se difumina, en cada invocación, cambia a la izquierda 1 píxel. También parece hacer la imagen en blanco y negro, pero eso podría ser algo más.

¿Hay algo en este código que salga como obviamente incorrecto? Todavía no lo he optimizado y es un poco difícil, pero espero que el código de convolución sea lo suficientemente claro.

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

Debo agregar que si comento la línea VDSP_Conv y cambio la línea a continuación;

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

Luego, como se esperaba, mi resultado es un clon de la fuente original. En color y no desplazado a la izquierda. Esto me implica que es la convolución la que va mal, pero no puedo ver dónde :-(

Pensamiento: en realidad pensando en esto, me parece que el convolve necesita saber que los píxeles de entrada están en formato argb, ya que de lo contrario la convolución multiplicará los valores junto sin conocimiento sobre su significado (es decir, será múltiple r * b, etc.) . Esto explicaría por qué obtengo un resultado de B&W, creo, pero no el cambio. Una vez más, creo que podría tener que tener más que mi ingenua versión aquí ...

Pensamiento final: creo que el cambio de izquierda es un resultado natural del filtro y necesito mirar las dimensiones de la imagen y posiblemente rellenarlo ... así que creo que el código realmente funciona bien dado lo que le he alimentado.

No hay solución correcta

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top