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.1、查看图像:napari.view_image()
    • 5.2、添加图像:viewer.add_image()
    • 5.3、添加点云:viewer.add_points()
    • 5.4、添加形状:viewer.add_shapes() —— 获取线条坐标(起点和终点)
  • 六、在napari中自定义组件,并与PyQt完成交互

一、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.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.view_image(data, channel_axis=None, name=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()等函数的图像数据对象。
#         channel_axis:用于多通道图像的通道轴的索引。默认值为None,表示使用最后一个轴作为通道轴。
#       - name:图像的名称,将在napari查看器中显示。
#       - 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(),将避免程序阻塞问题(一直等待界面关闭)

"""
#########################################################################################################
# 函数说明: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:要添加的图像数据。可以是以下格式之一:
#                 2D NumPy array:灰度图像数据。
#                 3D NumPy array:3D图像数据,例如多张2D图像叠加形成的图像序列。
#                 4D NumPy array:4D图像数据,例如多通道彩色图像。
#       - name:图像的名称,将在napari查看器中显示。
#         scale:图像的缩放因子。可以是单个值,表示在所有轴上应用相同的缩放,也可以是每个轴的缩放因子列表。
#         translate:图像的平移量。可以是单个值,表示在所有轴上应用相同的平移,也可以是每个轴的平移量列表。
#         contrast_limits:图像的对比度限制,用于控制图像显示的亮度范围。可以是单个值,表示在所有轴上应用相同的对比度限制,也可以是每个轴的对比度限制列表。
#       - colormap:图像的颜色映射。可以是字符串表示的颜色映射名称,或是colormap函数。
#         blending:图像的混合模式。可以是字符串表示的混合模式名称,例如"translucent"、"additive"等。
#         visible:图像是否可见。布尔值,默认为True。
#         opacity:图像的不透明度。默认为1.0,表示完全不透明。
#         interpolation:图像的插值方法。可以是字符串表示的插值方法名称,例如"nearest"、"bilinear"、"bicubic"等。
#         rendering:图像的渲染模式。可以是字符串表示的渲染模式名称,例如"mip"、"translucent"、"attenuated_mip"等。
#         rgb:布尔值,用于指示输入图像是否为RGB彩色图像。
#         colormap_range:颜色映射的范围。可以是字符串,例如"auto"或"full",表示自动计算颜色映射范围或使用完整范围。
#########################################################################################################
"""

5.3、添加点云:viewer.add_points()

将点的坐标和可选的其他属性添加到napari查看器中,并提供了多个可选参数来自定义点云的显示。

  • viewer.add_points()用于添加点云数据,但不能直接显示。需要先添加viewer.view_image(),然后再显示点云数据。
  • 点云数据:由离散点(x, y, z)坐标的集合组成。

在这里插入图片描述

import napari
import tifffile
import numpy as np

# (1)通过tifffile加载tif图像
marked_image = tifffile.imread('marked_image.tif')

# (2)获取图像的长宽高
if len(marked_image.shape) == 3:  # 灰度3D图像:10x10x10
    depth, height, width = marked_image.shape
elif len(marked_image.shape) == 4:  # 彩色3D图像:3x10x10x10
    depth, height, width, _ = marked_image.shape

# (3)根据图像类型自适应变量值
if marked_image.dtype == np.uint8:
    max_gray_value = 255
elif marked_image.dtype == np.uint16:
    max_gray_value = 65535
elif marked_image.dtype == np.uint32:
    max_gray_value = 4294967295
####################################################################
# (4.1)提取指定像素
indices = np.argwhere(marked_image == max_gray_value)

# (4.2)指定范围内的像素值,获取坐标,并绘制为标记点
# min_gray_value = 50
# max_gray_value = max_gray_value - 1
# indices = np.argwhere((marked_image >= min_gray_value) & (marked_image <= max_gray_value))
####################################################################
viewer = napari.Viewer()  # 创建napari查看器
viewer.add_image(marked_image)  # 添加图像到napari视图
viewer.add_points(indices[:, [0, 1, 2]], size=2, face_color='red', shading='spherical', edge_width=0)  # 添加点云
napari.run()  # 显示napari图形界面
# 备注:若不添加napari.run(),将避免程序阻塞问题(一直等待界面关闭)


5.4、添加形状:viewer.add_shapes() —— 获取线条坐标(起点和终点)

注意: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()
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]

        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中自定义组件,并与PyQt完成交互

