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

news2025/1/21 5:47:58

文章目录

  • 一、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.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图形界面

"""
#########################################################################################################
# 函数说明: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图形界面

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

# (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图层
        #########################################################################
        # (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_())

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

city walk结合VR全景,打造新时代下的智慧城市

近期爆火的city walk是什么梗&#xff1f;它其实是近年来备受追捧的城市漫步方式&#xff0c;一种全新的城市探索方式&#xff0c;与传统的旅游观光不同&#xff0c;城市漫步更注重与城市的亲密接触&#xff0c;一步步地感受城市的脉动。其实也是一种自由、休闲的方式&#xff…

vscode搭建java开发环境

一、配置extensions环境变量VSCODE_EXTENSIONS&#xff0c; 该环境变量路径下的存放安装组件&#xff1a; 二、setting配置文件 {"java.jdt.ls.java.home": "e:\\software\\jdk\\jdk17",// java运行环境"java.configuration.runtimes": [{"…

分类预测 | MATLAB实现DRN深度残差网络多输入分类预测

分类预测 | MATLAB实现DRN深度残差网络多输入分类预测 目录 分类预测 | MATLAB实现DRN深度残差网络多输入分类预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.分类预测 | MATLAB实现DRN深度残差网络多输入分类预测 2.代码说明&#xff1a;MATLAB实现DRN深度残差网络…

信捷 XDH Ethercat A_GearIn指令与轴配置

在前面的文章中描述了A_FOLLOW指令&#xff0c;有时不能满足要求&#xff0c;需要更高级的指令A_GearIn指令。 下面的例子A_GearIn指令和CNT_AB指令 实现手轮动马达动&#xff0c;手轮停马达停&#xff0c;手轮转的快马达也转得快。&#xff08;手轮输出接到PLC的X0和X1点&am…

【内测】百度AI搜索体验

收到百度搜索AI体验邀请&#xff0c;简单测试了一下&#xff0c;目前支持文案创作&#xff0c;AI绘画等。 文案创作功能还行&#xff0c;绘画功能效果比较差。

【数据库】P4 过滤数据 WHERE

过滤数据 WHERE 简介WHERE 子句操作符检测单个值案例范围值检查 BETWEEN AND空值检查 NULL 简介 数据库表一般包含大量的数据&#xff0c;很少需要检索表中的所有行。我们只检索所需数据需要指定搜索条件(search criteria)&#xff0c;搜索条件也称为过滤条件(filter conditio…

【每日一题】617. 合并二叉树

【每日一题】617. 合并二叉树 617. 合并二叉树题目描述解题思路 617. 合并二叉树 题目描述 给你两棵二叉树&#xff1a; root1 和 root2 。 想象一下&#xff0c;当你将其中一棵覆盖到另一棵之上时&#xff0c;两棵树上的一些节点将会重叠&#xff08;而另一些不会&#xff…

SpringBoot携带Jre绿色部署项目

文章目录 SpringBoot携带Jre绿色部署运行项目1. 实现步骤2. 自测项目文件目录及bat文件内容&#xff0c;截图如下&#xff1a;2-1 项目文件夹列表&#xff1a;2-2. bat内容 3. 扩展&#xff1a; 1.6-1.8版本的jdk下载 SpringBoot携带Jre绿色部署运行项目 说明&#xff1a; 实…

【数据结构与算法】十大经典排序算法-归并排序

&#x1f31f;个人博客&#xff1a;www.hellocode.top &#x1f3f0;Java知识导航&#xff1a;Java-Navigate &#x1f525;CSDN&#xff1a;HelloCode. &#x1f31e;知乎&#xff1a;HelloCode &#x1f334;掘金&#xff1a;HelloCode ⚡如有问题&#xff0c;欢迎指正&#…

基本变量与引用变量的区别

基本数据类型创建的变量&#xff0c;称为基本变量&#xff0c;该变量空间中直接存放的是其所对应的值&#xff1b; 而引用数据类型创建的变量&#xff0c;一般称为对象的引用&#xff0c;其空间中存储的是对象所在空间的地址。 public static void func() { int a 10; int b …

vue3 如果切换角色后权限不同 怎么清空之前添加动态路由。

项目中切换角色后发现会保留前面一个角色的权限&#xff0c;方法一是到login页面&#xff0c;权限重新reload&#xff0c;不过这样确实会影响体验&#xff0c;如果不采用此方案的话&#xff0c;你可以看下我从发现问题到解决问题的思路&#xff1a; 1、首先要找到一个初始状态…

光耦继电器:实现电气隔离的卓越选择

光耦继电器是一种常用的电子元件&#xff0c;用于实现电气隔离和信号传输。在工业控制、自动化系统和电力电子等领域&#xff0c;光耦继电器具有独特的特点和优势。本文将从可靠性、隔离性、响应速度和适应性等方面对光耦继电器的特点进行概述。 光耦继电器是一种典型的固态继电…

24、springboot的自动配置01--类条件注解@ConditionalOnClass、bean条件注解@ConditionalOnBean

springboot的自动配置 ★ 自动配置 Spring Boot的自动配置通常可根据依赖库自动触发——当Spring Boot检测到项目中包含某些框架的JAR包时&#xff0c;Spring Boot就会触发自动配置。其实通过EnableAutoConfiguration注解来启动▲ 其实你用到SpringBootApplication&#xff0…

vmware添加额外网卡

为vmware虚拟机添加额外网卡 vmware 配置管理界面配置系统内配置查看系统中的网卡状态启用网卡重启网络修改IP地址 vmware 配置管理界面配置 关闭运行的的系统。 编辑虚拟机设置—》添加–》选择网络适配器 选择网络适配器的模式 系统内配置 查看系统中的网卡状态 第一…

使用element UI 的el-upload上传图片并携带参数的用法

直接看代码&#xff1a;前端实现 <div class"upload"><el-uploadclass"upload-demo"name"upload_name":data"{user_name:user_name}"action"http://localhost:8000/api/deal_pest_Image":show-file-list"fal…

Linux学习之iptables规则基本演示

cat /etc/redhat-release看到操作系统是CentOS Linux release 7.6.1810&#xff0c;uname -r看到内核版本是3.10.0-957.el7.x86_64&#xff0c;iptables --version可以看到iptables版本是v1.4.21。 iptables的filter表 iptables -t filter 命令 规则链 规则 动作是iptables的…

实现定时发送天气信息到企微群

场景描述&#xff1a; 每天定时自动发送天气信息到企业微信群。通过Aboter如何实现呢&#xff1f; 步骤&#xff1a; 在【应用市场 > IPaaS应用 】中找到企微群定时发送天气信息的模板应用&#xff0c;点击【安装】。 在【IPaaS应用】流程列表中找到刚安装好的模板应用&…

【UE】Web Browser内嵌网页的使用

零、准备 1.在Edit菜单打开插件界面 搜索Web Browser并勾选&#xff0c;按提示重启引擎。 2.在资源窗口右键创建Widget Blueprint&#xff0c;并打开 3.搜索canvas panel 并拖拽到下方 4.在实验分类中找到Web Browser拖拽到Canvs Panel下 4.选中WebBrowser在右侧细节面板中…

复习1-2天【80天学习完《深入理解计算机系统》】第六天

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…