如何合并使用 openslide-python

问题描述

我正在尝试以正确的顺序组合拼贴,使它们最终成为相同的整个幻灯片图像(.svs 文件)。

根据以下函数文件路径中读取 .svs 文件

def open_slide(filepath = None):
try:
    slide = openslide.open_slide(filepath)
   
except OpenSlideError as o:
    print("Error" + str(o))
    
    slide = None
except FileNotFoundError as f:
    print("Error" +  str(f))
    slide = None
return slide

在下图中,我正在尝试使用 openslide-python 的 DeepZoom 生成器合并我得到的图块(请参阅下面的代码片段)

def create_tile_generator(slide,tile_size,overlap):
 gen = DeepZoomGenerator(slide,tile_size=tile_size,overlap=overlap,limit_bounds=False)

这就是我如何将 .svs 拆分成它的图块:

def split_wsi_to_tiles(wsi_path = None):
print("splitting wsi into tiles")
tile_indices = process_slide(slide_num = SLIDE_NUM,filepath= wsi_path,tile_size = TILE_SIZE,overlap = OVERLAP)
i = 0
tile_indices_savepath  = os.path.join(os.getcwd(),"saved","tile_indices")
save_file(filepath = tile_indices_savepath,filename=name,file= tile_indices)
for ti in tile_indices:
    suffix =  str(i)
    (slide_num,tile) = process_tile_index(tile_index =ti,filepath = svs_path )
    tile = cv2.cvtColor(tile,cv2.COLOR_BGR2RGB)
    cv2.imwrite(save_path + suffix + ext,tile)
    i = i + 1
print("done splitting wsi into tiles")
return tile_indices_savepath

下面给出了辅助函数 process_slide 和 process_tile_index

def process_slide(slide_num =1,filepath= None,tile_size = 256,overlap = 0):
slide = open_slide(filepath = filepath)
generator = create_tile_generator(slide,overlap)
zoom_level = get_40x_zoom_level(slide,generator)
print("zoom level set to " + str(zoom_level))
cols,rows = generator.level_tiles[zoom_level - 1]
tile_indices = [(slide_num,overlap,zoom_level,col,row)
              for col in range(cols) for row in range(rows)]
return tile_indices
def process_tile_index(tile_index=None,filepath= None):
    slide_num,row = tile_index
    slide = open_slide(filepath = filepath)
    generator = create_tile_generator(slide,overlap)
    tile = np.asarray(generator.get_tile(zoom_level,(col,row)))
    return (slide_num,tile)

get_40x_zoom_level 函数说明:

def get_40x_zoom_level(slide,generator):
global level
highest_zoom_level = generator.level_count - 1  # 0-based indexing
try:
    mag = int(slide.properties[openslide.PROPERTY_NAME_OBJECTIVE_POWER])
    
    offset = math.floor((mag / 40) / 2)
    level = highest_zoom_level - offset
except (ValueError,KeyError) as e:
    level = highest_zoom_level
print("zoom level set at " +str(level) )
save_file(filepath= os.path.join(os.getcwd(),"saved"),filename = "level.pickle",file = level)
return level

这是我尝试将磁贴合并回其整个幻灯片图像的方式(不一定是 .svs 格式,但必须是相同的图像):

def merge_tiles_to_wsi(tile_path= None,wsi_path = None):
print("merging tiles into wsi")
tile_indices = load_file(filepath = tile_indices_savepath,filename = name)
slide = open_slide(filepath = wsi_path)

level = load_file(filepath= os.path.join(os.getcwd(),filename = "level.pickle")
generator = create_tile_generator(slide,TILE_SIZE,OVERLAP)
slide_dims = generator.level_dimensions[level]
row_size = slide_dims[0]
col_size = slide_dims[1]
channel_size = 3
slide_shape = (row_size,col_size,channel_size)
print("shape of slide is " + str(slide_shape))
wsi = np.zeros(slide_shape)
for ti in tile_indices:
    slide_num,row  = ti
    generator = create_tile_generator(slide,row)))
    
    row_length = tile.shape[0]
    col_length = tile.shape[1]
    row_end = row + row_length
    col_end = col + col_length
    print("col: " + str(col) + " row: " + str(row) + str(wsi[row:row_end,col:col_end].shape) + " " + str(tile.shape))
    wsi[row:row_end,col:col_end] = tile
    # view_image(img= wsi)
print("merging tiles into wsi")

return wsi

这是最终输出的样子 out.png

解决方法

libvips 可以为您进行合并和加入。您可以从 pyvips(Python 绑定)调用它。

要加载 svs 图像并将其拆分为图块,您可以编写:

import pyvips

image = pyvips.Image.new_from_file("my-slide.svs")
image.dzsave("my-deepzoom")

它会写入 my-deepzoom.dzi 和一个包含所有图块的目录 my-deepzoom_files。您可以调整很多参数,请参阅文档中的章节:

https://libvips.github.io/libvips/API/current/Making-image-pyramids.md.html

速度非常快,甚至可以在普通硬件上制作任何大小的金字塔。

您可以使用 arrayjoin 重新组合图块以形成图像。你给它一个以行为主的图像列表,并将 across 设置为每行的图像数。例如:

import pyvips

tiles = [pyvips.Image.new_from_file(f"{x}_{y}.jpeg",access="sequential")
         for y in range(height) for x in range(width)] 
image = pyvips.Image.arrayjoin(tiles,across=width)
image.write_to_file("huge.tif",compression="jpeg",tile=True)

速度非常快,并且可以加入非常大的图像数组。