在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_())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/80760.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

grafana-zabbix基础操作篇------导入数据源

文章目录 一、grafana的安装1.1、下载地址1.2、下载后导入所安装机器1.3、yum安装解决依赖1.4、启动grafana1.5、查看端口是否启用&#xff08;端口默认3000&#xff09;1.6、浏览器访问 二、添加zabbix数据源2.1、导入数据源 **下一篇 我们讲讲构建仪表板的操作** 今天&#x…

SAP ABAP SQL查询语句-内连接与左连接使用

SQL查询语句-内连接与左连接使用 程序: data:begin of itab OCCURS 0,material type /bic/oizmaterial,batch type /bi0/oibatch,brd type /bic/oizzbrd,cpquabu type /bi0/oicpquabu,end of itab. *&**例一: clear: itab[]. select * into corresponding fields…

OpenLayers实战,OpenLayers判断点位是否与多边形有交集,判断车辆是否在电子围栏内

专栏目录: OpenLayers实战进阶专栏目录 前言 OpenLayers实战,OpenLayers判断点位是否与多边形有交集,可以用于判断车辆是否在电子围栏内,船舶是否在锚泊位中等常用案例。 在实际GIS地图业务开发中,一般是不会在前端实现是否在电子围栏这种计算的。 如果有人让你在前端实…

【数据结构】 单链表面试题讲解

文章目录 引言反转单链表题目描述示例&#xff1a;题解思路代码实现&#xff1a; 移除链表元素题目描述&#xff1a;示例思路解析&#xff1a; 链表的中间结点题目描述&#xff1a;示例&#xff1a;思路解析代码实现如下&#xff1a; 链表中倒数第k个结点题目描述示例思路解析&…

SpringBoot统⼀功能处理

前言&#x1f36d; ❤️❤️❤️SSM专栏更新中&#xff0c;各位大佬觉得写得不错&#xff0c;支持一下&#xff0c;感谢了&#xff01;❤️❤️❤️ Spring Spring MVC MyBatis_冷兮雪的博客-CSDN博客 本章是讲Spring Boot 统⼀功能处理模块&#xff0c;也是 AOP 的实战环节&…

Redis 扩展资料

Redis 扩展资料 1.缓存简介2.缓存分类3.常⻅缓存使⽤4.Redis 数据类型和使⽤5.持久化6.常⻅⾯试题7.Redis 集群&#xff08;选学&#xff09; 1.缓存简介 2.缓存分类 3.常⻅缓存使⽤ 4.Redis 数据类型和使⽤ 5.持久化 Redis 和 Memcached 有什么区别&#xff1f; 6.常⻅⾯试…

Java日志框架-JUL

JUL全称Java util logging 入门案例 先来看着入门案例&#xff0c;直接创建logger对象&#xff0c;然后传入日志级别和打印的信息&#xff0c;就能在控制台输出信息。 可以看出只输出了部分的信息&#xff0c;其实默认的日志控制器是有一个默认的日志级别的&#xff0c;默认就…

Linux命令200例:nc非常有用的网络工具(常用)

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &…

PHP-MD5注入

0x00 前言 有些零散的知识未曾关注过&#xff0c;偶然捡起反而更加欢喜。 0x01 md5 注入绕过 md5函数有两个参数&#xff0c;第一个参数是要进行md5的值&#xff0c;第二个值默认为false&#xff0c;如果为true则返回16位原始二进制格式的字符串。意思就是会将md5后的结果当…

MVCC 是否彻底解决了事物的隔离性 ?

目录 1. 什么是 MVCC 2. MVCC 是否彻底解决了事物的隔离性 3. MySQL 中如何实现共享锁和排他锁 4. MySQL 中如何实现悲观锁和乐观锁 1. 什么是 MVCC MVCC&#xff08;Multi-Version Concurrency Control&#xff0c;多版本并发控制&#xff09;是一种多版本并发控制机制&…

vue项目使用qrcodejs2遇到Cannot read property ‘appendChild‘ of null

