文章目录
一、简介
🥗官网地址:napari: a fast, interactive viewer for multi-dimensional images in Python
🥪使用案例:Examples of napari usage.
🦞函数接口:API Reference —— 函数 + 参数详解
napari 是一个基于 PyQt 的快速、交互式多维图像查看器。
- 提供了一个用户友好的界面,允许用户加载、查看、分析和编辑各种类型的图像数据,包括二维图像、三维体积数据以及多通道图像数据。
- napari 的 GUI 图形用户界面是基于 PyQt 库创建的
- 支持自定义界面及数据交互:用户通过 PyQt 自定义组件,然后将其添加到 napari 图层,就可以实现组件自定义以及数据交互。
二、使用指南
2.1、安装
- 安装napari:
pip install napari
- 更新napari:
pip install --upgrade napari
2.2、BUG(巨巨巨大)
【BUG】
:点击View - Toggle Full Screen将最大化软件界面,且菜单栏和很多按钮都将不可用。【影响】
:此时,想要任何操作都无法退出最大化,即使关闭后重试,卸载后重试都无法达到,没有试过关机后重试。【解决方法】
:Window + Tab切换窗口,菜单栏可以短暂有效且可点击,瞬间点击View - Toggle Full Screen,可解除BUG。
2.3、界面
2.3.1、菜单栏(File + View + Plugins + Window + Help)
File(文件) | ||
---|---|---|
1 | Open File | 打开文件 |
2 | Opencv File as Stack | 打开文件(适用于大尺度) |
3 | Open Sample + napari builtins(内置样本) | 初学者可以直接导入后研究 |
4 | Preferences | 设置(主题 + 快捷键等等) |
5 | Save Selected Layer(s)(所有帧图像) | 保存选定的单层或多层(指定后缀,修改图像格式) |
6 | Save All Layers(所有帧图像) | 保存所有层(指定后缀,修改图像格式) |
7 | Save Screenshot(单帧图像) | 保存当前窗口内容(不显示界面) |
8 | Save Screenshot with Viewer(单帧图像) | 保存整个视图内容(图像 + 界面) |
- Plugins(插件):安装和卸载插件(也可以自定义)
View(视图) | ||
---|---|---|
1 | Axes | 轴 |
2 | Scale Bar | 刻度条 |
3 | Toggle Full Screen | 切换全屏 |
4 | Toggle Menubar Visibity | 切换菜单可见性 |
5 | Toggle Paly | 切换面板 |
6 | Toggle Layer Tooltips | 切换图层工具提示 |
7 | Toggle Activity Dock | 切换活动区 |
Window(窗口) | ||
---|---|---|
1 | console | 控制面板(命令行窗口) |
2 | layer controls | 图层控制(点层、形状层、标签层) |
3 | layer list | 图层列表 |
Help(帮助) | 直接跳转官网页面 | |
---|---|---|
1 | Getting started | 开始 |
2 | Tutorials | 教程 |
3 | Using Layers Guides | 使用图层指南 |
4 | Examples Gallery | 示例图库 |
5 | Release Notes | 版本说明 |
6 | napari homepage | napari 主页 |
7 | napari Info | napari 信息 |
2.3.2、Window:layer list(参数详解)
2.3.3、Window:layer controls(点层 + 形状层 + 标签层)
三、项目实战
3.0、启动可视化界面
在命令窗口中,输入指令:
napari
,将显示 napari 的初始化界面。
- 支持直接拖拽一个或多个图像到界面中,并完成图形化显示。
3.1、查看图像层:napari.view_image()
import napari
import numpy as np
if __name__ == '__main__':
image_data = np.ones(shape=(512, 512)) # 创建示例图像
napari.view_image(image_data, name='image') # 查看图像层
napari.run() # 显示 napari 视图
"""#########################################################################################################
# 函数功能:用于在 napari 视图中快速查看图像。
# 函数说明:napari.view_image(data, *, channel_axis=None, rgb=None, colormap=None, contrast_limits=None, gamma=None,
# interpolation='nearest', rendering='mip', iso_threshold=0.5, attenuation=0.5, name=None,
# metadata=None, scale=None, translate=None, rotate=None, shear=None, affine=None,
# opacity=1.0, blending='translucent', visible=True, path=None, title='napari', **kwargs)
# 输入参数:
# data: 图像数据,可以是 NumPy 数组。
# channel_axis: 如果数据有多个通道,可以指定通道轴。
# rgb: 指定数据是否为 RGB 格式。
# colormap: 图像的颜色映射。
# contrast_limits: 图像对比度的上下限。
# gamma: 应用到颜色映射的伽马校正值。
# interpolation: 图像显示的插值方法,如 'nearest'、'bilinear' 等。
# rendering: 图像渲染模式,如 'mip'(最大强度投影)。
# iso_threshold: 用于等值面渲染的阈值。
# attenuation: 用于光线投射渲染的衰减系数。
# name: 图层名称。
# metadata: 图层的元数据。
# scale: 图像的比例因子。
# translate: 图像的平移因子。
# rotate: 图像的旋转因子。
# shear: 图像的剪切因子。
# affine: 图像的仿射变换。
# opacity: 图层的不透明度。
# blending: 图层的混合模式。
# visible: 图层的可见性。
# path: 图像文件的路径。
# title: 视图窗口的标题。
# **kwargs: 其他关键字参数。
#########################################################################################################"""
3.2、添加图像层:viewer.add_image()
import napari
import numpy as np
if __name__ == '__main__':
image_data = np.ones(shape=(512, 512)) # 创建示例图像
viewer = napari.Viewer() # 创建 napari 视图
viewer.add_image(image_data, name="image", colormap='red') # 添加图像(指定红色)
napari.run() # 显示 napari 视图
################################################################################
# 隐藏面板
# viewer.window.qt_viewer.controls.hide() # 隐藏后不可使用该功能(重新打开也不行)
# viewer.window.qt_viewer.layers.hide()
# viewer.window._qt_viewer.close()
# viewer.window.qt_viewer.controls.close()
# viewer.window.qt_viewer.layers.close()
# viewer.window.qt_viewer.layers.setVisible(False)
# viewer.window.qt_viewer.controls.setVisible(False)
################################################################################
"""#########################################################################################################
# 函数功能:用于在 napari 视图中添加图像图层,可以添加和编辑多个图像。
# 函数说明:viewer.add_image(data, *, name=None, scale=None, translate=None, contrast_limits=None,
# colormap=None, blending=None, visible=True, opacity=1.0, interpolation='bilinear',
# rendering='mip', rgb=None, colormap_range=None)
# 输入参数:
# - data: 必选参数,图像数据。通常是一个 NumPy 数组,表示图像的像素值。可以是 2D 图像、3D 图像或多通道图像,具体取决于您的数据。
# - name: 可选参数,图像名称,将在napari查看器中显示。
##########################################
# scale: 可选参数,图像的缩放因子。默认为 None,表示不进行缩放。
# translate: 可选参数,图像的平移量。默认为 None,表示不进行平移。
# rotate: 可选参数,图像的旋转角度。默认为 None,表示不进行旋转。
# interpolation: 可选参数,图像的插值方法。用于在缩放或变换时平滑图像。
# 默认为 'linear',表示线性插值。其他可能的值包括 'nearest'(最近邻插值)等。
##########################################
# rgb: 可选参数,(布尔值)用于指示输入图像是否为RGB彩色图像。
# - colormap: 可选参数,图像的颜色映射。默认为 'gray',表示灰度图。可以选择其他颜色映射,如 'viridis'、'cividis' 等。
# colormap_range: 可选参数,颜色映射的范围。可以是字符串,例如"auto"或"full",表示自动计算颜色映射范围或使用完整范围。
##########################################
# blending: 可选参数,图像的混合模式。即图像如何与其他图层叠加。
# 默认为 'translucent',表示半透明。其他可能的值包括 'opaque'(不透明)和 'additive'(叠加)等。
# visible: 可选参数,图像是否可见。默认为 True,表示图像可见。
# opacity: 可选参数,图像的不透明度。默认为1.0,表示完全不透明。
##########################################
# - contrast_limits: 可选参数,调整图像的对比度,默认为 None,表示不进行对比度调整。
# 通常是一个包含两个值的元组,表示对比度的最小和最大值。例如 (0, 255),图像的像素值将线性映射到指定的范围内。
# - gamma: 可选参数,调整图像的伽马校正。默认为 1.0,表示不进行伽马校正。
# 较低的值可以增加图像的亮度,较高的值可以增加图像的对比度。
##########################################
# - rendering: 可选参数,图像的渲染方法。不同的渲染方法可以影响图像的可视化效果。
# 'mip'(默认值): 最大强度渲染。 选择每个像素沿视线方向上的最大值来渲染图像。通常用于显示有深度信息的图像,如体绘图。
# 'minimum': 最小强度渲染。 选择每个像素沿视线方向上的最小值来渲染图像。通常用于查看图像中的最暗特征,如血管。
# 'attenuated_mip': 衰减最大强度投影。根据深度进行衰减,距离视线近的像素比远处的像素更容易看到。适用于可视化深度信息的图像。
# 'translucent': 半透明渲染。 根据像素的亮度来渲染图像,较暗的像素会显示为半透明。适用于需要突出细节的图像。
# 'translucent_no_depth':半透明但不考虑深度信息渲染。
# 'additive': 多通道渲染。 将像素的亮度相加,而不是取最大值。适用于需要将多个图像叠加在一起的情况,如叠加多通道的彩色图像。
# 'iso': 等值面渲染。 将图像中所有像素值相同的区域渲染为等值面,适用于可视化等值面数据的图像。
#########################################################################################################"""
3.2.1、(手动)多通道叠加显示(rendering=“additive”)
import napari
import tifffile
if __name__ == '__main__':
image_path1 = r'F:\py\sampleImage.tif'
image_path2 = r'F:\py\lineImage.tif'
sampleImage = tifffile.imread(image_path1)
lineImage = tifffile.imread(image_path2)
viewer = napari.Viewer() # 创建 napari 视图
viewer.add_image(sampleImage, name='sampleImage')
viewer.add_image(lineImage, name='lineImage', colormap='green', rendering="additive")
napari.run() # 显示 napari 视图
# 启动 napari 后设置参数
3.2.2、(自动)启动 n 维显示模式(Toggle ndisplay)
import napari
import tifffile
if __name__ == '__main__':
image_path = r'F:\py\image.tif'
image = tifffile.imread(image_path)
viewer = napari.Viewer() # 创建 napari 视图
viewer.add_image(image, name='image')
viewer.dims.ndisplay = 3 # 启动 n 维显示模式
napari.run() # 显示 napari 视图
3.2.3、(自动)启动网格视图模式(Toggle grid mode)
import napari
import tifffile
if __name__ == '__main__':
image_path = r'F:\py\YH220.tif'
image = tifffile.imread(image_path)
viewer = napari.Viewer() # 创建 napari 视图
viewer.add_image(image, name='image1')
viewer.add_image(image, name='image2', colormap='red') # 红
viewer.add_image(image, name='image3', colormap='orange') # 橙
viewer.add_image(image, name='image4', colormap='yellow') # 黄
viewer.add_image(image, name='image5', colormap='green') # 绿
viewer.add_image(image, name='image6', colormap='cyan') # 青
viewer.add_image(image, name='image7', colormap='blue') # 蓝
viewer.add_image(image, name='image8', colormap='pink') # 粉(不支持紫色)
viewer.grid.enabled = True # 启动网格视图模式
viewer.grid.shape = (3, 3) # 设置网格的行和列数
napari.run() # 显示 napari 视图
3.2.4、获取图像层的slice值
(1)在 napari 中,通过访问 viewer.dims.current_step
可以获取当前图像层的属性。其中:viewer.dims.current_step[0]
表示获取 slice 值。
(2)通过slice滑动条可以更改当前slice,但 viewer.dims.current_step 的值不会自动更新,可以使用回调函数来监听 viewer.dims.events 的变化。
import napari
import numpy as np
def update_current_slice(event):
"""获取更新的切片值"""
current_slice = viewer.dims.current_step[0] # 获取当前 slice 值
print(f"Current Slice Value: {current_slice}")
if __name__ == '__main__':
image_data = np.random.rand(10, 100, 100)
viewer = napari.Viewer() # 创建 napari 视图
viewer.add_image(image_data, name='image') # 添加图像图层
viewer.dims.events.current_step.connect(update_current_slice) # 监听 dims 的变化
napari.run() # 显示 napari 视图
3.2.5、获取图像层的参数
import napari
import numpy as np
if __name__ == '__main__':
image_data = np.random.rand(10, 100, 100) # 创建一个三维图像数据 (10 slices, 100x100 pixels)
viewer = napari.Viewer() # 创建 napari 视图
image_layer = viewer.add_image(image_data, name='Image', contrast_limits=None, gamma=1) # 添加图像层
"""(1)获取图层中默认或指定的参数值。"""
print(f"对比度限制={image_layer.contrast_limits}, 伽马校正={image_layer.gamma}, 不透明度={image_layer.opacity}")
napari.run() # 显示 napari 视图
"""(2)若在图层中修改参数,则获取修改后的参数值。"""
print(f"对比度限制={image_layer.contrast_limits}, 伽马校正={image_layer.gamma}, 不透明度={image_layer.opacity}")
viewer.layers.clear() # 清空图层
"""(3)将修改后的参数应用到新的图像上"""
image_layer_new = viewer.add_image(image_data, name='Image', contrast_limits=image_layer.contrast_limits, gamma=image_layer.gamma)
print(f"对比度限制={image_layer_new.contrast_limits}, 伽马校正={image_layer_new.gamma}, 不透明度={image_layer_new.opacity}")
"""
对比度限制=[8.243654331385741e-07, 0.9999989837185992], 伽马校正=1, 不透明度=1.0
对比度限制=[8.243654331385741e-07, 0.9999989837185992], 伽马校正=1, 不透明度=0.26573426573426573
对比度限制=[8.243654331385741e-07, 0.9999989837185992], 伽马校正=1, 不透明度=1.0
"""
3.3、添加点云层:viewer.add_points() —— 获取点坐标
import napari
import numpy as np
if __name__ == '__main__':
viewer = napari.Viewer() # 创建 napari 视图
points_layer = viewer.add_points(name='Points') # 添加点层
points_layer.data = np.array([[100, 100], [200, 200], [300, 300]]) # 添加指定的点到点层
points_layer.mode = 'add' # 设置点层的模式(直接开始绘制点)
napari.run() # 显示 napari 视图
print(f"Points coordinates:\n {points_layer.data}")
"""#####################################################
模式选项包括:
points_layer.mode = 'pan_zoom' # 切换到平移和缩放模式
points_layer.mode = 'select' # 切换到选择模式
points_layer.mode = 'add' # 切换到添加模式
#####################################################"""
"""#########################################################################################################
# 函数功能:用于在 napari 视图中添加点图层,可以添加和编辑多个点。
# 函数说明:viewer.add_points(data=None, *, name=None, size=10, face_color='white', edge_color='dimgray',
# edge_width=0.05, symbol='o', opacity=1, blending='translucent', visible=True)
# 输入参数:
# - data: 点的坐标。数组的形状为(N, D),其中:N表示点的数量,D表示点的维度。若为二维图像,D为2,表示(x,y)坐标
# - size: 每个点的直径大小
# - face_color: 每个点的填充颜色
# edge_color: 每个点的边缘颜色
# - edge_width: 每个点的边缘宽度
# symbol: 每个点的符号形状。默认圆形点: 'o'
# 's':方形点 '+':十字形点 'x':X形点 'd':菱形点 '>':朝右箭头 '<':朝左箭头
# '^':朝上箭头 'v':朝下箭头 '1':下箭头 '2':上箭头 '3':左箭头 '4':右箭头
#
# - name: 图层的名称
# opacity: 图层的不透明度。取值范围为 0(完全透明)到 1(完全不透明)之间。
# blending: 图层的混合模式,'translucent'(半透明)、'opaque'(不透明)、'additive'(叠加)
# visible: 图层的可见性
#########################################################################################################"""
3.3.1、绘制3D小球(指定像素值)
viewer.add_points():在图像上添加点云数据,故需要添加图像层之后再添加点云数据。
import napari
import numpy as np
if __name__ == '__main__':
# (1)新建图像
marked_image = np.random.rand(10, 10, 10)
marked_image[2:3, 1:4, 5:6] = 2
marked_image[5:8, 4:7, 5:9] = 2
# (2)提取坐标
gray_value = 2 # 指定像素
indices = np.argwhere(marked_image == gray_value) # 获取像素的坐标
# (3)绘制点层
viewer = napari.Viewer() # 创建 napari 视图
viewer.add_image(marked_image) # 添加图像
viewer.add_points(indices[:, [0, 1, 2]], size=1, face_color='red', shading='spherical', edge_width=0) # 添加点云
viewer.dims.ndisplay = 3 # 启动 n 维显示模式
napari.run() # 显示 napari 视图
3.3.2、保存3D小球(napari不支持,自定义绘制)
import numpy as np
import tifffile
import napari
if __name__ == '__main__':
points = np.random.randint(0, 100, size=(50, 3)) # 在[0, 100)内生成随机50个3D坐标
##########################################################################################################
viewer = napari.Viewer() # 创建 napari 视图
point_layer = viewer.add_points(points, size=10, shading='spherical', edge_color='red', face_color='blue')
napari.run() # 显示 napari 视图
##########################################################################################################
# 保存结果
image_shape = np.zeros((100, 100, 100), dtype=np.uint8) # 创建一个100x100x100的空白图像
blank_image = np.zeros((*image_shape.shape, 3), dtype=np.uint8)
for point in points: # 在空白图像上绘制3D圆
x, y, z = point
rr, cc, dd = np.meshgrid(range(image_shape.shape[0]), range(image_shape.shape[1]), range(image_shape.shape[2]), indexing='ij')
distance = np.sqrt((rr - x)**2 + (cc - y)**2 + (dd - z)**2)
circle_radius = 5 # 3D圆的半径
circle_mask = distance <= circle_radius
blank_image[circle_mask, 0] = 255 # 红色通道设置为255,表示红色
blank_image[circle_mask, 1] = 0 # 绿色通道设置为0,表示绿色
blank_image[circle_mask, 2] = 0 # 蓝色通道设置为0,表示蓝色
tifffile.imsave('output_image.tif', blank_image) # 保存图像
3.4、添加形状层:viewer.add_shapes()
import napari
import numpy as np
if __name__ == '__main__':
image = np.ones(shape=(512, 512)) # 创建示例图像
viewer = napari.Viewer() # 创建 napari 视图
viewer.add_image(image, name='Image') # 添加图像层
shapes_layer = viewer.add_shapes(name='Shapes') # 添加形状层
shapes_layer.mode = 'select' # 设置形状层的模式(直接开始绘制线条)
napari.run() # 显示 napari 视图
"""#####################################################
模式选项包括:
'select' :选择模式,可以选择已有的形状。
'direct' :直接模式,可以直接编辑现有的形状。
'pan_zoom' :平移和缩放模式。
'add_rectangle' :绘制矩形模式。
'add_ellipse' :绘制椭圆模式。
'add_line' :绘制线条模式。
'add_path' :绘制路径模式。
'add_polygon' :绘制多边形模式。
#####################################################"""
"""#########################################################################################################
# 函数功能:用于在 napari 视图中添加形状图层,可以添加和编辑多种形状。
# 函数说明:viewer.add_shapes(data=None, *, name=None, shape_type='rectangle', face_color='white', edge_color='black',
# edge_width=1, opacity=0.7, blending='translucent', visible=True)
# 输入参数:
# - data: 形状坐标的数组或列表。每个形状为(N, D),其中:N表示形状的顶点数量,D表示形状的维度。若为二维图像,D为2,表示(x,y)坐标
# - shape_type: 形状的类型。默认为 'rectangle',表示绘制矩形。其他可能的值包括 'line'(线条)、'ellipse'(椭圆)等。
# face_color: 形状的填充颜色
# edge_color: 形状的边框颜色
# edge_width: 形状的边框宽度
#
# - name: 图层的名称
# opacity: 图层的不透明度,范围是 0 到 1。默认是 0.7。
# blending: 图层的混合模式,'translucent'(半透明)、'opaque'(不透明)、'additive'(叠加)
# visible: 图层的可见性
#########################################################################################################"""
3.4.1、获取线条坐标(起点和终点)
- 根据绘制线条时的方向,获取线条的起点和终点。
- 切换到n维显示模式,将导致线条绘制无法选定;但切换到网格模式不会有影响。
- shapes层和image_data层是两个独立的层,故线的坐标映射到image_data需要进行高度和宽度限制。
import napari
import numpy as np
def print_coordinate(image=None, shapes_layer=None):
"""打印线条的坐标(检查并截断越界的线条)"""
if shapes_layer.data: # 检查图层是否存在数据
for index, line_coordinates in enumerate(shapes_layer.data): # 遍历线条坐标
print(f"line_coordinates{index} = {line_coordinates}") # 左上角 + 右下角
# 检查是否越界
min_x = np.clip(int(np.min(line_coordinates[:, 0])), 0, image.shape[1]) # 若越界,则截断
max_x = np.clip(int(np.max(line_coordinates[:, 0])), 0, image.shape[1]) # 若越界,则截断
if min_x == max_x: max_x = min_x + 5 # 0 == 0
min_y = np.clip(int(np.min(line_coordinates[:, 1])), 0, image.shape[2]) # 若越界,则截断
max_y = np.clip(int(np.max(line_coordinates[:, 1])), 0, image.shape[2]) # 若越界,则截断
if min_y == max_y: max_y = min_y + 5 # 0 == 0
print(f"line_coordinates{index} = {min_x, min_y, max_x, max_y}\n") # 左上角 + 右下角
if __name__ == '__main__':
image = np.ones(shape=(100, 512, 512)) # 创建示例图像
viewer = napari.Viewer() # 创建 napari 视图
viewer.add_image(image, name='Random Image') # 添加图像层
shapes_layer = viewer.add_shapes(name='Shapes') # 添加形状层
shapes_layer.mode = 'add_line' # 设置形状层的模式(直接开始绘制线条)
napari.run() # 显示 napari 视图
print_coordinate(image=image, shapes_layer=shapes_layer)
3.4.1、获取矩形坐标(左上角+右下角)
import napari
import numpy as np
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QPushButton
def napari_previewImage(image, shapes_layer):
#####################################################################
# 打印自定义区域或默认区域的角坐标
print(f"shapes_layer.data = {shapes_layer.data[0]}")
# 计算矩形所覆盖的区域
rectangle_coords = shapes_layer.data[0]
min_x = np.clip(int(np.min(rectangle_coords[:, 0])), 0, image.shape[1]) # 若越界,则截断
max_x = np.clip(int(np.max(rectangle_coords[:, 0])), 0, image.shape[1]) # 若越界,则截断
if min_x == max_x: max_x = min_x + 5 # 0 == 0
min_y = np.clip(int(np.min(rectangle_coords[:, 1])), 0, image.shape[2]) # 若越界,则截断
max_y = np.clip(int(np.max(rectangle_coords[:, 1])), 0, image.shape[2]) # 若越界,则截断
if min_y == max_y: max_y = min_y + 5 # 0 == 0
print(f"rectangle_coords = {min_x, max_x, min_y, max_y}") # 左上角 + 右下角
selected_slice = image[:, min_x:max_x, min_y:max_y]
#####################################################################
viewer = napari.Viewer()
viewer.add_image(selected_slice, name='selected_slice')
napari.run()
"""
shapes_layer.data中的矩形由四个顶点定义,顶点的顺序如下:
左上角(Top-left)、右上角(Top-right)、右下角(Bottom-right)、左下角(Bottom-left)
"""
def napari_image(image):
viewer = napari.Viewer()
viewer.add_image(image, name='Image')
#####################################################################
# (1)添加固定大小的矩形形状层
half_height = image.shape[1] // 4
half_width = image.shape[2] // 4
# rectangle_points = np.array([[0, 0], [100, 0], [100, 100], [0, 100]]) # 四个角点的坐标
# shapes_layer = viewer.add_shapes(data=[rectangle_points], shape_type='rectangle', edge_width=10, edge_color='red')
shapes_layer = viewer.add_shapes(shape_type='rectangle', edge_width=10, edge_color='red')
shapes_layer.data = np.array([[0, 0], [half_height, 0], [half_height, half_width], [0, half_width]]) # 四个角点的坐标
shapes_layer.mode = 'select'
#####################################################################
# (2)在napari中,新建一个按钮组件。用于提取预览图像
layout = QHBoxLayout()
load_button = QPushButton("Extract Image")
load_button.clicked.connect(lambda: napari_previewImage(image, shapes_layer))
layout.addWidget(load_button)
widget = QWidget()
widget.setLayout(layout)
viewer.window.add_dock_widget(widget, area='right')
#####################################################################
napari.run()
if __name__ == '__main__':
image = np.random.random((100, 512, 512))
napari_image(image)
3.5、保存图层数据:viewer.screenshot() + layer.data
import numpy as np
image1 = np.random.random((100, 100))
image2 = np.ones((100, 100), dtype=bool)
import napari
viewer = napari.Viewer(show=True) # 创建 napari 视图(默认True,若为False,则可视化图层和保存文件都为空)
viewer.add_image(image1, name="image1")
viewer.add_image(image2, name="image2")
viewer.grid.enabled = True # 启动网格视图模式
# 备注:在 napari 窗口中,点击菜单栏的 File > Save Screenshot,然后选择文件保存的位置和格式。
################################################################################
"""(1)保存图层数据(启动网格视图模式)"""
screenshot = viewer.screenshot() # 获取截图
napari.utils.io.imsave(f'screenshot1.png', screenshot) # 保存为 PNG 文件
# 只支持PNG和TIF格式,不支持JPG。 提示如下OSError: cannot write mode RGBA as JPEG
"""(2)保存指定图层数据(网格模式无效)"""
layer = viewer.layers[0] # 获取第一个图层
napari.utils.io.imsave(f'screenshot1.tif', layer.data) # 保存为 TIF 文件
# 只支持TIF格式,不支持PNG和JPG。 提示如下OSError: cannot write mode F as PNG/JPEG
################################################################################
viewer.close() # 关闭 napari 视图
# napari.run() # 显示 napari 视图
四、扩展功能:将自定义 PyQt 组件,添加到 napari 界面中,并完成数据交互。
- 备注:napari没有提供鼠标点击事件的接口。
- 在napari中自定义组件与PyQt新建组件的方法相同,只需要将组件的主窗口添加到napari界面的控制面板中。
viewer.window.add_dock_widget(widget, area='right')
- 其中:viewer表示指定的napari界面,widget是插件的主窗口。
- 功能:将自定义组件添加到主窗口中,然后将窗口显示在指定的napari界面的右侧区域。
import tifffile
import napari
import numpy as np
import sys
import os
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, \
QPushButton, QFileDialog, QTextEdit, QSlider, QCheckBox
from PyQt5.QtCore import Qt
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Window")
##########################################################
layout = QVBoxLayout()
button_layout = QHBoxLayout()
self.load_button = QPushButton("Load Image", self)
self.load_button.clicked.connect(self.load_image)
self.image_name_label = QLabel("")
button_layout.addWidget(self.load_button)
button_layout.addWidget(self.image_name_label)
layout.addLayout(button_layout)
##########################################################
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
##########################################################
# 初始化参数
self.image_path = ""
self.image_name = ""
##########################################################
def load_image(self):
file_dialog = QFileDialog()
image_path, _ = file_dialog.getOpenFileName(self, "Select Image", "", "Image Files (*.tif *.png *.jpg *.jpeg)")
if image_path:
self.image_path = image_path
self.image_name = os.path.basename(image_path)
self.image_name_label.setText(self.image_name)
self.image_slices = tifffile.imread(image_path)
self.napari_gray_view() # 调用napari_gray_view方法来显示第一个切片
def napari_gray_view(self):
# (1)napari:创建视图、添加图层、显示视图
self.viewer = napari.Viewer() # 创建napari视图
self.viewer.add_image(self.image_slices, name='image') # 添加napari图层
# napari.run() # 显示napari图形界面
# 备注:若不添加napari.run(),将避免程序阻塞问题(一直等待界面关闭)
#########################################################################
# (2)自定义组件
#########################################################################
# (2.1)创建滑动条
self.slider = QSlider() # 新建滑动条
self.slider.setMinimum(0) # 设置滑动条的最小值
self.slider.setMaximum(np.max(self.image_slices)) # 设置滑动条的最大值
self.slider.setValue(0) # 设置滑动条的初始值
# (2.2)创建标签
self.slider_label = QLabel(str(self.slider.value()))
# (2.3)复选框
self.checkbox = QCheckBox("checkbox") # 复选框
self.slider.setEnabled(False) # 复选框的初始状态:False
self.input_box = QLineEdit() # 新建输入框
self.input_box.setEnabled(True) # 复选框的初始状态:True
self.input_label = QLabel("range: " + str(np.min(self.image_slices)) + "/" + str(np.max(self.image_slices))) # 输入框标签
# (3)创建布局并将滑动条和标签添加到布局中
layout = QVBoxLayout()
layout.addWidget(self.slider)
layout.addWidget(self.slider_label)
layout.addWidget(self.checkbox)
layout.addWidget(self.input_box)
layout.addWidget(self.input_label)
# (4)创建一个QWidget作为插件的主窗口
widget = QWidget()
widget.setLayout(layout)
# (5)连接复选框的状态变化信号与槽函数
self.checkbox.stateChanged.connect(self.onCheckboxStateChanged)
self.slider.valueChanged.connect(self.napari_update_gray) # 根据滑动条的值,显示第一个切片
self.input_box.returnPressed.connect(self.napari_update_gray) # 根据输入框的值,显示第一个切片
# (6)将插件的主窗口添加到napari界面的控制面板中
self.viewer.window.add_dock_widget(widget, area='right') # 添加到napari的右侧
#########################################################################
# (7)napari:显示视图
self.viewer.window.show()
def onCheckboxStateChanged(self, state):
if state == Qt.Checked:
self.slider.setEnabled(True)
self.input_box.setEnabled(False)
else:
self.slider.setEnabled(False)
self.input_box.setEnabled(True)
def napari_update_gray(self):
# (1)获取napari视图中的图层对象,并获取图像数据
napari_image = self.image_slices.data
# (2)获取当前切片滑动条的值
current_slice = int(self.viewer.dims.current_step[0])
# (3)获取当前灰度滑动条的值
self.slider_label.setText(str(self.slider.value()))
if self.checkbox.isChecked():
current_gray = self.slider.value()
else:
current_gray = int(self.input_box.text())
print("current_slice:", current_slice, "current_gray:", current_gray)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())