napari图像可视化

文章目录

一、napari 简介

napari 是一个基于 PyQt 的快速、交互式多维图像查看器。

napari: a fast, interactive viewer for multi-dimensional images in Python
🥗napari 官网首页:https://napari.org/0.4.18/index.html#
🥪napari 使用案例:https://napari.org/0.4.18/gallery.html#gallery

  • 提供了一个用户友好的界面,允许用户加载、查看、分析和编辑各种类型的图像数据,包括二维图像、三维体积数据以及多通道图像数据。
  • napari 的 GUI 图形用户界面是基于 PyQt 库创建的
  • 支持自定义界面及数据交互:用户通过 PyQt 自定义组件,然后将其添加到 napari 图层,就可以实现组件自定义以及数据交互。

二、napari 使用指南

2.1、napari安装

  • 安装napari:pip install napari
  • 更新napari:pip install --upgrade napari

2.2、napari —— 巨巨巨大的一个BUG

  • 【BUG】:点击View - Toggle Full Screen将最大化软件界面,且菜单栏和很多按钮都将不可用。
  • 【影响】:此时,想要任何操作都无法退出最大化,即使关闭后重试,卸载后重试都无法达到,没有试过关机后重试。
  • 【解决方法】:Window + Tab切换窗口,菜单栏可以短暂有效且可点击,瞬间点击View - Toggle Full Screen,可解除BUG。

2.3、napari界面

2.3.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 信息

2.3.2、Window:layer list(参数详解)

在这里插入图片描述

2.3.3、Window:layer controls(点层 + 形状层 + 标签层)

在这里插入图片描述

三、项目实战

3.0、启动napari

在命令窗口中,输入指令: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.controls.close()
# viewer.window.qt_viewer.layers.close()
################################################################################

"""
#########################################################################################################
# 函数功能:用于在 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、添加图像层:viewer.add_image() —— 添加多张图像,(指定)多通道叠加显示(rendering=“additive”)

在这里插入图片描述

import napari
import tifffile


if __name__ == '__main__':
    # 加载两张图像
    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.add_image(SampleImage[500], name='SampleImage')  # 添加图像
    viewer.add_image(lineImage[500], name='lineImage', colormap='green', rendering="additive")  # 添加图像
    napari.run()  # 显示 napari 视图

3.2.2、添加图像层:viewer.add_image() —— 添加多张图像,(自动)切换到n维显示模式(Toggle ndisplay)

在这里插入图片描述

import napari
import tifffile


if __name__ == '__main__':
    # 加载两张图像
    image_path1 = r'C:\Users\Administrator\Desktop\py\SampleImage.tif'
    image_path2 = r'C:\Users\Administrator\Desktop\py\lineImage.tif'
    SampleImage = tifffile.imread(image_path1)
    lineImage = tifffile.imread(image_path2)

    viewer = napari.Viewer()  # 创建 napari 视图
    viewer.add_image(SampleImage, name='SampleImage', colormap='red')  # 添加图像
    viewer.add_image(lineImage, name='lineImage', colormap='green')  # 添加图像
    viewer.grid.enabled = not viewer.grid.enabled  # 切换到网格模式
    napari.run()  # 显示 napari 视图

3.2.3、添加图像层:viewer.add_image() —— 添加多张图像,(自动)切换到网格模式(Toggle grid mode)

在这里插入图片描述

import napari
import tifffile


if __name__ == '__main__':
    # 加载两张图像
    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.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.run()  # 显示 napari 视图

3.2.4、添加图像层:viewer.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 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='My Image')  # 添加图像图层
    viewer.dims.events.current_step.connect(update_current_slice)  # 监听 dims 的变化
    napari.run()  # 显示 napari 视图

3.2.5、添加图像层:viewer.add_image() —— 获取图像层的参数

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、添加点云层:viewer.add_points() —— 绘制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、添加点云层:viewer.add_points() —— 保存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、添加形状层:viewer.add_shapes() —— 获取线条坐标(起点和终点)

  • 根据绘制线条时的方向,获取线条的起点和终点。
  • 切换到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、添加形状层:viewer.add_shapes() —— 获取矩形坐标(左上角+右下角)

在这里插入图片描述

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)

四、扩展功能:使用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_())

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖墩会武术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值