这个问题是节点还没创建渲染完就读取节点&#xff0c;这个时候应该先让节点渲染完成在生成&#xff0c;解决方法有以下两种 1、使用$nextTick&#xff08;&#xff09;方法进行&#xff0c;这个方法是用来在节点创建渲染完成后进行的操作 that.$nextTick(() > {let qrcode …

Java基础知识小结(内部类、BigInteger、枚举、接口、重写重载和序列化)

一、Java内部类 1、内部类 在Java中&#xff0c;也可以嵌套类&#xff08;类中的类&#xff09;。嵌套类的目的是将属于同一类的类分组&#xff0c;这使代码更具可读性和可维护性。 要访问内部类&#xff0c;请创建外部类的对象&#xff0c;然后创建内部类的对象&#xff1a;…

SpringBoot中优雅的实现隐私数据脱敏(提供Gitee源码)

前言&#xff1a;在实际项目开发中&#xff0c;可能会对一些用户的隐私信息进行脱敏操作&#xff0c;传统的方式很多都是用replace方法进行手动替换&#xff0c;这样会由很多冗余的代码并且后续也不好维护&#xff0c;本期就讲解一下如何在SpringBoot中优雅的通过序列化的方式去…

【框架类】—MVVM框架

一、MVVM框架有哪些 Vue.jsReact.jsAngular.js 二、对MVVM的认识 1. MVC是什么 全称 Model View Controller, 它采用模型(Model)-视图(View)-控制器(controller)的方法把业务逻辑、数据与界面显示分离 2. MVVM的定义 MVVM是一种软件架构模式&#xff0c;它代表了模型 --视…

深入理解JVM——垃圾回收与内存分配机制详细讲解

所谓垃圾回收&#xff0c;也就是要回收已经“死了”的对象。 那我们如何判断哪些对象“存活”&#xff0c;哪些已经“死去”呢&#xff1f; 一、判断对象已死 1、引用计数算法 给对象中添加一个引用计数器&#xff0c;每当有一个地方引用它时&#xff0c;计数器就加一&…

探索无限创造力的星辰大道,画出想象的浩瀚宇宙!-turtle

介绍 视频教程地址在此&#xff1a;https://www.bilibili.com/video/BV1Pm4y1H7Tb/ 大家好&#xff0c;欢迎来到本视频&#xff01;今天&#xff0c;我们将一同探索Python编程世界中的一个有趣而创意的库——Turtle库。无需专业绘画技能&#xff0c;你就可以轻松地用代码绘制…

人工智能在网络安全中的作用:当前的局限性和未来的可能性

人工智能 (AI) 激发了网络安全行业的想象力&#xff0c;有可能彻底改变安全和 IT 团队处理网络危机、漏洞和勒索软件攻击的方式。 然而&#xff0c;对人工智能的能力和局限性的现实理解至关重要&#xff0c;并且存在许多挑战阻碍人工智能对网络安全产生直接的变革性影响。 在…

概述、搭建Redis服务器、部署LNP+Redis、创建Redis集群、连接集群、集群工作原理

Top NSD DBA DAY09 案例1&#xff1a;搭建redis服务器案例2&#xff1a;常用命令限案例3&#xff1a;部署LNPRedis案例4&#xff1a;创建redis集群 1 案例1&#xff1a;搭建redis服务器 1.1 具体要求如下 在主机redis64运行redis服务修改服务运行参数 ip 地址192.168.88.6…

在 ubuntu 18.04 上使用源码升级 OpenSSH_7.6p1到 OpenSSH_9.3p1

1、检查系统已安装的当前 SSH 版本 使用命令 ssh -V 查看当前 ssh 版本&#xff0c;输出如下&#xff1a; OpenSSH_7.6p1 Ubuntu-4ubuntu0.7, OpenSSL 1.0.2n 7 Dec 20172、安装依赖&#xff0c;依次执行以下命令 sudo apt update sudo apt install build-essential zlib1g…

[论文笔记]Glancing Transformer for Non-Autoregressive Neural Machine Translation

引言 这是论文Glancing Transformer for Non-Autoregressive Neural Machine Translation的笔记。 传统的非自回归文本生成速度较慢,因为需要给定之前的token来预测下一个token。但自回归模型虽然效率高,但性能没那么好。 这篇论文提出了Glancing Transformer,可以只需要一…