Core ImageでRGBチャンネル分解をしてみる

背景

研究の方で蛍光顕微鏡をよく使う。複数種類のタンパク質を複数種類の蛍光色素で染め分け、ある時点、ある領域でそれらがどのように局在しているかを明らかにするのだ。通常蛍光色素は固有の波長で励起され、蛍光の画像がデータとして保存される。
そこで問題は、これらのデータは画像であるのだが、通常の風景写真などとは異なる。RGB各色はそれぞれ異なる波長で撮られた蛍光データであり、お互いに何ら関係のないデータなのである。つまり、Photoshopなどを用いて補正するときも、例えばRのチャンネルがGに混ざり込むような操作はできない。むしろチャンネルごとに分割して作業すべきなのだが、Photoshop Elementsではこれが(手間をかければ出来るが)一筋縄ではいかない。また、分割したところでそれぞれの局在の関連を見なければいけないので、独立に表示したのでは意味がない。
じゃあ画像を読み込んで、RGBに分割し、キー操作かなんかで瞬時にRGBをオンオフして簡単にその局在を比べられるような俺様用のソフトを作ればいいじゃないか、ということになった。ちょうどいいことに10.4からCore Imageなんてものもあるしね。ここまで導入。

画像の読み込み、フィルタ、表示

参考にしたのはここ。
Core Imageで体験 - Mac OS Xの高速画像処理
RGBの分離が出来そうなフィルタを捜してみると、「CIColorMatrix」というのがそれらしい。
http://developer.apple.com/jp/documentation/GraphicsImaging/Conceptual/CoreImaging/ci_filters/chapter_5_section_3.html
これのオフにしたい色に対して、零ベクトルを指定してやればいい。それにしてもCore Imageのフィルタの使い方は面白い。パラメータや出力は全部KVCで設定するのだ。

で、RGB各色のオンオフを設定した画像を表示してみた。しかし!結果の画像を見てみると、これが大失敗。例えばGBをオフにしても、GBのあった場所にうっすらRが残っていたりするのである。先に述べたように、チャンネルが独立して扱えなければ研究には使えないのだ。どうしてこうなるのか?

色空間を無視する

たどり着いた答えはこうだ。OS XのColorSync、これがこういう用途には邪魔なのだ。Core ImageのCIImageは、単なるビットマップだけでなく色空間も保持しており、なんだか分からないがファイルから読み込むときに色空間も読み込むか付加するかして自動的に補正がかかってしまうらしい。
CIImageのimageWithContentsOfURL:options:のoptionsには、色空間を指定することが出来るのだが、これにgenericRGBColorSpaceを指定した場合でも、Photoshop Elementsで作ったテスト用ファイルにプロファイルを埋め込んだときと埋め込まないときで違いが出るので、強制的に色空間を上書き出来るわけではないらしい。
結局以下のようにした。

NSURL *fileURL = [NSURL fileURLWithPath:filePath];
		
CGImageRef        imageRef = NULL;
CGImageSourceRef sourceRef = CGImageSourceCreateWithURL((CFURLRef)fileURL, NULL);
if(sourceRef) {
	imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, NULL);
	CFRelease(sourceRef);
}

CGColorSpaceRef colorSpace = [[NSColorSpace genericRGBColorSpace] CGColorSpace];
NSDictionary *options = [NSDictionary dictionaryWithObject:(id)colorSpace forKey:kCIImageColorSpace];
		
CIImage *inputImage = [CIImage imageWithCGImage:imageRef options:options];
CFRelease(imageRef);

そう、CGImageRefはどうやら色空間の情報は持っていないらしい。ので、いったんCGImageRefを作ってからgenericRGBColorSpaceを指定してCIImageを作るとファイルに指定された色空間情報を無視してピュアなRGBに出来るようだ*1

*1:…じゃあCore Graphicsで全部やればいいんじゃね?