Python项目实战:基于napari的3D可视化(点云+slice)

2023-11-11 15:20

本文主要是介绍Python项目实战:基于napari的3D可视化(点云+slice),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、napari 简介
  • 二、napari 安装与更新
  • 三、napari【巨巨巨大的一个BUG】
  • 四、napari 使用指南
    • 4.1、菜单栏(File + View + Plugins + Window + Help)
    • 4.2、Window:layer list(参数详解)
    • 4.3、Window:layer controls(points layer + shapes layer + labels layer)
  • 五、项目实战
    • 5.0、启动napari
    • 5.1、查看图像层:napari.view_image()
    • 5.2、添加图像层:viewer.add_image()
    • 5.3、添加点云层:viewer.add_points() —— 获取点坐标
    • 5.4、添加形状层:viewer.add_shapes() —— 获取线条坐标(起点和终点)
  • 六、扩展功能
    • 6.1、在PyQt中,自定义组件,并添加到napari中,且完成数据交互
    • 6.2、在add_points中,提取图像中指定像素值并绘制成点
    • 6.2、在add_points中,保存点层的3D圆(napari不支持,自定义绘制)
    • 6.3、在add_image中,添加带箭头的线条(napari不支持,自定义绘制)
    • 6.4、在add_image中,添加两张图像并进行多通道叠加显示(rendering="additive")
    • 6.4、在add_image中,添加两张图像并自动切换到n维显示模式(Toggle ndisplay)
    • 6.5、在add_image中,添加两张图像并自动切换网格模式(Toggle grid mode)
    • 6.6、在add_image中,获取图像层的slice值
    • 6.7、在add_image中,获取图像层的参数contrast_limits + gamma

一、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(文件)
1Open File打开文件
2Opencv File as Stack打开文件(适用于大尺度)
3Open Sample + napari builtins(提供了很多的内置样本)初学者可以直接导入后研究
4Preferences设置(主题 + 快捷键等等)
5Save Selected Layer(s)(所有帧图像)保存选定的单层或多层(指定后缀,修改图像格式)
6Save All Layers(所有帧图像)保存所有层(指定后缀,修改图像格式)
7Save Screenshot(单帧图像)保存当前窗口内容(不显示界面)
8Save Screenshot with Viewer(单帧图像)保存整个视图内容(图像 + 界面)
  • Plugins(插件):安装和卸载插件(也可以自定义)
View(视图)
1Axes
2Scale Bar刻度条
3Toggle Full Screen切换全屏
4Toggle Menubar Visibity切换菜单可见性
5Toggle Paly切换面板
6Toggle Layer Tooltips切换图层工具提示
7Toggle Activity Dock切换活动区
Window(窗口)
1console控制面板(命令行窗口)
2layer controls图层控制(点层、形状层、标签层)
3layer list图层列表
Help(帮助)直接跳转官网页面
1Getting started开始
2Tutorials教程
3Using Layers Guides使用图层指南
4Examples Gallery示例图库
5Release Notes版本说明
6napari homepagenapari 主页
7napari Infonapari 信息

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 tifffileimage_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 tifffileimage_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] = 0elif line[0, 0] > image_data.shape[0]:line[0, 0] = image_data.shape[0]if line[1, 0] < 0:line[1, 0] = 0elif line[1, 0] > image_data.shape[0]:line[1, 0] = image_data.shape[0]# 【宽度限制】:删除超出图像的线条if line[0, 1] < 0:line[0, 1] = 0elif line[0, 1] > image_data.shape[1]:line[0, 1] = image_data.shape[1]if line[1, 1] < 0:line[1, 1] = 0elif 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 Qtclass 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_pathself.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)  # 复选框的初始状态:Falseself.input_box = QLineEdit()  # 新建输入框self.input_box.setEnabled(True)  # 复选框的初始状态:Trueself.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 = pointrr, 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_radiusblank_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)

在这里插入图片描述

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 的变化。

import napari
import numpy as npviewer = 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 npviewer = 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()  # 运行 naparicontrast_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()  # 运行 naparicontrast_limits_value2 = image_layer.contrast_limits
gamma_value2 = image_layer.gamma
print("参数2 =", contrast_limits_value2, gamma_value2)

