阿簡生物筆記

2018年11月5日

用imagej加手機前鏡頭偵測脈搏






有很多手機app都可以利用手機的前後鏡頭來偵測脈搏,只要手指蓋住鏡頭,App可以自動偵測出脈搏。其原理是計算每幀影格的像素強度變化,可能做些濾波和數值處理。

其實好幾年前就想自己寫個程式來偵測看看,但是當時對於電腦視覺根本不熟,現在想想其實imagej就可以做處理了。

讀入影像
1.使用fiji,先在Help/Update..,更新imagej,然後在Imagej Updater的視窗左下角選擇Manager Update sites,勾選FFMPEG,然後Apply Changes。這會加入一個匯入mp4影像的外掛。安裝後重新啟動fjij



2.開啟fiji,在File/Import/Movie(ffmpeg),把拍攝的影片匯入成stack。
3.由於影片的前後不一定是需要的部份,比方說還沒拍到手指,或是手指已經離開。因此需要剪接stack。不過imagej對於stack內的slices刪除不是很好用(或者是說我還沒找到好方法),所以建議是用複製影格的方式來做,比方說第10影格到第90影格才是需要的部份,那就在Image/Duplicate...把要的影格複製出來成一個stack。

繪製像素強度變化圖(即脈搏圖)
1.利用方框選取工具,然後選擇Image/Stack/Plot z-axis profile,即可以畫出如下圖的脈搏圖




如果不嫌費工夫,也可以把stack在分離出不同色頻來分析,例如這個是分析R Channel的強度變化,雜訊會少很多。方法有點複雜
1.利用Image/Type/RGB Stack,可以把原始的stack分離出不同的色頻,然後再用Image/Stack/Plot z-axis profile來繪製。




同樣也可以分離出HSB,這個是亮度B( brightness )的圖



以下是處理過程的教學影片

2018年10月30日

用Imagej疊圖看水波干涉的腹線(antinodal line)

前幾天看到小p拿出他的兵器-做水波干涉實驗的兵器,錄製了一段影片。突然我想到我在這篇《imagej將時間資料視覺化》寫到imagej可以將時間資料濃縮,可以從中看出特別的時間資訊。

一時手癢就來把小p拍攝的影片用imagej疊圖分析看看。

1.先用youtube-dl把影片用mp4格式下載回來。
2.用fiji(特製的imagej)的file/import/Movie(FFMPEG)將mp4檔讀成stacks
3.用Image/Stacks/Z Project製作疊圖

以下分別是用Min intensity和standard deviation製作的疊圖






Min intensity是把影像中每個隨著時間變化的像素,用最小的數值(相當於最暗的)去疊出來。

而standard deviation的圖我是第一次用這疊,發現還蠻有趣的。疊出來的影像中,黑色的部份代表標準差很小,意思就是數值變動不大,所以在影片中沒什麼變化的點就會呈現黑色。而動得越厲害的部份,就會越彩色。所以左方的水波產生器顏色就很彩色。

把影片做成疊圖來分析,在看水波干涉時產生的腹線(antinodal line),如中央腹線、第一腹線、第二腹線等可是特別明顯呢。

2018年10月28日

使用imagej的Macro切割細胞與細胞追蹤



來自網友的這個提問,其實目的是要做細胞追蹤,要處理的是細胞分裂的影片。希望能將A細胞在每個影格都能定位出來,網友也提供了判斷邏輯。將第一影格的A細胞和第二影格的兩個細胞都做交集處理,看看和第二影格的哪個細胞交集的比較多,就可以找到第二影格的A細胞在哪。

由於之前沒有寫過類似的Macro,所以也看了幾次說明文件,還參考了其他人寫的Macro,總算是寫出來了。要處理這個問題之前,其實得先把細胞切割好,還好網友已經先切好了給我處理。



影片中用的Macro我貼在本文最後,使用前提是要用wand tool先點選一個細胞,加入ROI Manager之後,再去執行Macro。

雖然網友已經提供給我切割好的細胞輪廓,不過我也還是手癢想處理看看這個影片,想說有沒有辦法可以把細胞切割好,不過我試了好幾個方法都切不好。最後只好用半自動的方法來做。

方法是先手動在細胞分界處劃線,存成ROI,再用這個ROI去切割開細胞。具體的作法就看影片囉



