これまで、パーソナルコンピュータ上で、小さなプログラムを書くことは何度 かあったが、UNIX上で他の人との協調作業をしながらの、大規模なプログラミン グは始めてであった。また、Eosシステムというプログラミング環境に慣れるのに、 時間が必要であった。
Eosシステムは、まだ開発途中で、マニュアル類が新規開発者向けには整備され ていなかった。また、そのマニュアルを書くことも、特別実験の内容に含まれて いた。そこで、二三のプログラムを書いた後に、チュートリアルマニュアルを書 いた。このシステムは、広く公開されることから、英語で書くことが要求されて いた。しかし、語学力不足のため、本当に書きたい言い回しが出来なかった点が 残念であった。
初めは、単純なテキストファイルであったが、安永さんにより、ハイパーテキ スト化と若干の修正が行われた。現在、 Eosシステム開発者向けのページ の下の Quick Tutorial に公開されている。
以下、実際に作成したプログラムの紹介と、使用した結果・感想を述べる。使 用結果を表示している物は、クライオ電子顕微鏡写真原画 像(1000×1000)の右上の250×250について実行した。加工前の画像は、以下 のような物である。
250×250、デフォーカス1.97μm(19700Å)。
まず、開発方法になれるために、すでに存在する平滑化処理のプログラムに、 新たな平滑化手法を付け足すことから始めた。
平滑化処理とは、画像の点に対し、その周囲の決められた大きさの範囲を決め、 その中の値の統計を取り、統計から計算された値をその点の新たな値とする作業 である。簡単のために一次元で例を挙げると、点x=iに対し、x=i-nか らx=i+n の範囲の2n+1この点でその点の値f(x)の統計を取り、それをf(x=i)の新たな値と するのである。
lmrcImageSmoothing.c には、すでに中央値を取る関数 __lmrcImageSmoothingMedianFilter が存在した。練習のため、単純に平均を取る、 __lmrcImageSmoothingMeanFilter を新たに作った。
次に、曲面当てはめ処理のプログラム lmrcImageSmoothingSurfaceFitFilterを 作った。これは、f(x(i),y(i))に対し、その周辺の決められた領域の値で、
g(x,y) = a x^2 + b y^2 + c xy + d x + e y + h
を当てはめ、係数 a,b,c,d,e,hを最小二乗法により、決定するプログラムであ る。こうして決定したg(x,y)に(x(i),y(i))を代入して、その点の新たな値とす る。平均値フィルタは、取り立てて言うことはない。曲面当てはめは、画像に連続 性をもたらすので、少し大きめの(被写体や、ノイズの程度にも依るが、7×7〜 9×9)範囲を取ると効果がある。平滑化処理に共通するが、どうしても眠 い画像になってしまう。しかし、曲面当てはめ処理は、ある程度大きい範囲でも、 極端に眠い画像にならないという利点がある。
平均値フィルタ(9×9)処理
後の画像。
中央値フィルタ(9×9)処
理後の画像。
曲面当てはめフィルタ
(9×9)処理後の画像。上の二つと比べ、同じ大きさの範囲(9×9)で平滑化してい
るにも関わらず、ぼやけ方が少ない。
次に、分散平滑化処理(CVE)のプログラムを作成した。これは、画像のむらを取 り除く効果がある。
対象とする電子顕微鏡写真は、電子線強度、被写体の厚さ、現像・焼き付けな どで、画像濃度に本来無いむらが生じる。このむらを取り除きたい。しかし、む らを完全に取り除くと、画像は一様な灰色になってしまう。そこで、統計的な手 法でこのむらを取り除くことになる。
そこで、むらとは、次のような物とする。まず、大きさのスケールsの対象の写っ た真の画像 f(x(i),y(i)) を仮定する。ここに、大きさのスケールSのむらフィルタ、
g(x(i),y(i)) = a(x(i),y(i)) f(x(i),y(i)) + b(x(i),y(i))
がかかったとする。ただし、Σb=0と仮定する。この画像を大きさのスケールs<L<<Sの範囲Lでは、上の式は、
g(x(i),y(i)) = a f(x(i),y(i)) + b
の様に表されると近似できる。スケールs<Lの範囲L内では、真の画像の値 f(x(i),y(i)) の分布は、画像のどの 範囲についても同じになることが期待される。これを、平均μで、分散がσの 正規分布と捉えることにする。この分布が、
g(x(i),y(i)) = a f(x(i),y(i)) + b
の変換を受けると、gの平均と分散はμ'=aμ+b、σ'=aσの様に変換される。そこ で、むらを取り除くためには、aとbを求めて逆変換を行えば良いと考えられる。 具体的には、真の平均μと真の分散σは全画像範囲から求めることになる。このプログラムでは、ある点の周りの範囲についてfの和とf^2の和を求める事 が何度も行われる。しかし、すぐ隣の点について同じ事を行うと、作業の殆どは 前回の繰り返しである。この無駄を、前回の計算結果を保存することで効率を上 げた。これにより、計算範囲をn倍(nL×nLで和を取る)しても、計算量はn倍で済 み、n倍効率が良くなる。
この処理は、大きめの範囲(写っている被写体に大きく依存する。)で行うと、む らの少ない良い画像が得られた。また、縦長の短冊状で行うと、写真の取り込み スキャナの性質に由来する縦縞の細いむらを完全に除去することが出来る。これ により、フーリエパワースペクトルの原点付近の値が落ちつき、CTFの計算に役立 つと考えられる。しかし、同時にCVEの計算範囲が極端な場合(例えば短冊状の1× 1000)フーリエ空間の像は連続性が破壊される。この点には気を付けなければいけ ない。また、逆に、不用意に小さい範囲で処理を行うと、下の図の様に肝心な画 像まで消失してしまうことになる。
CVE処理(25×25)後の画像。範囲が小さす
ぎたために、肝心な被写体が「むら」として取り除かれている。
強調処理とは、平滑化などでぼやけた輪郭線をはっきりと表示する処理である。 方法は二種類考えられる。一つは、すべての点について、比較的明るければより 明るく、比較的暗ければより暗く値を変化させる方法(コントラストの強調)であ る。もう一つは、値の急変する点の周りについて、その変化率を大きくする方法 (縁取り)である。ここでは、前者の方法を取った。
具体的には、画像 f(x(i),y(i)) に対して、写像g(f)を定義してやることである。 この写像は、特に用途を限定しない場合、一対一写像であることが要求される。 また、ディスプレー等で表現できる値の幅には限界がある。そのため、fの値が無 限大・無限小でもg(f)の値がある値に落ちつくことが期待される。
これらの条件を満たす関数として、arctanやtanh等が考えられる。ここでは、
arctanを用いた。arctanは、原点に対して点対称で、値域が(-π/2,π/2)である。
また、
まず、元の画像の統計を取り、平均値mと分散sを求める。(x(i),y(i))における画像の値fに対して、バイアスbと傾きgを定数として与えると、
は、fが平均値から離れる度合いをs単位で表し、それをbだけ平行移動した上で傾 き調整の因子gで割っている。つまり、画像の値が分布よりbシグマずれている点 が基準となっている。さらに、その基準からgシグマずれたものは、1となり、arctan の性質を利用すれば、最大値の半分の値に変換することが出来る。このようにし て、bとgは写像関数の重要なパラメータであることが分かる。f - m -b + ─── s ────── g
この変数変換を元に、最大値・最小値が元の画像と変わらないように変換する のがlmrcImageHighlighting.cのHighlightByArcTan関数である。
この処理の結果は、bとgの値を変えるだけで、様々に変化する。gを小さく取る と、二値化したのと同様の結果となる。そのとき、bは閾値の役割をする。gを上 手く調節することによって、表示するときに都合が悪い、極端に明るい・暗い点 を処理することが出来る。
arctan関数による強調。b(bias)=0、g
(grad)=1である。
この処理は、小さな範囲の統計が全体の統計からどれだけ異常であるかを求める 物である。全画像が正規分布を示すランダムな画像であったとき、その中のある 範囲を取り出す事を考える。その統計分布は、一般には、全体の正規分布とは異 なる。全体からのずれは、Student's t-statisticと呼ばれる分布に従う。実際の 計算は、Xを部分の平均、sを部分の標本分散(の平方根)、μを全体の平均とすると、
と表される。X - μ t = ―――― s / √n
この分布は、小さな範囲の中の点の数が増えて行くに従って、正規分布N(0,1)に 近づく。そこで、ある点の周りの小範囲についてtを求め、それをその点の値とし た画像は、平凡な領域では絶対値が1程度であり、絶対値が3を越えるような点は きわめて異常であると言える。
プログラムの殆どはmrcImageCVEと共通である。実際、共有できれば良いのであ るが、C言語でオブジェクト指向のプログラムを書いているため、難しい。C++等 のオブジェクト指向言語を用いれば、継承などの特徴を生かせるであろう。早く 標準的なオブジェクト指向環境が整うことが待たれる。 結果は予想と異なり、タンパクを強調する物ではなく、 むしろ強く平滑化されたものとなった。
t関数変換処理(9×9)をした画像。白いところは
「異常」に明るかった部分。黒いところは「異常」に暗かった部分。中庸の灰色
部分は、画像全体の分布と近い「普通」の領域。
実空間での処理で、プログラミングの流れに慣れたところで、フーリエ空間で のプログラムに着手した。これらのプログラムでは、データの範囲を間違えて理 解してプログラムをしたために、バグが残っている。このバグの修正は重要であ る。
具体的には、
for(nz = -inFFT->HeaderN.z / 2.0; nz <= inFFT->HeaderN.z / 2.0; nz += 1.0) { for(ny = -inFFT->HeaderN.y / 2.0; ny <= inFFT->HeaderN.y / 2.0; ny += 1.0) {とある部分の、nzとnyの範囲の<=を、次の様に<に修正しなければならない。
for(nz = -inFFT->HeaderN.z / 2.0; nz < inFFT->HeaderN.z / 2.0; nz += 1.0) { for(ny = -inFFT->HeaderN.y / 2.0; ny < inFFT->HeaderN.y / 2.0; ny += 1.0) {
実空間と逆の次元を持つ逆空間上で、原点周辺の半径Rの円(もしくは球)を境に して、内側の点についてはそのままに、その外側については減衰させる処理をす る。これによって、被写体の大きさから写るはずの無いような細かな規模のノイ ズを減少させることが出来る。
Rの近辺での実際のフィルタの値gは、それより内側の極限で1、外側の極限で0 に成るような、何らかの関数が選ばれる。今回用意したのは、単純ステップ、余弦、 指数関数の三種類である。画像は、逆空間で(X(i),Y(i))の値fに対し、g(f)に変えられ る。
これらのフィルタ関数には、フィルタの値gが0.5になる逆空間での距離(hvp=half value point)が必須であり、さらに必要があれば、gが0から1に変化するおおよそ の幅(width)を与えてやる必要がある。今回用意したフィルタでの各引数のgとの 関係は、次の図の様になる。
これは、ローパスフィルタとは逆に、逆空間上の原点周辺の半径Rの円(もしく は球)を境にして、内側の点については値を減衰させ、その外側についてはそのま まとする処理である。この処理によって、被写体のサイズと比べ、はるかに上回 るような大きさの規模のノイズを減少させることが出来る。
Rの近辺でのフィルタの値gは、単純ステップ、余弦、指数関数型を用いた。各 引数とフィルタの値は、次の図の様になる。
バンドパスフィルタは、ローパスフィルタとハイパスフィルタの両方の性質を 合わせ持っている。逆空間で、原点から決められた二つの距離の間にある点につ いてはそのままの値を、そこからはずれる点については、減衰させる。
このフィルタの関数には、ハイパスの部分とのローパス部分の二つの部分用に、 hvpとwidthを用意しなければならない。(hvp,width)はハイパスに対して(hvl,wl) に、ローパスに対して(hvh,wh)と対応する。関数として単純ステップ、余弦、指 数関数型の三種類を用意した。それらの引数との対応は次の図の様になる。
フーリエ空間での、ローパス・ハイパス・バンドパスの三種のフィルタを作り、 フーリエ空間を取り扱うプログラムに慣れたところで、いよいよ画像復元の段階 に入った。まず、最適フィルタの為に用いるノイズレベルを、現在はS/N比1とし て計算しているのを、実際の画像に即したS/N比を用いようと考えた。
最適フィルタのノイズレベルは、かなり荒くても良い結果が得られ、逆に言う とノイズレベルの良い近似を与えても結果はそれほど良くは成らないと考えられ る。しかし、少しでも良くなればと、とにかく作ってみることにした。電子顕微 鏡写真のフーリエパワースペクトルは、図の様になっている。電子顕微鏡と被写 体の特性から、図の様にいくつかの節を持つ分布となる。これは、真の画像がCTF という関数で表されるフィルタにかけられたと見ることが出来る。
図を良く見ると、CTFの節に相当する部分では、ノイズだけが現れており、それ は片対数グラフでは直線に乗っている。逆に言えば、この直線を求めてやれば、 ノイズに対するシグナルの量を、フーリエ空間での距離Rに対して求めることが出 来る。
ただし、CTFの節を計算するためには、デフォーカスという、故意に焦点をぼか した距離を与える必要がある。
このようにして作ったプログラムで、テスト画像に対して実行すると、期待通 りの同心円上の模様が生じた。しかし、これを用いて再帰的に画像を復元すると いう所までは進まなかったので、これ以上の評価は出来ない。
先のS/Nを求めるプログラムでは、デフォーカスを人間が見当を付けて与えてい た。それを、何とか自動的に計算する方法はないかと、色々な方法を考えた。そ のためには、使いやすいフーリエパワースペクトルのデータが必要となる。
そこで、mrcImageCTFSNで用いたルーチンを活用して、フーリエパワースペクト ルだけを求めるプログラムを作った。パワースペクトルは、フーリエ空間での距 離について、円周上の値の和を取っていくので、円周の長さで規格化されなくて は成らない。このプログラムでは、円周に微小な面積があると考えて、単位面積 当たりのパワースペクトルを求める方法を採った。これは、二次元でも三次元で も同じプログラムが使えるようにするためである。
このプログラムの出力結果を用いて、いくつかの方法でデフォーカスの量を推 定するプログラムを書いた。データはテキストデータなのでPerl等のようなスク リプトが便利である。
しかし、残念ながら、候補を絞る手助けにも成るか成らないかという結果しか 得られず、断念した。
以上