起因
使用ImageJ手动选定测定相对强度值操作繁琐、系统误差大,遂考虑用Python自动化的手段达到目的。
需求
首先检测荧光图像中参照通道的高亮点,并根据高亮点位置画设定大小的选择圈,然后在目的通道与参照通道的中测定选定圈内的中间密度值(int-density),最后计算两个通道的比值。
核心代码
import os
from skimage import io,data,filters
from PIL import Image, ImageDraw,ImageFont
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
def mat2gray(image):
"""
归一化函数(线性归一化)
:param image: ndarray
:return:
"""
# as dtype = np.float32
image = image.astype(np.float32)
image = (image - np.min(image)) / (np.max(image)-np.min(image)+ 1e-14)
return image
def show2D(img2D):
plt.imshow(img2D,cmap=plt.cm.gray)
plt.show()
#分离通道并优化处理
def channel(pic):
#分离通道
pic_1_raw = pic[:,:,1] #参考通道-根据具体情况设定
pic_0 = pic[:,:,0] #目的通道
#高斯模糊gamma通道-可选,在需要将两个位置极近的点算作单个目标的时候使用
pic_1 = filters.gaussian(pic_1_raw,sigma=3)
pic_1 = pic_1 * 255
show2D(pic_0)
show2D(pic_1)
return pic_0,pic_1
# 检测gamma的高亮点并且计算两个通道的比值
#bright_threshold亮度阈值,根据需求调整0-1。pixel_range画圈范围,根据需要调整单位为像素
def highlight(pic_1,pic_0,bright_threshold,pixel_range,name):
# 检测gamma的高亮点
pic_1_mask = (mat2gray(pic_1)>=bright_threshold).astype(float)
from skimage import measure, color
pic_1_mask_point = measure.label(pic_1_mask, connectivity=pixel_range)
final_list = []
radius = 5
index_mask = np.zeros(pic_1_mask_point.shape) # 写上数字
index_mask = Image.fromarray(index_mask)
d = ImageDraw.Draw(index_mask)
fnt = ImageFont.truetype(r"/System/Library/Fonts/AppleSDGothicNeo.ttc", 30)
for point_index in range(1, np.max(pic_1_mask_point)+1):
# 记录坐标
dim = np.where(pic_1_mask_point ==point_index)
dim0,dim1 = [dim[0][0], dim[1][0]]
# 读取point所在范围
bbox = [np.min(dim[0]), np.max(dim[0]), np.min(dim[1]), np.max(dim[1])]
bbox[0] -= radius
bbox[1] += radius
bbox[2] -= radius
bbox[3] += radius
# 计算强度比
intens = (np.sum(pic_0[bbox[0]:bbox[1], bbox[2]:bbox[3]])) / (np.sum(pic_1[bbox[0]:bbox[1], bbox[2]:bbox[3]])+1e-12)
# 记录
final_list.append([point_index, intens])
# 在mask写上数字
d.text((dim1,dim0), str(point_index), font=fnt)
index_mask = np.array(index_mask)
show2D(index_mask)
results=pd.DataFrame(columns=name,data=final_list)#数据有三列,列名分别为one,two,three
return results,index_mask #results 为pd数据,index_mask为图像数据
if __name__ == '__main__':
pic = io.imread(file) #file为文件路径
pic_b,pic_a = channel(pic)
results,index_mask = highlight(pic_1=pic_a,
pic_0 = pic_b,
bright_threshold = 0.38, #定义筛选阈值
pixel_range = 2,#定义画圈范围
name = ['No','b/a']#定义文件名
)
print(results)
savepath,rawfile = os.path.split(file) #分出原路径为保存路径
results.to_csv(savepath+'/results.csv',encoding='gbk') #保存为csv
io.imsave(savepath+'/conuts-mask.tif', index_mask) #mask文件保存为tif
到这里荧光图片就能够按照我的需求处理了,下一次将测试批量自动测定并合并整理CSV数据