此处以批量缩小ROI为例介绍如何利用shapely模块对ROI进行调整。
由于在ImageJ中选取ROI太小操作上会有点困难,所以有时候为了提高效率,会先稍微选取大一点的范围。但这样做不仅包含了信号区域,同时还包含了较多的背景区域,这个时候的采样就不是“纯”的信号了。有一种方案就是批量操作ROI,比如把它缩小一点。
from roifile import roiread, ImagejRoi
import numpy as np
from shapely import geometry as geo
def roi_shrink(roi, ratio=0.1, verbose=False):
'''
roi: roifile读取后的roi对象
'''
assert ratio>0 and ratio<1
roi_ = geo.Polygon(roi.coordinates())
x, y = roi_.centroid.xy
cx = x[0]
cy = y[0]
# 遍历所有轮廓上的点,找到一个距离质心最短的点,避免过度缩放
xs, ys = roi_.exterior.xy
idx = 0
ds = []
for xn, yn in zip(xs, ys):
# 快速计算两点之间距离
d = np.linalg.norm([xn-cx, yn-cy])
ds.append(d)
idx += 1
idy = np.argmin(ds)
mx = xs[idy]
my = ys[idy]
md = ds[idy]
# 确定要缩小的buffer量(像素单位)
td = md*ratio
roi_2 = roi_.buffer(-td) # 如果要放大就去除负号
if verbose:
print(f"buffer={td}")
# 构造一个新的roi对象
x2, y2 = roi_2.exterior.xy
locs = np.array([x2, y2]).T
roi2 = ImagejRoi.frompoints(locs)
roi2.roitype=roi.roitype
roi2.name = roi.name
return roi2
上述代码算是一个ROI和Shapely综合利用的模板案例,事实上在这类抽样的问题中,更多是在ImageJ使用更为方便的点选,这样得到的是一个点,然后再buffer扩大来选取像素。