更新:より多くのコードを含む以下の追加の質問を参照してください。
画像をぼかすためのカテゴリをコーディングしようとしています。私の出発点は、ここにあるJeffLaMarcheのサンプルです。これは(他の人が提案した修正後)正常に機能しますが、私の要件には1桁遅すぎます。3GSでは、適切なぼかしを行うのに3秒かかる可能性があり、これを0.5未満に下げたいと思います。フルスクリーンの場合は秒(速いほど良い)。
彼はAccelerateフレームワークをパフォーマンスの向上として言及しているので、私はこれ、特にAppleDocumenationによるとvDSP_f3x3を見て最後の日を過ごしました。
3x3カーネルで2次元畳み込みを実行することにより、画像をフィルタリングします。単精度。
完璧-私は適切なフィルターマトリックスを持っていて、画像を持っています...しかし、これは私が困惑するところです。
vDSP_f3x3は、画像データが(float *)であると想定していますが、私の画像は;からのものです。
srcData = (unsigned char *)CGBitmapContextGetData (context);
コンテキストはkCGImageAlphaPremultipliedFirstを使用したCGBitmapContextCreateから取得されるため、私のsrcDataは実際にはコンポーネントあたり8ビットのARGBです。
私が本当に必要としているのはfloatコンポーネントのコンテキストだと思いますが、Quartzのドキュメントによると、kCGBitMapFloatComponentsはMac OSでのみ利用可能であり、iOSでは利用できません:-(
私が持っている整数コンポーネントをvDSP_f3x3が必要とするfloatコンポーネントに変換するaccelateフレームワークを使用する本当に速い方法はありますか?自分でできるということですが、それを実行してから畳み込みを行ってから元に戻すまでに、畳み込みを行った方がよいので、今よりもさらに遅くなっているのではないかと思います。
多分私は間違ったアプローチをしていますか?
vDSPを使用してiPhoneで画像処理を行ったヒントはありますか?私が見つけることができるドキュメントは、非常に参照指向であり、この種のことに関してはあまり初心者に優しいものではありません。
誰かが本当に速いぼかし(そして高品質、解像度を下げてから私が見たものを再スケーリングしてズボンに見えるものではない)のリファレンスを持っているなら、それは素晴らしいでしょう!
編集:
@Jasonに感謝します。私はこれを実行し、ほぼ機能していますが、問題は、画像がぼやけても、呼び出すたびに1ピクセル左にシフトすることです。また、画像が白黒になるように見えますが、それは別のことかもしれません。
このコードには、明らかに正しくないものとして飛び出しているものがありますか?私はまだそれを最適化しておらず、少しラフですが、たたみ込みコードが十分に明確であることを願っています。
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;
}
vDSP_conv行をコメントアウトし、次の行を次のように変更する場合は、これを追加する必要があります。
vDSP_vfixu8(srcAsFloat, 1, finalData, 1, width*height*componentsPerPixel);
その後、予想どおり、私の結果は元のソースのクローンになります。カラーで、左にシフトされていません。これは、問題が発生しているのは畳み込みであることを意味しますが、どこにあるのかわかりません:-(
思考:実際にこれについて考えると、畳み込みは入力ピクセルがARGB形式であることを知る必要があるように思われます。そうしないと、畳み込みは値を乗算し、その意味についての知識がありません(つまり、複数のR * Bなど) 。これは、私が思うに白黒の結果が得られる理由を説明しますが、シフトは説明しません。繰り返しになりますが、ここにある私の素朴なバージョンよりも多くのものが必要かもしれないと思います...
最終的な考え:左へのシフトはフィルターの自然な結果だと思います。画像のサイズを確認し、場合によってはそれを埋める必要があります...したがって、コードは実際に機能していると思います。