# 側流道內的微流井 Microwell in side channel 以下將會介紹怎麼圈選出 side channel 的 microwell,如下圖: ![](https://i.imgur.com/INK3GuK.jpg) 圈選成功的話會長這樣: ![](https://i.imgur.com/fdJyTJI.png) 再放大一些: ![](https://i.imgur.com/Y9J0HUn.png) ## 分析思路 ### 目標 以 side channel 為單位,圈選出該 side channel 內的 12 個 microwell 再移動到下一個 side channel,這樣得到的數據才比較有規律,方便之後計算各個 side channel 的平均,或是依據距離中間主流道分組計算平均。 ### 作法 1. 用巢狀迴圈算出每個 side channel 中的最左上的 microwell 2. 在上面的迴圈內再加入新的巢狀迴圈,算出 12 個 microwell 的位置 :::info - 以上共四層迴圈 - 每算出一個就加到 ImageJ 的 ROI manager 中 ::: ## 執行流程 提示使用者要先選好四個角落 ``` java= waitForUser("Tips", "Please select 4 points. TL, BL, TR, BR."); ``` --- 通常顯微鏡拍出來的影像會自動帶入一個scale,但通常都是不對的,所以為了方便後續單位統一,這邊都移除,用像素(pixel)就好 ```java=+ // remove scale run("Set Scale...", "distance=0 known=0 unit=pixel"); ``` --- 使用`selectionType()`來判斷前面是否有成功選取四個角落 `-1`表示沒有選取 `10`表示為point selection 最後再用`getSelectionCoordinates(xPoints,yPoints)`來取得四個角落的座標,它們的x,y會依序存進`xPoints`和`yPoints`這兩個Array中 ```java=+ s = selectionType(); // get coordinates if( s == -1 ) { exit("There was no selection."); } else if( s != 10 ) { exit("The selection wasn't a point selection."); } else { getSelectionCoordinates(xPoints,yPoints); } ``` --- 接下來,要判斷四個點的相對關係,看哪個是左上、左下、右上、右下 這邊我使用的判斷方式是計算出四點的重心之後,觀察它跟重心座標的相對關係 要計算出Array中的數值的平均值,要使用`Array.getStatistics` :::warning :warning: 由於排列上有可能會是歪的,因此不適合直接比較四點座標來判斷相對位置 ::: ```java=+ // define tl, bl, tr, br Array.getStatistics(xPoints, xmin, xmax, xmean, xstdDev); Array.getStatistics(yPoints, ymin, ymax, ymean, ystdDev); for (i=0; i<4; i++) { if (xPoints[i] < xmean && yPoints[i] < ymean) { tl_x = xPoints[i]; // top left of circle tl_y = yPoints[i]; // top left of circle } else if (xPoints[i] < xmean && yPoints[i] > ymean) { bl_x = xPoints[i]; // bottom left bl_y = yPoints[i]; } else if (xPoints[i] > xmean && yPoints[i] < ymean) { tr_x = xPoints[i]; // top right tr_y = yPoints[i]; } else { br_x = xPoints[i]; // bottom right br_y = yPoints[i]; } } ``` --- 確認四個角落的座標後,把座標輸出,並將輸出的座標儲存在第`48`~`55`行中,下次分析就可以將這段取消註解,並上面所有程式碼註解掉,即可再現分析結果 (每次選取位置都可能會有誤差) ```java=+ print("tl_x = " + tl_x); print("tl_y = " + tl_y); print("bl_x = " + bl_x); print("bl_y = " + bl_y); print("tr_x = " + tr_x); print("tr_y = " + tr_y); print("br_x = " + br_x); print("br_y = " + br_y); /* //parameters: tl_x = 550 tl_y = 710 bl_x = 353.6667 bl_y = 1797.5 tr_x = 14826.5 tr_y = 284.5 br_x = 14627.75 br_y = 1361.25 */ ``` --- 依據待分析的影像設定參數,其中`r`指的是待分析的圓圈的半徑,我習慣設定的略小於實際microwell的大小,以確保不會圈選到microwell以外的區域而產生誤差。 不同焦距、顯微鏡放大倍率等都會影響到`r`的理想值,所以分析時需確認一下半徑`r`是否需要調整 ```java=+ r = 70; column = 32; row = 2; ``` --- 計算microwell的間距 :::warning :warning: 儘管理論上microwell array應該是一個平行四邊形,但是實際上會有一些誤差,因此這邊我在四條邊界都有計算間距,之後就可以用內差的方式算出所有的microwell位置 ::: ```java=+ v_dx_l = (bl_x - tl_x)/(row -1); // vertical left v_dy_l = (bl_y - tl_y)/(row -1); v_dx_r = (br_x - tr_x)/(row -1); // vertical right v_dy_r = (br_y - tr_y)/(row -1); h_dx_t = (tr_x - tl_x)/(column -1); // horizontal top h_dy_t = (tr_y - tl_y)/(column -1); h_dx_b = (br_x - bl_x)/(column -1); // horizontal bottom h_dy_b = (br_y - bl_y)/(column -1); ``` --- 畫出左上 (第一個) 圓圈,並記錄其相關數值 ```java=+ // create the circles makeOval(tl_x - r, tl_y - r, r*2, r*2); getSelectionBounds(x, y, w, h); setSelectionLocation(x, y); ``` --- 開始以巢狀迴圈設定所有位置 ```java=+ for (i=0; i<row; i++) { j = 0; if (i != 0) { roiManager("select", 0); // select the first rectangle } // select the first rectangle, than move down getSelectionBounds(x, y, w, h); setSelectionLocation(x + i*v_dx_l, y + i*v_dy_l); roiManager('Add'); //print(i); //waitForUser("Tips", "i="); //---------------------------------------------------------------- tl_x = 551; tl_y = 711; bl_x = 568; bl_y = 1287; tr_x = 666; tr_y = 706; br_x = 684; br_y = 1284; sv_dx_l = (bl_x - tl_x)/(6 -1); sv_dy_l = (bl_y - tl_y)/(6 -1); sh_dx_t = (tr_x - tl_x)/(2 -1); // horizontal top sh_dy_t = (tr_y - tl_y)/(2 -1); sh_dx_b = (br_x - bl_x)/(2 -1); // horizontal bottom sh_dy_b = (br_y - bl_y)/(2 -1); for (m=0; m<6;m++) { n = 0; if (m != 0) { roiManager("select", i*2*6*column); } getSelectionBounds(x, y, w, h); setSelectionLocation(x + m*sv_dx_l, y + m*sv_dy_l); if (m != 0) { roiManager('Add'); //print(i,m); //waitForUser("Tips", "i, m="+ i + m); } sh_dx = ((6 - m)*sh_dx_t + m*sh_dx_b)/6; sh_dy = ((6 - m)*sh_dy_t + m*sh_dy_b)/6; for (n=1; n<2; n++) { if (n == 1) { getSelectionBounds(x, y, w, h); } setSelectionLocation(x + n*sh_dx, y + n*sh_dy); // move right roiManager('Add'); //print(i,m,n); //waitForUser("Tips", "i, m, n="); } } //-------------------------------------------------------------- roiManager("select", i*2*6*column) h_dx = ((row - i)*h_dx_t + i*h_dx_b)/row; h_dy = ((row - i)*h_dy_t + i*h_dy_b)/row; for (j=1; j<column; j++) { if (j !=1) { roiManager("select", i*2*6*column); getSelectionBounds(x, y, w, h); } if (j == 1) { getSelectionBounds(x, y, w, h); } setSelectionLocation(x + j*h_dx, y + j*h_dy); // move right roiManager('Add'); for (m=0; m<6;m++) { n = 0; if (m != 0) { roiManager("select", i*2*6*column + j*2*6); } getSelectionBounds(x, y, w, h); setSelectionLocation(x + m*sv_dx_l, y + m*sv_dy_l); if (m != 0) { roiManager('Add'); } sh_dx = ((6 - m)*sh_dx_t + m*sh_dx_b)/6; sh_dy = ((6 - m)*sh_dy_t + m*sh_dy_b)/6; for (n=1; n<2; n++) { if (n == 1) { getSelectionBounds(x, y, w, h); } setSelectionLocation(x + n*sh_dx, y + n*sh_dy); // move right roiManager('Add'); } } } } ```