*********************************


setBatchMode(true);
setAutoThreshold("Default");
width = getWidth;
height = getHeight;

n = getSliceNumber();



for (i=n; i<=nSlices-1; i++) {
//for (i=n; i<=n; i++) {
print("==========");
print("i=",i);
roiMan_n = roiManager("count");
print("roiMan_n=",roiMan_n);

run("Select None");
setSlice(i+1);

run("Analyze Particles...", "display add slice");
roiMan_n_new = roiManager("count");
print("roiMan_n_new=",roiMan_n_new);

//計算下一張Slice增加了多少個ROI
roi_add = roiMan_n_new - roiMan_n ;
print("roi_add=",roi_add);

roiManager("Show None");

AND_Big_area= 0; //預設取交集後的面積為零
AND_Big_area_n = 0 ;//預設取交集後的面積,最大的是第零個

for (j=1; j<=roi_add; j++) {
roiManager("Select", newArray(roiMan_n-1,roiMan_n-1+j));
roiManager("AND");
getStatistics(area);
print("j=",j,",area=",area);

//沒交集的面積會回報成整張圖片的面積,所以將回報面積設為0
if(area == width * height){
area =0;
}

if(area>AND_Big_area){
AND_Big_area = area;
AND_Big_area_n = j;
}
}
print("Big=",AND_Big_area_n);
print("AND_Big_area=",AND_Big_area);

//select biggest area and add the new ROI in the next slice
roiManager("Select", roiMan_n -1 + AND_Big_area_n);
roiManager("Add");

//delete all new ROI in the next slice
for (j=1; j<=roi_add; j++) {
roiManager("Select", roiMan_n-1+1);
roiManager("Delete");
}

}

resetThreshold();
setBatchMode(false);

使用imagej將影像中的維管束群組化

最近一個網友來信問到的問題,是和影像群組化有關的。這方向的問題也是很多提問的人會問到的,不如在影片中詳細解說一下,有此疑惑的也可以藉此練習看看。


就以下面這圖為例,大方塊和小方塊在做Analyze Particles時,會被視作是不同的兩個Particle,但是如果我們的需求是要把這兩個圈在同一個ROI,那應該怎麼做?



什麼時候會有這種情況呢?來看看這個例子,這是竹子維管束的圖片,右圖是進行threshold之後,維管束分離的樣子,而在分析的時候,我們需要將那些分離的小碎片視作是一個完整的Particle。


以下四部影片就是在介紹這些步驟

第一部影片:imagej 將分散的小區塊用二值化影像處理流程做群組1 二值化處理的功能說明
是進行二值化處理的教學流程,介紹erode、dilate等程序的作用

第二部影片:imagej 將分散的小區塊用二值化影像處理流程做群組2 一步一步說明
利用上述的二值化程序一步一步說明,如何將影像中分散的小顆粒在分析時處理成一個完整的部份。


第三部影片:imagej 將分散的小區塊用二值化影像處理流程做群組3 用程式碼加快處理流程
將第二部的步驟化處理程序寫成Imagej的Macro程式碼。程式碼的檔案我放在雲端硬碟,文字我也貼在本文的最後。



第四部影片:imagej用Macro將影像的ROI都各自存圖
將分析後的ROI各自存成圖,然後再組成一個Montage
結果會如這張圖

程式碼比較簡單一些,我直接貼在這邊
***********************
path = "/home/shawn-pc/桌面/crop/";
//path="c:/users/user/Desktop/crop/";
fileTitle=getTitle; 

for (i=0; i<roiManager("count"); ++i) {
    roiManager("Select", i);
    roiname = call("ij.plugin.frame.RoiManager.getName", i);
    run("Duplicate...", "title=crop");
    saveAs("Jpeg", path + roiname +".jpeg");
    close();
    //Next round!
    selectWindow(fileTitle);
}

***********************


第三部影片提到的程式碼,則是這樣
*************************
//input = "C:/Users/user/Desktop/roi/";
input = "/home/shawn-pc/桌面/imagej竹子維管束/roi/"

particle_size = "70-140";
particle_size_connect= "150-500";
particle_size_horseshoe = "30-200";
particle_size_fragment = "10-100";


