一、napari 简介
napari 是一个基于 Python 的科学图像和体积数据可视化工具,专注于提供交互性和可扩展性。其提供了一个交互式的图像和数据可视化环境,使用户能够探索、分析和处理科学图像、体积数据和其他多维数据。
napari支持用户自定义界面及数据交互:由于napari的GUI图形用户界面是基于 PyQt 库创建,故用户只需要通过PyQt自定义组件后,然后添加到napari图层就可以实现自定义组件显示。
napari: a fast, interactive viewer for multi-dimensional images in Python
napari:基于 Python 编写的快速、交互式多维图像查看器
🥗napari 官网首页:https://napari.org/0.4.18/index.html#
🥪napari 使用案例:https://napari.org/0.4.18/gallery.html#gallery
二、napari 安装与更新
- 安装napari:
pip install napari
- 更新napari:
pip install --upgrade napari
三、napari【巨巨巨大的一个BUG】
【BUG】
:点击View - Toggle Full Screen将最大化软件界面,且菜单栏和很多按钮都将不可用。【影响】
:此时,想要任何操作都无法退出最大化,即使关闭后重试,卸载后重试都无法达到,没有试过关机后重试。【解决方法】
:Window + Tab切换窗口,菜单栏可以短暂有效且可点击,瞬间点击View - Toggle Full Screen,可解除BUG。
四、napari 使用指南
4.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 信息 |
4.2、Window:layer list(参数详解)
4.3、Window:layer controls(points layer + shapes layer + labels layer)
五、项目实战
5.0、启动napari
在Pycharm的Terminal中输入:napari
。然后将显示napari的初始化界面,可以直接拖拽一个或多个图像到界面中进行图形化显示。
5.1、查看图像层:napari.view_image()
在napari查看器中显示单个或多个图像,并提供了许多可选参数来自定义图像的显示。
import napari
import tifffile
image_path = 'output_8bit.tif'
marked_image = tifffile.imread(image_path)
viewer = napari.view_image(marked_image, name='image', rgb=False)
napari.run()
# 备注:若不添加napari.run(),将避免程序阻塞问题(一直等待界面关闭)
"""
#########################################################################################################
# 函数功能:创建一个 napari 查看器(Viewer),并在查看器中显示图像。
# 函数说明:napari.view_image(data, *, name=None, channel_axis=None, colormap=None, blending=None, interpolation=None, gamma=None, is_pyramid=None, rgb=None, scale=None, translate=None, contrast_limits=None, rendering=None)
# 输入参数:
# - data:要显示的图像数据。可以是以下格式之一:
# 2D NumPy array:灰度图像数据。
# 3D NumPy array:3D图像数据,例如多张2D图像叠加形成的图像序列。
# 4D NumPy array:4D图像数据,例如多通道彩色图像。
# List of 2D, 3D, or 4D arrays:多个图像数据列表。
# Dask array:支持分块加载的大型图像数据。
# ImageData:来自dask_image.imread()等函数的图像数据对象。
# - name: 图像的名称,将在napari查看器中显示。
# channel_axis: 用于多通道图像的通道轴的索引。默认值为None,表示使用最后一个轴作为通道轴。
# - colormap: 图像的颜色映射。可以是字符串表示的颜色映射名称,或是colormap函数。默认值为None,表示使用默认颜色映射。
# blending: 图像的混合模式。可以是字符串表示的混合模式名称,例如"translucent"、"additive"等。默认值为None,表示使用默认混合模式。
# interpolation: 图像的插值方法。可以是字符串表示的插值方法名称,例如"nearest"、"bilinear"、"bicubic"等。默认值为None,表示使用默认插值方法。
# gamma: 图像的gamma值,用于对图像进行伽马校正。默认值为None,表示不进行伽马校正。
# is_pyramid: 布尔值,用于指示是否使用金字塔结构显示图像。默认值为None,表示不使用金字塔结构。
# rgb: 布尔值,用于指示输入图像是否为RGB彩色图像。默认值为None,表示根据输入图像数据自动判断。
# scale: 图像的缩放因子。可以是单个值,表示在所有轴上应用相同的缩放,也可以是每个轴的缩放因子列表。默认值为None,表示不进行缩放。
# translate: 图像的平移量。可以是单个值,表示在所有轴上应用相同的平移,也可以是每个轴的平移量列表。默认值为None,表示不进行平移。
# contrast_limits: 图像的对比度限制,用于控制图像显示的亮度范围。可以是单个值,表示在所有轴上应用相同的对比度限制,也可以是每个轴的对比度限制列表。默认值为None,表示不设置对比度限制。
# rendering: 图像的渲染模式。可以是字符串表示的渲染模式名称,例如"mip"、"translucent"、"attenuated_mip"等。默认值为None,表示使用默认渲染模式。
#########################################################################################################
"""
5.2、添加图像层:viewer.add_image()
将单个或多个图像添加到napari查看器中,并提供了多个可选参数来自定义图像的显示。
import napari
import tifffile
image_path = '561result-1-part.tif'
marked_image = tifffile.imread(image_path)
viewer = napari.Viewer() # 创建napari视图
viewer.add_image(marked_image, name="image", colormap='red') # 添加图像(指定红色)
################################################################################
# 隐藏面板
# viewer.window.qt_viewer.controls.hide() # 隐藏后不可使用该功能(重新打开也不行)
# viewer.window.qt_viewer.layers.hide()
# viewer.window.qt_viewer.controls.close()
# viewer.window.qt_viewer.layers.close()
################################################################################
napari.run() # 显示napari图形界面
# 备注:若不添加napari.run(),将避免程序阻塞问题(一直等待界面关闭)
"""
#########################################################################################################
# 函数功能:用于在 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': 等值面渲染。 将图像中所有像素值相同的区域渲染为等值面,适用于可视化等值面数据的图像。
#########################################################################################################
"""
5.3、添加点云层:viewer.add_points() —— 获取点坐标
将点的坐标和可选的其他属性添加到napari查看器中,并提供了多个可选参数来自定义点云的显示。
点云数据:由离散点(x, y, z)坐标的集合组成。
import napari
# (1)创建napari Viewer
viewer = napari.Viewer() # 创建napari查看器
points_layer = viewer.add_points(size=5, face_color='red', edge_color='green', name='Points') # 添加点层
viewer.layers['Points'].mode = 'add' # 打开点绘制模式
napari.run() # 运行napari
# (2)打印坐标
points_data = viewer.layers['Points'].data # 获取绘制的点的图层
print("绘制的点:\n", points_data) # points_data坐标顺序:[y, x]
"""
#########################################################################################################
# 函数功能:用于在 napari 视图中添加点图层,它允许您可视化点数据。
# 函数说明:viewer.add_points(data, *, name=None, face_color='white', edge_color='black', size=10,
# symbol='o', edge_width=1, opacity=1.0, blending='translucent')
#
# 输入参数:
# - data: 点的坐标数据。用于指定点的位置坐标,可以接受不同维度的数据。
# 对于 2D 数据,data 可以是一个形状为 (N, 2) 的数组,其中 N 表示点的数量,每行包含点的 X 和 Y 坐标。
# 对于 3D 数据,data 可以是一个形状为 (N, 3) 的数组,其中每行包含点的 X、Y 和 Z 坐标。
# 对于更高维度的数据,data 的形状会相应地增加,以包含更多的坐标信息。
# - name: 图层的名称,用于标识图层。默认为 None。
# - face_color: 点的填充颜色。默认为红色 ('red')。
# edge_color: 点的边缘颜色。默认为红色 ('red')。
# - size: 点的大小。默认为 10(单位:像素),表示点的直径。
# symbol: 点的形状。默认为圆形点: 'o'
# 's':表示方形点。 '+':表示十字形点。 'x':表示X形点。
# 'd':表示菱形点。 '>':表示朝右箭头。 '<':表示朝左箭头。
# '^':表示朝上箭头。 'v':表示朝下箭头。 '1':表示下箭头。
# '2':表示上箭头。 '3':表示左箭头。 '4':表示右箭头。
# - shading: 点的着色方式。用于控制渲染点图层时的着色方式。指定点的渲染方式,以改变点的外观。
# 'flat': 默认值。使用平面着色,使点看起来像扁平的二维图标。这是最常见的着色方式,适用于大多数情况。
# 'smooth': 使用平滑的渐变着色,使点看起来更加光滑和立体。这种着色方式可以让点看起来更加圆润,适用于需要强调点的立体感的情况。
# 'spherical':使用球形着色,使点看起来像立体的球体。这种着色方式强调了点的立体感,尤其在 3D 空间中使用时效果明显。
# edge_width: 点的边缘宽度。默认为 1(单位:像素)。
# opacity: 点的不透明度。默认为 1.0,表示完全不透明。取值范围为 0(完全透明)到 1(完全不透明)之间。
# blending: 点的混合模式,控制点的渲染方式。可以是 'translucent'(默认值,半透明)、'opaque'(不透明)和 'additive'(叠加)等。
#########################################################################################################
"""
5.4、添加形状层:viewer.add_shapes() —— 获取线条坐标(起点和终点)
- napari会根据实际绘制线条的方向自动获取线条的起点和终点,而不是随机情况。
- 切换到n维显示模式(
viewer.dims.ndisplay = 3
)将导致无法选定线条绘制,但切换网格模式不会有影响。
注意:shapes层和image_data层是两个独立的层,故线的坐标映射到image_data需要进行高度和宽度限制。
import napari
import cv2
# (1)加载图像
image_path = 'blank.png'
image_data = cv2.imread(image_path)
print("height:", image_data.shape[0], "width:", image_data.shape[1])
# (2)创建napari Viewer
viewer = napari.Viewer() # 创建napari查看器
viewer.add_image(image_data) # 添加图像
shapes_layer = viewer.add_shapes(data=None, shape_type='line', edge_width=3, edge_color='red') # 添加形状(线条 + 线宽 + 颜色)
shapes_layer.mode = 'add_line' # 直接开始绘制线条
napari.run() # 运行napari
# 备注:若不添加napari.run(),将避免程序阻塞问题(一直等待界面关闭)
# (3)打印坐标
# image_shape = image_data.shape # 获取图像的形状
line_layer = viewer.layers['Shapes'] # 获取绘制的线的图层
line_coordinates1 = [] # 获取绘制的所有线的坐标
line_coordinates2 = [] # 获取绘制的所有线的坐标:删除超出图像的线条
if line_layer.data: # 检查图层数据是否存在
for line in line_layer.data: # 遍历线的坐标
coordinates1 = [line[0, 0], line[0, 1], line[1, 0], line[1, 1]]
line_coordinates1.append(coordinates1)
for line in line_layer.data: # 遍历线的坐标
# 【高度限制】:删除超出图像的线条
if line[0, 0] < 0:
line[0, 0] = 0
elif line[0, 0] > image_data.shape[0]:
line[0, 0] = image_data.shape[0]
if line[1, 0] < 0:
line[1, 0] = 0
elif line[1, 0] > image_data.shape[0]:
line[1, 0] = image_data.shape[0]
# 【宽度限制】:删除超出图像的线条
if line[0, 1] < 0:
line[0, 1] = 0
elif line[0, 1] > image_data.shape[1]:
line[0, 1] = image_data.shape[1]
if line[1, 1] < 0:
line[1, 1] = 0
elif line[1, 1] > image_data.shape[1]:
line[1, 1] = image_data.shape[1]
# 坐标获取:[y1, x1, y2, x2]
coordinates2 = [line[0, 0], line[0, 1], line[1, 0], line[1, 1]]
line_coordinates2.append(coordinates2)
# 输出所有坐标(shapes:线坐标)
for idx, coordinates in enumerate(line_coordinates1):
print(f'Line {idx + 1} coordinates1:', coordinates)
print("")
# 输出所有坐标(image:线坐标映射到图像的坐标):高度限制+宽度限制
for idx, coordinates in enumerate(line_coordinates2):
print(f'Line {idx + 1} coordinates2:', coordinates)
"""
#########################################################################################################
# 函数功能:用于在 napari 视图中添加形状图层,允许您可视化和编辑形状数据。
# 函数说明:viewer.add_shapes(data=None, shape_type='rectangle', edge_color='red', face_color='transparent',
# opacity=1.0, edge_width=1, blending='translucent', name=None)
# 输入参数:
# - data: 包含形状数据的列表。
# (1)列表中可以包含多个形状字典,每个字典描述一个形状。
# (2)字典中包含形状的类型、坐标、边框颜色、填充颜色等信息。
# data = [{'type': 'rectangle', 'roi': [x1, y1, x2, y2], 'edge_color': 'red', 'face_color': 'transparent'}]
# - name: 形状图层的名称,用于标识图层。默认为 None。
# - shape_type: 指定要绘制的形状类型。默认为 'rectangle',表示绘制矩形。其他可能的值包括 'line'(线条)、'ellipse'(椭圆)等。
# edge_color: 形状的边框颜色。默认为 'red',表示红色。
# face_color: 形状的填充颜色。默认为 'transparent',表示透明填充。
# opacity: 形状的不透明度,用于控制形状的透明度。默认为 1.0,表示完全不透明。
# edge_width: 形状的边框宽度,用于指定形状的边框线宽。默认为 1。
# blending: 形状的混合模式,用于指定形状的绘制方式。默认为 'translucent',表示半透明。其他可能的值包括 'opaque'(不透明)和 'additive'(叠加)等。
#########################################################################################################
"""
六、扩展功能
6.1、在PyQt中,自定义组件,并添加到napari中,且完成数据交互
- 备注:napari没有提供鼠标点击事件的接口。
- 在napari中自定义组件与PyQt新建组件的方法相同,区别是需要将组件的主窗口添加到napari界面的控制面板中:
self.viewer.window.add_dock_widget(widget, area='right') # 添加到napari的右侧
,其中:widget是插件的主窗口。
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_())
6.2、在add_points中,提取图像中指定像素值并绘制成点
viewer.add_points()用于添加点云数据,但不能直接显示。需要先添加viewer.view_image(),然后再显示点云数据。
import napari
import numpy as np
# (1)通过tifffile加载tif图像
marked_image = np.random.rand(10, 10, 10) # 创建一个三维图像数据 (10 slices, 100x100 pixels)
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) # 添加图像到napari视图
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图形界面
# 备注:若不添加napari.run(),将避免程序阻塞问题(一直等待界面关闭)
6.2、在add_points中,保存点层的3D圆(napari不支持,自定义绘制)
import numpy as np
import tifffile
import napari
from napari.layers import Points
# 创建一个新的Napari查看器
viewer = napari.Viewer()
####################################################################################
"""替换坐标即可完成点绘制"""
num_points = 50 # 随机生成50个3D坐标点
points = np.random.randint(0, 100, size=(num_points, 3)) # 在范围[0, 100)内生成随机坐标
####################################################################################
# 方法一:添加点层
point_layer = viewer.add_points(points, size=10, shading='spherical', edge_color='red', face_color='blue')
# 方法二:创建一个点层并添加坐标点
# point_layer = Points(points, size=10, shading='spherical', edge_color='red', face_color='blue')
# viewer.add_layer(point_layer)
####################################################################################
# 创建一个空白的3D图像,你需要指定图像的大小(shape)
image_shape = np.zeros((100, 100, 100), dtype=np.uint8) # 例如,创建一个100x100x100的空白图像
blank_image = np.zeros((*image_shape.shape, 3), dtype=np.uint8)
# 在空白图像上绘制3D圆
for point in points:
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,表示蓝色
# 保存绘制后的图像为TIFF文件
tifffile.imsave('output_image.tif', blank_image)
# 启动Napari查看器以查看绘制的点和图像
napari.run()
6.3、在add_image中,添加带箭头的线条(napari不支持,自定义绘制)
import napari
import cv2
import numpy as np
# 创建napari Viewer
viewer = napari.Viewer()
# 创建空白图像
image_shape = (300, 400, 3)
image = np.zeros(image_shape, dtype=np.uint8)
# 在图像上绘制带箭头的线条
start_point = (100, 100)
end_point = (300, 200)
arrow_color = (255, 0, 0) # Red color in BGR
# 使用OpenCV绘制带箭头的线条
arrow_image = cv2.arrowedLine(image.copy(), start_point, end_point, arrow_color, thickness=2, tipLength=0.3)
# 将OpenCV图像添加到napari中
viewer.add_image(arrow_image, name='Arrow Line')
# 运行napari
napari.run()
6.4、在add_image中,添加两张图像并进行多通道叠加显示(rendering=“additive”)
import napari
import tifffile
# 加载两张图像
image_path1 = r'D:\BIRDS\_coach_path_561temp_BIRDS\registration\coarse\downSampleImage.tif'
image_path2 = r'D:\BIRDS\_coach_path_561temp_BIRDS\registration\coarse\lineImage.tif'
SampleImage = tifffile.imread(image_path1)
lineImage = tifffile.imread(image_path2)
viewer = napari.Viewer() # 创建napari Viewer
viewer.add_image(SampleImage[500], name='SampleImage') # 添加帧图像
viewer.add_image(lineImage[500], name='lineImage', colormap='green', rendering="additive") # 添加帧图像
napari.run() # 显示napari图形界面
6.4、在add_image中,添加两张图像并自动切换到n维显示模式(Toggle ndisplay)
import napari
import tifffile
# 加载两张图像
image_path1 = r'C:\Users\Administrator\Desktop\py\SampleImage.tif'
image_path2 = r'C:\Users\Administrator\Desktop\py\lineImage.tif'
image_data1 = tifffile.imread(image_path1)
image_data2 = tifffile.imread(image_path2)
viewer = napari.Viewer() # 创建napari Viewer
viewer.add_image(SampleImage[500], name='SampleImage') # 添加帧图像
viewer.add_image(lineImage[500], name='lineImage', colormap='green') # 添加帧图像
""""添加图像:后一个会自动覆盖在前一个上,故需要注意顺序"""
viewer.dims.ndisplay = 3 # 切换到n维显示模式(此时,系统会将两张图像融合在一起)
napari.run() # 显示napari图形界面
6.5、在add_image中,添加两张图像并自动切换网格模式(Toggle grid mode)
文章来源:https://www.toymoban.com/news/detail-650639.html
import napari
import tifffile
# 加载两张图像
image_path1 = r'C:\Users\Administrator\Desktop\py\SampleImage.tif'
image_path2 = r'C:\Users\Administrator\Desktop\py\lineImage.tif'
image_data1 = tifffile.imread(image_path1)
image_data2 = tifffile.imread(image_path2)
# 创建napari Viewer
viewer = napari.Viewer()
viewer.add_image(image_data1, name='Image 1', colormap='red')
viewer.add_image(image_data2, name='Image 2', colormap='green')
# 切换网格模式
viewer.grid.enabled = not viewer.grid.enabled
# 显示napari图形界面
napari.run()
6.6、在add_image中,获取图像层的slice值
(1)在 napari 中,通过访问 viewer.dims.current_step 属性可以获取当前图像层的属性。其中:viewer.dims.current_step[0]表示获取 slice 值。
(2)通过slice滑动条可以更改当前slice,但 viewer.dims.current_step 的值不会自动更新,可以使用回调函数来监听 viewer.dims.events 的变化。文章来源地址https://www.toymoban.com/news/detail-650639.html
import napari
import numpy as np
viewer = napari.Viewer() # 创建 napari 视图
image_data = np.random.rand(10, 100, 100) # 创建一个三维图像数据 (10 slices, 100x100 pixels)
image_layer = viewer.add_image(image_data, name='My Image') # 添加图像图层
"""创建一个回调函数,获取更新的切片值"""
def update_current_slice(event):
current_slice = viewer.dims.current_step[0] # 获取当前 slice 值
print("Current Slice Value:", current_slice)
# 监听 dims 的变化
viewer.dims.events.current_step.connect(update_current_slice)
napari.run() # 运行 napari
6.7、在add_image中,获取图像层的参数contrast_limits + gamma
import napari
import numpy as np
viewer = napari.Viewer() # 创建 napari 视图
image_data = np.random.rand(10, 100, 100) # 创建一个三维图像数据 (10 slices, 100x100 pixels)
image_layer = viewer.add_image(image_data, name='Image', contrast_limits=None, gamma=1) # 添加图像层
##############################################################################
"""
对比度限制和伽马校正参数: 不会在图像图层的显示期间自动更新
"""
contrast_limits_value = image_layer.contrast_limits # 获取图层的对比度限制参数
gamma_value = image_layer.gamma # 获取图层的伽马校正参数
print("初始参数 =", contrast_limits_value, gamma_value)
napari.run() # 运行 napari
contrast_limits_value2 = image_layer.contrast_limits
gamma_value2 = image_layer.gamma
print("参数1 =", contrast_limits_value2, gamma_value2)
##############################################################################
"""
在图像层添加后再次运行 napari.run() 来重新启动 napari 查看器,那么之前的图像图层和参数将会被丢弃,因此 contrast_limits 和 gamma 的值会恢复为默认值。
viewer = napari.Viewer() # 创建 napari 视图
viewer.layers.clear() # 清空 napari 图层
viewer.add_image() # 添加 napari 图层
"""
viewer.layers.clear() # 清空图层
image_data = np.random.rand(10, 100, 100) # 创建一个三维图像数据 (10 slices, 100x100 pixels)
image_layer = viewer.add_image(image_data, name='Image', contrast_limits=contrast_limits_value2, gamma=gamma_value2)
napari.run() # 运行 napari
contrast_limits_value2 = image_layer.contrast_limits
gamma_value2 = image_layer.gamma
print("参数2 =", contrast_limits_value2, gamma_value2)
到了这里,关于Python项目实战:基于napari的3D可视化(点云+slice)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!