这篇关于Python项目实战:基于napari的3D可视化(点云+slice)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/390983

相关文章

Nginx实现高并发的项目实践

《Nginx实现高并发的项目实践》本文主要介绍了Nginx实现高并发的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录使用最新稳定版本的Nginx合理配置工作进程(workers)配置工作进程连接数(worker_co

python中列表list切分的实现

《python中列表list切分的实现》列表是Python中最常用的数据结构之一,经常需要对列表进行切分操作,本文主要介绍了python中列表list切分的实现,文中通过示例代码介绍的非常详细,对大家... 目录一、列表切片的基本用法1.1 基本切片操作1.2 切片的负索引1.3 切片的省略二、列表切分的高

基于Python实现一个PDF特殊字体提取工具

《基于Python实现一个PDF特殊字体提取工具》在PDF文档处理场景中,我们常常需要针对特定格式的文本内容进行提取分析,本文介绍的PDF特殊字体提取器是一款基于Python开发的桌面应用程序感兴趣的... 目录一、应用背景与功能概述二、技术架构与核心组件2.1 技术选型2.2 系统架构三、核心功能实现解析

通过Python脚本批量复制并规范命名视频文件

《通过Python脚本批量复制并规范命名视频文件》本文介绍了如何通过Python脚本批量复制并规范命名视频文件,实现自动补齐数字编号、保留原始文件、智能识别有效文件等功能,听过代码示例介绍的非常详细,... 目录一、问题场景:杂乱的视频文件名二、完整解决方案三、关键技术解析1. 智能路径处理2. 精准文件名

基于Python开发PDF转Doc格式小程序

《基于Python开发PDF转Doc格式小程序》这篇文章主要为大家详细介绍了如何基于Python开发PDF转Doc格式小程序,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用python实现PDF转Doc格式小程序以下是一个使用Python实现PDF转DOC格式的GUI程序,采用T

Python使用PIL库将PNG图片转换为ICO图标的示例代码

《Python使用PIL库将PNG图片转换为ICO图标的示例代码》在软件开发和网站设计中,ICO图标是一种常用的图像格式,特别适用于应用程序图标、网页收藏夹图标等场景,本文将介绍如何使用Python的... 目录引言准备工作代码解析实践操作结果展示结语引言在软件开发和网站设计中,ICO图标是一种常用的图像

使用Python开发一个图像标注与OCR识别工具

《使用Python开发一个图像标注与OCR识别工具》:本文主要介绍一个使用Python开发的工具,允许用户在图像上进行矩形标注,使用OCR对标注区域进行文本识别,并将结果保存为Excel文件,感兴... 目录项目简介1. 图像加载与显示2. 矩形标注3. OCR识别4. 标注的保存与加载5. 裁剪与重置图像

使用Python实现表格字段智能去重

《使用Python实现表格字段智能去重》在数据分析和处理过程中,数据清洗是一个至关重要的步骤,其中字段去重是一个常见且关键的任务,下面我们看看如何使用Python进行表格字段智能去重吧... 目录一、引言二、数据重复问题的常见场景与影响三、python在数据清洗中的优势四、基于Python的表格字段智能去重

Python中如何控制小数点精度与对齐方式

《Python中如何控制小数点精度与对齐方式》在Python编程中,数据输出格式化是一个常见的需求,尤其是在涉及到小数点精度和对齐方式时,下面小编就来为大家介绍一下如何在Python中实现这些功能吧... 目录一、控制小数点精度1. 使用 round() 函数2. 使用字符串格式化二、控制对齐方式1. 使用

Spring AI与DeepSeek实战一之快速打造智能对话应用

《SpringAI与DeepSeek实战一之快速打造智能对话应用》本文详细介绍了如何通过SpringAI框架集成DeepSeek大模型,实现普通对话和流式对话功能,步骤包括申请API-KEY、项目搭... 目录一、概述二、申请DeepSeek的API-KEY三、项目搭建3.1. 开发环境要求3.2. mav