---
# System prepended metadata

title: 側流道內的微流井 Microwell in side channel

---

# 側流道內的微流井 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');
			}
			
		}
	}
}

```