particle_cir = "0.6-1.0";
particle_cir_01 = "0.0-1.0";


analy_string = "size="+ particle_size +" circularity="+ particle_cir +" show=Masks clear include summarize add";
analy_string_connect = "size="+ particle_size_connect +" circularity= " + particle_cir_01 +" show=Masks clear include summarize add";
analy_string_horseshoe = "size="+ particle_size_horseshoe +" circularity= " + particle_cir_01 +" show=Masks clear include summarize add";
analy_string_fragment = "size="+ particle_size_fragment +" circularity= " + particle_cir_01 +" show=Masks clear include summarize add";

function single(m){
run("Duplicate...", "title="+m);
run("Analyze Particles...", analy_string);
if(Table.size != 0){
//if ((Table.get("Count",Table.size-1)) != 0) { 
roiManager("Save", input + m +".zip");

selectWindow("0");
n=roiManager("count");
for(i=0;i<n;i++){
roiManager("Select", i);
setForegroundColor(255, 255, 255);
run("Fill", "slice");
}
}
n=roiManager("count");
for(i=0;i<n;i++){
roiManager("Select", 0);
roiManager("delete");
}
run("Select None");
roiManager("show none");
close("Mask of "+m);
close("Mask of 0");
close("Mask of Mask of 0");
close(m);

}

function connect(m){
run("Analyze Particles...", analy_string_connect);
run("Watershed");
single(m);
}

//=========================================


name=getTitle; 
run("Duplicate...", "title=0");
setAutoThreshold("Default");
run("Convert to Mask");

single(1);

connect(2);

//抓馬蹄形,單獨的
run("Analyze Particles...", "size=70-140 circularity=0.00-1.00 show=Masks clear include summarize add");
run("Close-");
single(3);

//抓馬蹄形,連在一起的
run("Analyze Particles...", analy_string_horseshoe);
run("Close-");
connect(4);

//抓碎片
run("Analyze Particles...", analy_string_horseshoe);
run("Close-");
single(5);

//抓更碎片
run("Analyze Particles...", analy_string_fragment);
run("Close-");
run("Dilate");
run("Fill Holes");
run("Watershed");
run("Erode");
single(6);


//抓更更碎片
run("Analyze Particles...", analy_string_fragment);
run("Dilate");
run("Fill Holes");
run("Erode");
single(7);




list = getFileList(input);
for (i = 0; i < list.length; i++){
roiManager("Open", input+list[i]);

}


selectWindow(name);
roiManager("show none");

roiManager("Show All without labels");


*************************

2018年10月12日

用在生態系的AR App介紹: WWF Free Rivers

昨天看到Apple網站上對新版本的iPad的廣告,特別強調了AR擴增實境的介紹。特別點進去看,看到了介紹幾款APP,然後我就試用了這個WWF Free Rivers。

這是WWF世界自然基金會出品的,簡單地說這個APP是個用AR方式帶你看一個模型裡發生的故事,本身互動性我覺得還好,沒有什麼特別的互動功能,但是能夠你讓你用上帝的視角去東看西看。

APP一開始先讓你設定模型的位置,你需要一張桌子(或是地板),然後你就決定模型要擺放的方向。這APP有中文介面,也有中文介紹,畫面就如同下面這樣,是個以河流為主的模型。不過陸域的設定其實是綜合的,看那裏面的動物,同時有熊、獅子、老虎、鱷魚還有白鱀豚...。大概是包含了非洲草原、熱帶雨林、三角洲等等之類的。



可以看看河流和周圍動物的之間的關係,或是人類怎麼利用河流,然後故事會進展到看到起雲降雨(這個場景用AR來看還蠻有意思的),接著就是蓋起水壩,看看水壩上游和下游有什麼不同,然後就是拆掉水壩再看看有什麼變化。蓋水壩是為了能源需求,所以場景中也加入了可以用風力發電來提供能源。












除了上述的場景外,也提供另外一個體驗,它像是你面向一個大展版,展板前方還有一些模型這樣。







我覺得這個APP在生態和環境的課程中應該可以使用看看,不過就不適合老師絮絮叨叨地介紹,應該是提供一個觀察提問的指引單,讓學生透過模型去看那些現象。

你可能對這有興趣

Related Posts Plugin for WordPress, Blogger...