狠狠撸

狠狠撸Share a Scribd company logo
ImageJ を使った画像解析実習
数?形態?分布の解析
第194回農林交流センターワークショップ
「 植物科学?作物育種におけるフェノーム解析
- はじめて画像解析を行う研究者のための入門実習 - 」
2015-09-18 09:15-10:20 (実習75分)
実習主担当: 朽名 夏麿
例: 葉緑体の形の解析 (粒子解析)
二値画像
グレイスケール画像
Analyze >
Analyze Particles…
例: アクチン繊維の配向解析
共焦点画像 バンドパスフィルタ
による繊維等の強調
二値化像 細線化像
短径 / 長径
短径
長径
気孔開閉の指標
気孔に対する
アクチン繊維の角度
アクチン繊維の配向の指標
気孔
θ
気孔
θ
気孔
この場合,
短径 / 長径=0.47
この場合,
アクチン繊維の角度=54.3°
灰色: 気孔領域
黒色: アクチン繊維
シロイヌナズナ気孔
アクチン繊維
バンドパスフィルタ
Process > FFT > Bandpass Filter...
解析対象のおおよその大きさをもとに強調する処理.
ノイズ,背景,シェーディングの影響を抑制する.
細胞表層微小管のプラス端
輝度プロファイル(左図の黄色い線)
バンドパスフィルタによる焦点外物体の影響除去
原画像(明視野像) 処理後
焦点外にある細胞やナイロンメッシュの影響を抑えることができる.
BDM処理した
BY-2細胞
BY-2プロトプラスト
から得た単離液胞
アクチン繊維配向の定量と可視化
向き: 配向の平均角度
長さ: 配向の整列性
明るさ(擬似色): 繊维の密度
* stomata-actin.tif を開く.
* Image > Stacks > Z Project... >
Projection type = Max Intensity
* Process > FFT > Bandpass Filter...
Filter large... = 5
Filter small... = 1
Tolerance... = 0
* Image > Adjust > Threshold... >
… > Apply
* Process > Binary > Skeletonize
* Plugins > LPX > Lpx_LinesAngle
mode = map (可視化)
* Plugins > LPX > Lpx_LinesAngle
mode = eachSlice (定量)
実験圃場(水田)
60 cm 間隔
圃場のイネの各個体を毎週撮影し,
地上部の大きさ?形?色を経時的に
定量する実験系を確立する.
定量した形質をQTL解析に供する.
例: 圃场におけるイネの生长解析
撮像装置
実際に撮影された画像
カラーチャート
個体識別札
画像提供: 香川大学 農学部 杉田(小西)左江子 先生
画像解析上の課題
1. ウキクサのような浮遊物
2. 太陽光の直接反射
http://www.mathworks.com/matlabcentral/fileexchange/28790-colorspace-transformations
色空間
一般的なカラー画像では色彩の表現として,
RGB (発光時に用いる色表現,カメラに用いる色表現) や
CMYK (印刷に用いる色表現)
が用いられる.
一方,バイオイメージング分野では
単色からスペクトルまで
多様な色情報のデータが
扱われている.
(A) http://www.jiscdigitalmedia.ac.uk/guide/colour-theory-understanding-and-modelling-colour/
(B) http://w3.kcua.ac.jp/~fujiwara/infosci/colorspace/colorspace3.html
その他 http://en.wikipedia.org/ よりそれぞれ引用
CIE1976 L*a*b* (CIELAB) color space
L*: lightness, a* & b*: color-opponent space
perceptually uniform
RGB color space (A)
(B)
Additive primary colors:
Red, Green, Blue mimic the nonlinear response of the eye
RGB HSV YIQ CIE L*a*b* CIE XYZ
各種色空間への変換例
→ CIE a* 軸がイネ地上部の領域抽出に向く.
カラーパネル検出ならびに葉領域の抽出と細線化
原画像 CIELAB 色空間の a* 軸 a* が閾値以下の領域
葉領域画像 細線画像カラーパネル検出結果
カラーパネルの円の直径が既知(12.5 cm)
であるため,スケールバーとして利用し,
比率 r [cm / pixel] を求める.
画像や細線化画像で測定された pixel 単位
の値を cm に換算するのに用いる.
緑色の領域は a* 軸では小さな値となる.
手作業で個体中心付近に設定した円(青色
で示す)と連結した白領域のみ抽出し,
さらにモルフォロジカルフィルタ(close)
によって領域境界の平滑化を行なうことで
葉領域を得た.
白黒画像の細線化アルゴリズムを適用して
得た.
他に輪郭画像を形態計測の際には作成
しているが,ここでは省略している.
形態特徴の測定法 1/3
葉領域画像 area1: イネ地上部の面積(cm2).葉領域画像中の白画素数 × r2
perimeter4conn: イネ地上部領域の周長(cm).輪郭画像中の白画素数 × r
widthByAreaPeri4: 葉の幅に関する指標(cm).2 × area1 ÷ perimeter4conn
complexity: 形状の複雑度.perimeter4conn 2 ÷( 4 π × area1 )
拡大
輪郭画像葉領域画像
輪郭抽出
形態特徴の測定法 2/3
葉領域画像 skelLen: 葉の長さに関する指標(cm).細線画像中の白画素数 × r
widthByAreaSkelLen: 葉の幅に関する指標(cm).area1 ÷ skelLen
skelEnd: 葉の枚数に関する指標(個).細線画像中の端点の数 (赤い丸).
skelBranch: 葉の混み具合に関する指標(個).細線画像中の分岐点の数 (黄色い丸).
拡大
細線画像葉領域画像
細線化
端点
端点
分岐点
分岐点
形態特徴の測定法 3/3
widthBySkelDisttrfmMean: 葉の幅に関する指標(cm).以下の手続きによって求める値.
Step 1. 細線画像(左の画像)中のi 番目の白画素 Ai について( i は 1 から skelLen まで):
Step 1-1. 画素Aiに最も近い,輪郭画像(右の画像)中の白画素を探し,これを画素Bとする.
Step 1-2. 画素Aiと画素Biの距離(pixel)を求めて, di とする.
Step 2. di の平均値(i は 1 から skelLen まで) × 2 r を widthBySkelDisttrfmMean とする.
細線画像 輪郭画像
画素Ai 画素Bi
実習
- RGB 各信号 への分解:
Image > Color > Split Channels
- その他の色空間の座標へ:
Plugins > LPX > Lpx Color >
mode = RGB2...
もしくは
Plugins > Filters > Color Transformer
- 輝度を閾値とした2値化
Image > Adjust > Threshold
- 面積の測定
Analyze > Analyze Particles
- 細線化と線長の測定
Process > Binary > Skeletonize
Analyze > Analyze Particles
or KBI_Measure > blobMeasure...
feature=chain_codes_8_totalLength
- 端点抽出と計数
Plugin > LPX > Lpx_Filter2d >
filtersForBilevel__ > pixSpec__ > pick,,end
例2: ブドウ葉の病斑解析
シートフィード式スキャナ (ScanSnap) で撮影.
画像提供: 農研機構 果樹研究所 河野淳 様
http://www.scansnap.net/escaneres-by-fujitsu/scansnap/s1100/
拡大図
※スケール代わりの付箋紙にも注目.
回転
縮小 + CIE L* + ノイズ抑制 縮小 + CIE a* + ノイズ抑制
入力画像
入力画像
回転
縮小 + CIE L* + ノイズ抑制 縮小 + CIE a* + ノイズ抑制
拡大図
自動二値化 自動二値化
病斑領域の二値化
自動二値化だけで 常に 必要十分に 正しく 領域抽出するのは困難.
→ ユーザの目視による二値化基準の修正 +
二値化後の除去 (主に葉脈部を除くため円形度を閾値とした)
適切 (必要十分)
偽陰性(見逃し) あり
偽陽性(採り過ぎ)あり
葉領域 ならびに 病斑領域 の決定
葉領域
病斑領域 群葉領域
叶および病斑に関する定量
縮小率: 長さ比 1/shrink に縮小する.
葉領域のノイズ抑制 (to CIEL* 像).
葉領域の自動2値化アルゴリズム
病斑領域のノイズ抑制 (to CIEa* 像)
病斑領域の自動2値化アルゴリズム
葉領域の最小面積
Phase 1: 2値化による領域分割まで
Phase 2: 領域分割後のフィルタリング
病斑領域の最小円形度
object Ijp extends LpxPlugIn {
private val leafThreffective = Seq('ijHuang, 'ijLi, 'ijMinimum, …
private val spotThreffective = Seq('ijRenyiEntropy, 'ijYen, …
private val leafThrSyms =
leafThreffective ++ (plg.threshold.Common.ijSymbols.toSet -- leaf…
}
private val spotThrSyms = {
spotThreffective ++ (plg.threshold.Common.ijSymbols.toSet -- spot…
}
private val mode = arg("kaMode", Seq('measure, 'setParam))
private val sep1 = arg("-- phase1 --")
private val shrink = arg("shrink", 4)
private val leafDenoise = arg("leafDenoise", 2.0)
private val leafThr = arg("leafThr", leafThrSyms)
private val spotDenoise = arg("spotDenoise", 1.0)
private val spotThr = arg("spotThr", spotThrSyms)
private val genStk = arg("genStk", false)
private val sep2 = arg("-- phase2 --")
private val leafMinArea = arg("leafMinAreaInOrg", 500000d)
private val spotCircularity = arg("spotCircularity", 0.6)
private val sep3 = arg("----")
private val continuePlugIn = arg("continuePlugIn", true)
// R G B
private val colorLeaf = new java.awt.Color(128, 128, 128)
private val colorSpot = new java.awt.Color(255, 255, 255)
private val colorLeafId = new java.awt.Color( 0, 198, 255)
private val colorSpotId = new java.awt.Color( 0, 255, 0)
private val colorImageJForeground = new java.awt.Color(255, 255, 255)
private val fontLeaf = new java.awt.Font("Serif", java.…
private val fontSpot = new java.awt.Font("Serif", java.…
def config(argStr: String): Option[() => Any] = {
def rec() {
val imp = IJ.getImage
input(mode)
mode.getSym match {
case 'measure => measure(imp)
case 'setParam => {
if (setParam()) rec()
}
}
}
rec()
None
}
private def measure(imp: Imp) {
if (ImgC.is(imp)) {
phase1(imp)
} else {
phase2()
}
}
private def phase1(impOrg: Imp) {
def bandpass(ip: Ip, loSd: Double, hiSd: Double): Ip = {
new plg.band_pass.DiffOfGaussian(loSd, hiSd)(ip)
}
def bandpassMin0(ip: Ip, loSd: Double, hiSd: Double): Ip = {
plg.band_pass.Min0(bandpass(ip, loSd, hiSd))
}
def to8bit(ip: Ip): Ip = plg.filter2d.ToByteType.SliScale(ip)
def toThrStk(ip: Ip): Ist = new plg.filter2d.ToStkByThrFromByte(A…
def showAndSetCurSlice(ist: Ist, title: String, z: Int) {
val impShow = new Imp(WindowManager.makeUniqueName(title), ist)
impShow.setDisplayRange(0, 255, 7)
impShow.updateAndDraw
impShow.setSlice(z + 1)
impShow.show
}
require(ImgC.is(impOrg), "ImgC.is")
require(impOrg.getStackSize == 1, "getStackSize == 1")
require(shrink() >= 1, "shrink >= 1")
ij.gui.Toolbar.setForegroundColor(colorImageJForeground)
impOrg.setTitle(WindowManager.makeUniqueName("org"))
val ipOrg = impOrg.getProcessor.rotateRight
impOrg.setProcessor(ipOrg)
ipOrg.setInterpolationMethod(Ip.BILINEAR)
val ipShrink = ipOrg.resize((ipOrg.getWidth / shrink().toFloat).r…
val (ipCieL, ipCieA, ipCieB_notUsed) =
new Rgb2ColorSpace(false).procSli(ipShrink, 'CIELAB2_speedy)
val (numX, numY) = UtilImg.dim(ipCieL)
val bpHiMax = numX.min(numY)
// leaf: CIEL*
val ipLeaf = to8bit(bandpassMin0(plg.filter_pt.MathOpMultiply(-1)…
val thrLeaf = new IjThresholder(leafThr.getSym).getThr(ipLeaf).get()
if (genStk()) {
val istLeaf = toThrStk(ipLeaf)
showAndSetCurSlice(istLeaf, "leaf", thrLeaf)
} else {
val imp = UtilImg.show(ipLeaf, f"leaf_${thrLeaf}")
IJ.setThreshold(imp, thrLeaf, 255) }
// spot: CIEa*
val ipSpot = to8bit(bandpass(ipCieA, spotDenoise(), bpHiMax))
val thrSpot = new IjThresholder(spotThr.getSym).getThr(ipSpot).get()
if (genStk()) {
val istSpot = toThrStk(ipSpot)
showAndSetCurSlice(istSpot, "spot", thrSpot)
} else {
val imp = UtilImg.show(ipSpot, f"spot_${thrSpot}")
IJ.setThreshold(imp, thrSpot, 255)
}
}
// use leafMinArea(), spotCircularity()
private def phase2() {
def getIpOfTitle(title: String): Ip = {
val titles = UtilIj.getAllImageTitles()
val hits = titles.filter(_.startsWith(title))
LpxExc.assert(hits.size == 1, f"Image '$' is not …
val ip = WindowManager.getImage(hits.head).getProcessor
LpxExc.assert(Img8.isBinary(ip), f"Image '$' must be …
ip
}
def drawString(ipTgt: Ip, s: String, font: Font, color: Color, …
ipTgt.setColor(color)
ipTgt.setFont(font)
val width = ipTgt.getStringWidth(s)
ipTgt.drawString(s, x - width, y)
}
ij.gui.Toolbar.setForegroundColor(colorImageJForeground)
val ipLeaf = getIpOfTitle("leaf")
val ipSpot = getIpOfTitle("spot")
LpxExc.assert(UtilImg.sameDim(ipLeaf, ipSpot), "dimension mismatch")
val leafMinAreaInShrinked = (leafMinArea() / (shrink() * shrink()))…
val leafBlobs = {
PixGrp.filterOutSmall(PixGrp.getBlobs(ipLeaf), leafMinAreaInShr…
}
val spotBlobs = {
val ipSpotInLeaf = Img8.dupRet(ipSpot, false) { ipSpotInLeaf =>
for (i <- 0 until ipSpot.getPixelCount if ipLeaf.get(i) == 0) {
ipSpotInLeaf.set(i, 0)
}
}
PixGrp.getBlobs(ipSpotInLeaf).filter(_.getCircularity >=
spotCircularity()) }
UtilIj.writeln(f"#shrink;?t${shrink()}")
UtilIj.writeln(f"# areaAdjustFactor;?t${shrink() * shrink()}")
UtilIj.writeln(f"#leafDenoise;?t${leafDenoise()}")
UtilIj.writeln(f"#leafThr;?t${leafThr.getSym.name}")
UtilIj.writeln(f"#spotDenoise;?t${spotDenoise()}")
UtilIj.writeln(f"#spotThr;?t${spotThr.getSym.name}")
UtilIj.writeln(f"#leafMinAreaInOrg;?t${leafMinArea()}")
UtilIj.writeln(f"# leafMinAreaInShrinked;?t${leafMinAreaInShrinked}"
UtilIj.writeln(f"#spotCircularity;?t${spotCircularity()}?n")
for ((leafBlob, leafIdx) <- leafBlobs.zipWithIndex) {
for (polRoi <- leafBlob.toPolygonRoi(true, true)) {
plg.roi_util.Painter.drawByRoiInSitu(ipDebug, colorLeaf, polRoi)
val awtRectangle = polRoi.getFloatPolygon.getBounds
ipDebug.setColor(colorLeafId)
val x = awtRectangle.x
val y = awtRectangle.y + awtRectangle.height / 2
drawString(ipDebug, f"${leafIdx}", fontLeaf, colorLeafId, x, y)
}
val leafXySet = leafBlob.toXys.toSet
val assocBlobs = spotBlobs.filter { spotBlob =>
val (centroidX, centroidY) = spotBlob.getCentroid
leafXySet.contains((centroidX.round.toInt, centroidY.round.…
} sortBy(- _.size)
for ((blob, blobIdx) <- assocBlobs.zipWithIndex) {
blob.drawToIpByColor(ipDebug, colorSpot)
val x = blob.xsMin - 3
val y = (blob.ysMin + blob.ysMax) / 2 + 10
drawString(ipDebug, f"${blobIdx}", fontSpot, colorSpotId, x, y)
}
UtilIj.writeln(f"leafIdx;?t$leafIdx")
UtilIj.writeln(f"leafArea;?t${leafBlob.size * shrink() * shrink(…
UtilIj.writeln(f"spotNum;?t${assocBlobs.size}")
val spotTotalArea = assocBlobs.map(_.size).sum
UtilIj.writeln(f"spotTotalArea;?t${spotTotalArea * shrink() * shr…
for ((spotBlob, spotIdx) <- assocBlobs.zipWithIndex) {
UtilIj.writeln(f" spotArea;?t${leafIdx}-${spotIdx};?t" +
f"${spotBlob.size * shrink() * shrink()}")
}
UtilIj.writeln("")
}
null
}
private def setParam(): Boolean = {
input(sep1,
shrink, leafDenoise, leafThr, spotDenoise, spotThr, genStk,
sep2,
leafMinArea, spotCircularity,
sep3, continuePlugIn)
mode.setIdx(0)
continuePlugIn()
}
}

More Related Content

What's hot (20)

PDF
滨尘补驳别闯チュートリアル
LPIXEL
?
PPTX
滨尘补驳别闯を使った画像解析実习?大量の画像データに対する処理の自动化?
LPIXEL
?
PDF
画像解析の基础知识
LPIXEL
?
PDF
滨尘补驳别闯を使った画像解析実习?起动?终了とファイルの入出力?
LPIXEL
?
PDF
Kaggle RSNA Pneumonia Detection Challenge 解法紹介
理 秋山
?
PDF
条件付き确率场の推论と学习
Masaki Saito
?
PDF
比例ハザードモデルはとっても迟谤颈肠办测!
takehikoihayashi
?
PDF
机械学习におけるオンライン确率的最适化の理论
Taiji Suzuki
?
PDF
「内積が見えると統計学も見える」第5回 プログラマのための数学勉強会 発表資料
Ken'ichi Matsui
?
PDF
クラシックな机械学习の入門 3. 線形回帰および識別
Hiroshi Nakagawa
?
PDF
Transformer メタサーベイ
cvpaper. challenge
?
PDF
SSII2019TS: 実践カメラキャリブレーション ~カメラを用いた実世界計測の基礎と応用~
SSII
?
PDF
初めてのグラフカット
Tsubasa Hirakawa
?
PPTX
SSII2014 チュートリアル資料
Masayuki Tanaka
?
PDF
3次元レジストレーション(笔颁尝デモとコード付き)
Toru Tamaki
?
PDF
合成変量とアンサンブル:回帰森と加法モデルの要点
Ichigaku Takigawa
?
PPTX
多変量解析
Yoshihiro_Handa
?
PDF
Fisher Vectorによる画像認識
Takao Yamanaka
?
PDF
画像认识の初歩、厂滨贵罢,厂鲍搁贵特徴量
takaya imai
?
PDF
贰尝叠翱型痴础贰のダメなところ
KCS Keio Computer Society
?
滨尘补驳别闯チュートリアル
LPIXEL
?
滨尘补驳别闯を使った画像解析実习?大量の画像データに対する処理の自动化?
LPIXEL
?
画像解析の基础知识
LPIXEL
?
滨尘补驳别闯を使った画像解析実习?起动?终了とファイルの入出力?
LPIXEL
?
Kaggle RSNA Pneumonia Detection Challenge 解法紹介
理 秋山
?
条件付き确率场の推论と学习
Masaki Saito
?
比例ハザードモデルはとっても迟谤颈肠办测!
takehikoihayashi
?
机械学习におけるオンライン确率的最适化の理论
Taiji Suzuki
?
「内積が見えると統計学も見える」第5回 プログラマのための数学勉強会 発表資料
Ken'ichi Matsui
?
クラシックな机械学习の入門 3. 線形回帰および識別
Hiroshi Nakagawa
?
Transformer メタサーベイ
cvpaper. challenge
?
SSII2019TS: 実践カメラキャリブレーション ~カメラを用いた実世界計測の基礎と応用~
SSII
?
初めてのグラフカット
Tsubasa Hirakawa
?
SSII2014 チュートリアル資料
Masayuki Tanaka
?
3次元レジストレーション(笔颁尝デモとコード付き)
Toru Tamaki
?
合成変量とアンサンブル:回帰森と加法モデルの要点
Ichigaku Takigawa
?
多変量解析
Yoshihiro_Handa
?
Fisher Vectorによる画像認識
Takao Yamanaka
?
画像认识の初歩、厂滨贵罢,厂鲍搁贵特徴量
takaya imai
?
贰尝叠翱型痴础贰のダメなところ
KCS Keio Computer Society
?

Similar to 滨尘补驳别闯を使った画像解析実习?数?形态?分布の解析? (18)

PPTX
机械学习
ssusere8ae711
?
PPTX
R -> Python
Kazufumi Ohkawa
?
ODP
Real World OCamlを読んでLispと協調してみた
blackenedgold
?
PDF
たのしい関数型
Shinichi Kozake
?
PPTX
Feature Selection with R / in JP
Sercan Ahi
?
PDF
boost tour 1.48.0 all
Akira Takahashi
?
PDF
Python 机械学习プログラミング データ分析ライブラリー解説編
Etsuji Nakai
?
PPTX
[机械学习]文章のクラス分類
Tetsuya Hasegawa
?
PPTX
20180728 halide-study
Fixstars Corporation
?
PDF
ラズパイでデバイスドライバを作ってみた。
Kazuki Onishi
?
PDF
搁で学ぶロバスト推定
Shintaro Fukushima
?
PDF
衛星芸術Pbl 2011 10_18
Koichiro Mori
?
PDF
10分て?分かるr言語入門ver2.9 14 0920
Nobuaki Oshiro
?
PDF
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
de:code 2017
?
PDF
Introduction to NumPy & SciPy
Shiqiao Du
?
PDF
文献紹介:Deep Analysis of CNN-Based Spatio-Temporal Representations for Action Re...
Toru Tamaki
?
PPTX
論文解説:スマホカメラを用いたBRDFパラメータ取得技術(非DNN)「Two-Shot SVBRDF Capture for Stationary Mat...
Teppei Kurita
?
PDF
2013.12.26 prml勉強会 線形回帰モデル3.2~3.4
Takeshi Sakaki
?
机械学习
ssusere8ae711
?
R -> Python
Kazufumi Ohkawa
?
Real World OCamlを読んでLispと協調してみた
blackenedgold
?
たのしい関数型
Shinichi Kozake
?
Feature Selection with R / in JP
Sercan Ahi
?
boost tour 1.48.0 all
Akira Takahashi
?
Python 机械学习プログラミング データ分析ライブラリー解説編
Etsuji Nakai
?
[机械学习]文章のクラス分類
Tetsuya Hasegawa
?
20180728 halide-study
Fixstars Corporation
?
ラズパイでデバイスドライバを作ってみた。
Kazuki Onishi
?
搁で学ぶロバスト推定
Shintaro Fukushima
?
衛星芸術Pbl 2011 10_18
Koichiro Mori
?
10分て?分かるr言語入門ver2.9 14 0920
Nobuaki Oshiro
?
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
de:code 2017
?
Introduction to NumPy & SciPy
Shiqiao Du
?
文献紹介:Deep Analysis of CNN-Based Spatio-Temporal Representations for Action Re...
Toru Tamaki
?
論文解説:スマホカメラを用いたBRDFパラメータ取得技術(非DNN)「Two-Shot SVBRDF Capture for Stationary Mat...
Teppei Kurita
?
2013.12.26 prml勉強会 線形回帰モデル3.2~3.4
Takeshi Sakaki
?
Ad

滨尘补驳别闯を使った画像解析実习?数?形态?分布の解析?

  • 1. ImageJ を使った画像解析実習 数?形態?分布の解析 第194回農林交流センターワークショップ 「 植物科学?作物育種におけるフェノーム解析 - はじめて画像解析を行う研究者のための入門実習 - 」 2015-09-18 09:15-10:20 (実習75分) 実習主担当: 朽名 夏麿
  • 3. 例: アクチン繊維の配向解析 共焦点画像 バンドパスフィルタ による繊維等の強調 二値化像 細線化像 短径 / 長径 短径 長径 気孔開閉の指標 気孔に対する アクチン繊維の角度 アクチン繊維の配向の指標 気孔 θ 気孔 θ 気孔 この場合, 短径 / 長径=0.47 この場合, アクチン繊維の角度=54.3° 灰色: 気孔領域 黒色: アクチン繊維 シロイヌナズナ気孔 アクチン繊維
  • 4. バンドパスフィルタ Process > FFT > Bandpass Filter... 解析対象のおおよその大きさをもとに強調する処理. ノイズ,背景,シェーディングの影響を抑制する. 細胞表層微小管のプラス端 輝度プロファイル(左図の黄色い線)
  • 7. * stomata-actin.tif を開く. * Image > Stacks > Z Project... > Projection type = Max Intensity * Process > FFT > Bandpass Filter... Filter large... = 5 Filter small... = 1 Tolerance... = 0 * Image > Adjust > Threshold... > … > Apply * Process > Binary > Skeletonize * Plugins > LPX > Lpx_LinesAngle mode = map (可視化) * Plugins > LPX > Lpx_LinesAngle mode = eachSlice (定量)
  • 12. http://www.mathworks.com/matlabcentral/fileexchange/28790-colorspace-transformations 色空間 一般的なカラー画像では色彩の表現として, RGB (発光時に用いる色表現,カメラに用いる色表現) や CMYK (印刷に用いる色表現) が用いられる. 一方,バイオイメージング分野では 単色からスペクトルまで 多様な色情報のデータが 扱われている.
  • 13. (A) http://www.jiscdigitalmedia.ac.uk/guide/colour-theory-understanding-and-modelling-colour/ (B) http://w3.kcua.ac.jp/~fujiwara/infosci/colorspace/colorspace3.html その他 http://en.wikipedia.org/ よりそれぞれ引用 CIE1976 L*a*b* (CIELAB) color space L*: lightness, a* & b*: color-opponent space perceptually uniform RGB color space (A) (B) Additive primary colors: Red, Green, Blue mimic the nonlinear response of the eye
  • 14. RGB HSV YIQ CIE L*a*b* CIE XYZ 各種色空間への変換例 → CIE a* 軸がイネ地上部の領域抽出に向く.
  • 15. カラーパネル検出ならびに葉領域の抽出と細線化 原画像 CIELAB 色空間の a* 軸 a* が閾値以下の領域 葉領域画像 細線画像カラーパネル検出結果 カラーパネルの円の直径が既知(12.5 cm) であるため,スケールバーとして利用し, 比率 r [cm / pixel] を求める. 画像や細線化画像で測定された pixel 単位 の値を cm に換算するのに用いる. 緑色の領域は a* 軸では小さな値となる. 手作業で個体中心付近に設定した円(青色 で示す)と連結した白領域のみ抽出し, さらにモルフォロジカルフィルタ(close) によって領域境界の平滑化を行なうことで 葉領域を得た. 白黒画像の細線化アルゴリズムを適用して 得た. 他に輪郭画像を形態計測の際には作成 しているが,ここでは省略している.
  • 16. 形態特徴の測定法 1/3 葉領域画像 area1: イネ地上部の面積(cm2).葉領域画像中の白画素数 × r2 perimeter4conn: イネ地上部領域の周長(cm).輪郭画像中の白画素数 × r widthByAreaPeri4: 葉の幅に関する指標(cm).2 × area1 ÷ perimeter4conn complexity: 形状の複雑度.perimeter4conn 2 ÷( 4 π × area1 ) 拡大 輪郭画像葉領域画像 輪郭抽出
  • 17. 形態特徴の測定法 2/3 葉領域画像 skelLen: 葉の長さに関する指標(cm).細線画像中の白画素数 × r widthByAreaSkelLen: 葉の幅に関する指標(cm).area1 ÷ skelLen skelEnd: 葉の枚数に関する指標(個).細線画像中の端点の数 (赤い丸). skelBranch: 葉の混み具合に関する指標(個).細線画像中の分岐点の数 (黄色い丸). 拡大 細線画像葉領域画像 細線化 端点 端点 分岐点 分岐点
  • 18. 形態特徴の測定法 3/3 widthBySkelDisttrfmMean: 葉の幅に関する指標(cm).以下の手続きによって求める値. Step 1. 細線画像(左の画像)中のi 番目の白画素 Ai について( i は 1 から skelLen まで): Step 1-1. 画素Aiに最も近い,輪郭画像(右の画像)中の白画素を探し,これを画素Bとする. Step 1-2. 画素Aiと画素Biの距離(pixel)を求めて, di とする. Step 2. di の平均値(i は 1 から skelLen まで) × 2 r を widthBySkelDisttrfmMean とする. 細線画像 輪郭画像 画素Ai 画素Bi
  • 19. 実習 - RGB 各信号 への分解: Image > Color > Split Channels - その他の色空間の座標へ: Plugins > LPX > Lpx Color > mode = RGB2... もしくは Plugins > Filters > Color Transformer
  • 20. - 輝度を閾値とした2値化 Image > Adjust > Threshold - 面積の測定 Analyze > Analyze Particles - 細線化と線長の測定 Process > Binary > Skeletonize Analyze > Analyze Particles or KBI_Measure > blobMeasure... feature=chain_codes_8_totalLength - 端点抽出と計数 Plugin > LPX > Lpx_Filter2d > filtersForBilevel__ > pixSpec__ > pick,,end
  • 21. 例2: ブドウ葉の病斑解析 シートフィード式スキャナ (ScanSnap) で撮影. 画像提供: 農研機構 果樹研究所 河野淳 様 http://www.scansnap.net/escaneres-by-fujitsu/scansnap/s1100/
  • 23. ※スケール代わりの付箋紙にも注目. 回転 縮小 + CIE L* + ノイズ抑制 縮小 + CIE a* + ノイズ抑制 入力画像
  • 24. 入力画像 回転 縮小 + CIE L* + ノイズ抑制 縮小 + CIE a* + ノイズ抑制 拡大図
  • 26. 病斑領域の二値化 自動二値化だけで 常に 必要十分に 正しく 領域抽出するのは困難. → ユーザの目視による二値化基準の修正 + 二値化後の除去 (主に葉脈部を除くため円形度を閾値とした) 適切 (必要十分) 偽陰性(見逃し) あり 偽陽性(採り過ぎ)あり
  • 27. 葉領域 ならびに 病斑領域 の決定 葉領域 病斑領域 群葉領域
  • 29. 縮小率: 長さ比 1/shrink に縮小する. 葉領域のノイズ抑制 (to CIEL* 像). 葉領域の自動2値化アルゴリズム 病斑領域のノイズ抑制 (to CIEa* 像) 病斑領域の自動2値化アルゴリズム 葉領域の最小面積 Phase 1: 2値化による領域分割まで Phase 2: 領域分割後のフィルタリング 病斑領域の最小円形度
  • 30. object Ijp extends LpxPlugIn { private val leafThreffective = Seq('ijHuang, 'ijLi, 'ijMinimum, … private val spotThreffective = Seq('ijRenyiEntropy, 'ijYen, … private val leafThrSyms = leafThreffective ++ (plg.threshold.Common.ijSymbols.toSet -- leaf… } private val spotThrSyms = { spotThreffective ++ (plg.threshold.Common.ijSymbols.toSet -- spot… } private val mode = arg("kaMode", Seq('measure, 'setParam)) private val sep1 = arg("-- phase1 --") private val shrink = arg("shrink", 4) private val leafDenoise = arg("leafDenoise", 2.0) private val leafThr = arg("leafThr", leafThrSyms) private val spotDenoise = arg("spotDenoise", 1.0) private val spotThr = arg("spotThr", spotThrSyms) private val genStk = arg("genStk", false) private val sep2 = arg("-- phase2 --") private val leafMinArea = arg("leafMinAreaInOrg", 500000d) private val spotCircularity = arg("spotCircularity", 0.6) private val sep3 = arg("----") private val continuePlugIn = arg("continuePlugIn", true)
  • 31. // R G B private val colorLeaf = new java.awt.Color(128, 128, 128) private val colorSpot = new java.awt.Color(255, 255, 255) private val colorLeafId = new java.awt.Color( 0, 198, 255) private val colorSpotId = new java.awt.Color( 0, 255, 0) private val colorImageJForeground = new java.awt.Color(255, 255, 255) private val fontLeaf = new java.awt.Font("Serif", java.… private val fontSpot = new java.awt.Font("Serif", java.… def config(argStr: String): Option[() => Any] = { def rec() { val imp = IJ.getImage input(mode) mode.getSym match { case 'measure => measure(imp) case 'setParam => { if (setParam()) rec() } } } rec() None }
  • 32. private def measure(imp: Imp) { if (ImgC.is(imp)) { phase1(imp) } else { phase2() } } private def phase1(impOrg: Imp) { def bandpass(ip: Ip, loSd: Double, hiSd: Double): Ip = { new plg.band_pass.DiffOfGaussian(loSd, hiSd)(ip) } def bandpassMin0(ip: Ip, loSd: Double, hiSd: Double): Ip = { plg.band_pass.Min0(bandpass(ip, loSd, hiSd)) } def to8bit(ip: Ip): Ip = plg.filter2d.ToByteType.SliScale(ip) def toThrStk(ip: Ip): Ist = new plg.filter2d.ToStkByThrFromByte(A… def showAndSetCurSlice(ist: Ist, title: String, z: Int) { val impShow = new Imp(WindowManager.makeUniqueName(title), ist) impShow.setDisplayRange(0, 255, 7) impShow.updateAndDraw impShow.setSlice(z + 1) impShow.show }
  • 33. require(ImgC.is(impOrg), "ImgC.is") require(impOrg.getStackSize == 1, "getStackSize == 1") require(shrink() >= 1, "shrink >= 1") ij.gui.Toolbar.setForegroundColor(colorImageJForeground) impOrg.setTitle(WindowManager.makeUniqueName("org")) val ipOrg = impOrg.getProcessor.rotateRight impOrg.setProcessor(ipOrg) ipOrg.setInterpolationMethod(Ip.BILINEAR) val ipShrink = ipOrg.resize((ipOrg.getWidth / shrink().toFloat).r… val (ipCieL, ipCieA, ipCieB_notUsed) = new Rgb2ColorSpace(false).procSli(ipShrink, 'CIELAB2_speedy) val (numX, numY) = UtilImg.dim(ipCieL) val bpHiMax = numX.min(numY) // leaf: CIEL* val ipLeaf = to8bit(bandpassMin0(plg.filter_pt.MathOpMultiply(-1)… val thrLeaf = new IjThresholder(leafThr.getSym).getThr(ipLeaf).get() if (genStk()) { val istLeaf = toThrStk(ipLeaf) showAndSetCurSlice(istLeaf, "leaf", thrLeaf) } else { val imp = UtilImg.show(ipLeaf, f"leaf_${thrLeaf}") IJ.setThreshold(imp, thrLeaf, 255) }
  • 34. // spot: CIEa* val ipSpot = to8bit(bandpass(ipCieA, spotDenoise(), bpHiMax)) val thrSpot = new IjThresholder(spotThr.getSym).getThr(ipSpot).get() if (genStk()) { val istSpot = toThrStk(ipSpot) showAndSetCurSlice(istSpot, "spot", thrSpot) } else { val imp = UtilImg.show(ipSpot, f"spot_${thrSpot}") IJ.setThreshold(imp, thrSpot, 255) } } // use leafMinArea(), spotCircularity() private def phase2() { def getIpOfTitle(title: String): Ip = { val titles = UtilIj.getAllImageTitles() val hits = titles.filter(_.startsWith(title)) LpxExc.assert(hits.size == 1, f"Image '$' is not … val ip = WindowManager.getImage(hits.head).getProcessor LpxExc.assert(Img8.isBinary(ip), f"Image '$' must be … ip }
  • 35. def drawString(ipTgt: Ip, s: String, font: Font, color: Color, … ipTgt.setColor(color) ipTgt.setFont(font) val width = ipTgt.getStringWidth(s) ipTgt.drawString(s, x - width, y) } ij.gui.Toolbar.setForegroundColor(colorImageJForeground) val ipLeaf = getIpOfTitle("leaf") val ipSpot = getIpOfTitle("spot") LpxExc.assert(UtilImg.sameDim(ipLeaf, ipSpot), "dimension mismatch") val leafMinAreaInShrinked = (leafMinArea() / (shrink() * shrink()))… val leafBlobs = { PixGrp.filterOutSmall(PixGrp.getBlobs(ipLeaf), leafMinAreaInShr… } val spotBlobs = { val ipSpotInLeaf = Img8.dupRet(ipSpot, false) { ipSpotInLeaf => for (i <- 0 until ipSpot.getPixelCount if ipLeaf.get(i) == 0) { ipSpotInLeaf.set(i, 0) } } PixGrp.getBlobs(ipSpotInLeaf).filter(_.getCircularity >= spotCircularity()) }
  • 36. UtilIj.writeln(f"#shrink;?t${shrink()}") UtilIj.writeln(f"# areaAdjustFactor;?t${shrink() * shrink()}") UtilIj.writeln(f"#leafDenoise;?t${leafDenoise()}") UtilIj.writeln(f"#leafThr;?t${leafThr.getSym.name}") UtilIj.writeln(f"#spotDenoise;?t${spotDenoise()}") UtilIj.writeln(f"#spotThr;?t${spotThr.getSym.name}") UtilIj.writeln(f"#leafMinAreaInOrg;?t${leafMinArea()}") UtilIj.writeln(f"# leafMinAreaInShrinked;?t${leafMinAreaInShrinked}" UtilIj.writeln(f"#spotCircularity;?t${spotCircularity()}?n") for ((leafBlob, leafIdx) <- leafBlobs.zipWithIndex) { for (polRoi <- leafBlob.toPolygonRoi(true, true)) { plg.roi_util.Painter.drawByRoiInSitu(ipDebug, colorLeaf, polRoi) val awtRectangle = polRoi.getFloatPolygon.getBounds ipDebug.setColor(colorLeafId) val x = awtRectangle.x val y = awtRectangle.y + awtRectangle.height / 2 drawString(ipDebug, f"${leafIdx}", fontLeaf, colorLeafId, x, y) } val leafXySet = leafBlob.toXys.toSet val assocBlobs = spotBlobs.filter { spotBlob => val (centroidX, centroidY) = spotBlob.getCentroid leafXySet.contains((centroidX.round.toInt, centroidY.round.… } sortBy(- _.size)
  • 37. for ((blob, blobIdx) <- assocBlobs.zipWithIndex) { blob.drawToIpByColor(ipDebug, colorSpot) val x = blob.xsMin - 3 val y = (blob.ysMin + blob.ysMax) / 2 + 10 drawString(ipDebug, f"${blobIdx}", fontSpot, colorSpotId, x, y) } UtilIj.writeln(f"leafIdx;?t$leafIdx") UtilIj.writeln(f"leafArea;?t${leafBlob.size * shrink() * shrink(… UtilIj.writeln(f"spotNum;?t${assocBlobs.size}") val spotTotalArea = assocBlobs.map(_.size).sum UtilIj.writeln(f"spotTotalArea;?t${spotTotalArea * shrink() * shr… for ((spotBlob, spotIdx) <- assocBlobs.zipWithIndex) { UtilIj.writeln(f" spotArea;?t${leafIdx}-${spotIdx};?t" + f"${spotBlob.size * shrink() * shrink()}") } UtilIj.writeln("") } null }
  • 38. private def setParam(): Boolean = { input(sep1, shrink, leafDenoise, leafThr, spotDenoise, spotThr, genStk, sep2, leafMinArea, spotCircularity, sep3, continuePlugIn) mode.setIdx(0) continuePlugIn() } }