2008年11月27日木曜日

QC: Lens Blur / とりあえず書いてある通りやってみる

追記(2008/11/29):パッチ出しました



アイも変わらず頭の悪い文章ですみません.


経緯
ちらほらいろんなところで聞いていたTilt-shift本城直季さん.
先日これをみてどやるんだろう?とおもい始めました.
でわかったことはPhotoshopをつかった技があるってこと.
(本来はカメラとレンズの継ぎ部をいじるテクニック)

そこで出てきたLens BlurというBlur.
ほほー.ピンぼけ画像をつくるのね.で思った.Quartz Composerでできねぇかな?って.

QCのPatchを調べた.…ない.Gaussian Blurが似ているけど結果が実は違う(上記Lens BlurというBlurのとび先でわかる).

じゃあつくろう.でもどうやって?ということで調べた.ピンぼけ画像のつくりかたw.

参考
そこでみつけたページがここ
(余談:サンプルのモチーフがちょっとどっかきになって,サイトルートにいってみたら納得したw.)
物理としてあってるかどうかはわからないけど,なんとなくそれっぽいし解説もシッカリあった.

実装
ということでとりあえず書いてある通りの実装をしてみるとして,先のエントリーの実処理部(memcpy)を書き換えてみた.
(絞りは矩形ということで.)
- (BOOL) renderToBuffer:(void*)baseAddress 
withBytesPerRow:(NSUInteger)rowBytes
pixelFormat:(NSString*)format
forBounds:(NSRect)bounds
{
vImage_Buffer inBuffer, outBuffer;
if(![_image lockBufferRepresentationWithPixelFormat:format
colorSpace:[_image imageColorSpace]
forBounds:bounds])
return NO;

inBuffer.data= (void *)[_image bufferBaseAddress];
inBuffer.rowBytes= [_image bufferBytesPerRow];
inBuffer.width= [_image bufferPixelsWide];
inBuffer.height= [_image bufferPixelsHigh];
outBuffer.data= baseAddress;
outBuffer.rowBytes= rowBytes;
outBuffer.width= [_image bufferPixelsWide];
outBuffer.height= [_image bufferPixelsHigh];

{
unsigned long i, j;
for(j= 0; j<inBuffer.height; j++) {
for(i= 0; i<inBuffer.width; i++) {
int c;
for(c= 0; c<4; c++) {
long dw, dh;
double sum= 0.0;
NSUInteger m= 5;
double n= 1.03;
for(dh= j-m; dh<j+m+1; dh++) {
for (dw= i-m; dw<i+m+1; dw++) {
unsigned char v= [OutputImageProvider valueWithPos:c x:dw y:dh vImage:inBuffer];
sum+= pow(n, v);
}
}
double s= sum/((2*m+1)*(2*m+1));
s= log(s)/log(n);
s= (s>255)?255:s;
[OutputImageProvider setValue:s pos:c x:i y:j vImage:outBuffer];
}
}
}

}

[_image unlockBufferRepresentation];
return YES;
}

+ (unsigned char)valueWithPos:(int)i x:(int)x y:(int)y vImage:(vImage_Buffer)inBuffer
{
if (x<0 || inBuffer.width<x || y<0 || inBuffer.height<y) {
return (unsigned char)0;
}
return *((unsigned char *)(inBuffer.data+(inBuffer.rowBytes*y+4*x+i)));
}
+ (void)setValue:(unsigned char)v pos:(int)i x:(int)x y:(int)y vImage:(vImage_Buffer)outBuffer
{
if (x<0 || outBuffer.width<x || y<0 || outBuffer.height<y) {
return;
}
*((unsigned char *)(outBuffer.data+(outBuffer.rowBytes*y+4*x+i)))= v;
}


結果
左はGaussian Blur(r=5), 右がm= 5, n= 1.03(だったと思う)の結果.


左はGaussian Blur(r=10), 右がm= 10, n= 1.03(だったと思う)の結果.


左はGaussian Blur(r=5), 右がm= 5, n= 1.05(だったと思う,かなり怪しい記憶)の結果.


考察
一応,Gaussianとの違いも出たっぽいのでよしとしてみる.
で,やっぱり遅い.最初に対数をとったBufferをつくってしまって,絞り形状の平均値用のカーネルをつくってみればvImage.framework関連の処理でいけるんじゃね?ということを考えてみる.

所感
って感じ.(絞り形状が六角形とっかそれっぽくてよくない?ちょっとやってみたいw)

間違いやお気づきの点がありましたらコメントもらえるとうれしいです.

0 件のコメント: