Python实现生物医学大图像分块切片与拼接(无信息损失)
大IHC图像通道分离的分块处理方案
针对大图像处理时的内存不足问题,我们可以通过分块处理的方式,将图像切割成小切片逐一处理,最后拼接回完整图像。以下是适配原scikit-image通道分离逻辑的完整实现:
完整代码实现
import numpy as np import matplotlib.pyplot as plt from skimage import data from skimage.color import rgb2hed, hed2rgb from skimage.exposure import rescale_intensity def split_image_into_blocks(image, block_size=(512, 512)): """将图像分割成指定大小的非重叠块""" height, width = image.shape[:2] blocks = [] # 遍历所有块的起始坐标 for y in range(0, height, block_size[0]): for x in range(0, width, block_size[1]): # 处理边缘块(如果图像尺寸不是块大小的整数倍) y_end = min(y + block_size[0], height) x_end = min(x + block_size[1], width) block = image[y:y_end, x:x_end] blocks.append((y, x, y_end, x_end, block)) return blocks def process_block(block, h_percentile, d_percentile): """对单个图像块执行通道分离和伪荧光转换""" # 通道分离 ihc_hed = rgb2hed(block) null = np.zeros_like(ihc_hed[:, :, 0]) # 原代码的单通道RGB可视化(可选,若不需要可注释) ihc_h = hed2rgb(np.stack((ihc_hed[:, :, 0], null, null), axis=-1)) ihc_e = hed2rgb(np.stack((null, ihc_hed[:, :, 1], null), axis=-1)) ihc_d = hed2rgb(np.stack((null, null, ihc_hed[:, :, 2]), axis=-1)) # 基于全局统计的强度缩放,生成伪荧光图 h = rescale_intensity(ihc_hed[:, :, 0], out_range=(0, 1), in_range=(0, h_percentile)) d = rescale_intensity(ihc_hed[:, :, 2], out_range=(0, 1), in_range=(0, d_percentile)) zdh_block = np.dstack((null, d, h)) return zdh_block, ihc_h, ihc_e, ihc_d def main(): # 替换为你的大图像加载代码,例如用skimage.io.imread # 这里用示例图像模拟大图像(可以重复拼接成更大的图) ihc_rgb = data.immunohistochemistry() # 模拟大图像:(2048, 2048, 3) ihc_rgb_large = np.tile(ihc_rgb, (4, 4, 1)) height, width = ihc_rgb_large.shape[:2] block_size = (512, 512) # -------------------------- # 步骤1:全局统计H和D通道的99百分位数 # -------------------------- h_values = [] d_values = [] blocks = split_image_into_blocks(ihc_rgb_large, block_size) for _, _, _, _, block in blocks: hed_block = rgb2hed(block) h_values.append(hed_block[:, :, 0].flatten()) d_values.append(hed_block[:, :, 2].flatten()) # 计算全局99百分位数 h_percentile = np.percentile(np.concatenate(h_values), 99) d_percentile = np.percentile(np.concatenate(d_values), 99) # -------------------------- # 步骤2:分块处理并初始化结果图像 # -------------------------- zdh_result = np.zeros_like(ihc_rgb_large, dtype=np.float64) # 若需要保存单通道可视化结果,可初始化对应的数组 ihc_h_result = np.zeros_like(ihc_rgb_large, dtype=np.float64) ihc_e_result = np.zeros_like(ihc_rgb_large, dtype=np.float64) ihc_d_result = np.zeros_like(ihc_rgb_large, dtype=np.float64) for y, x, y_end, x_end, block in blocks: zdh_block, ihc_h_block, ihc_e_block, ihc_d_block = process_block(block, h_percentile, d_percentile) # 将处理后的块放回结果图像对应位置 zdh_result[y:y_end, x:x_end] = zdh_block ihc_h_result[y:y_end, x:x_end] = ihc_h_block ihc_e_result[y:y_end, x:x_end] = ihc_e_block ihc_d_result[y:y_end, x:x_end] = ihc_d_block # -------------------------- # 步骤3:可视化结果(可选) # -------------------------- fig, axes = plt.subplots(2, 3, figsize=(12, 8)) ax = axes.ravel() ax[0].imshow(ihc_rgb_large) ax[0].set_title("Original Large Image") ax[0].axis('off') ax[1].imshow(ihc_h_result) ax[1].set_title("Hematoxylin") ax[1].axis('off') ax[2].imshow(ihc_e_result) ax[2].set_title("Eosin") ax[2].axis('off') ax[3].imshow(ihc_d_result) ax[3].set_title("DAB") ax[3].axis('off') ax[4].imshow(zdh_result) ax[4].set_title("Pseudofluorescent (D+G)") ax[4].axis('off') ax[5].axis('off') fig.tight_layout() plt.show() if __name__ == "__main__": main()
关键逻辑说明
- 分块函数:
split_image_into_blocks将大图像切割成指定大小的非重叠块,自动处理边缘不足一个块的情况,避免遗漏像素。 - 全局百分位数统计:先遍历所有块收集H和D通道的像素值,计算全局99百分位数,确保单块处理时的强度缩放和整图处理结果一致,避免出现块间亮度差异。
- 单块处理:
process_block复用原代码的通道分离和伪荧光转换逻辑,仅针对单个块操作,大幅降低内存占用。 - 结果拼接:初始化和原图像尺寸一致的结果数组,将每个处理好的块放回对应坐标位置,最终得到完整的处理后图像。
注意事项
- 可根据你的内存情况调整
block_size,内存充足可设大一点,内存紧张则设小。 - 若不需要单通道的RGB可视化结果,可以注释掉对应代码,进一步节省内存。
- 加载大图像时建议用
skimage.io.imread或PIL.Image.open配合逐块读取(如果图像格式支持),避免一次性加载整图。
内容的提问来源于stack exchange,提问作者Burgera
相关产品推荐
相关产品推荐

