【UE5醫學影像可視化】讀取dicom數據生成2D紋理并顯示

文章目錄

    • 1.實現目標
    • 2.實現過程
      • 2.1 數據準備
      • 2.2 創建項目
      • 2.3 dcmtk庫集成
      • 2.4 流程&原理
      • 2.5 材質
      • 2.6 應用實現
    • 3.參考資料

1.實現目標

本文在UE5中讀取本地的dicom文件,解析像素值、窗寬窗位等信息,生成2D紋理,在UE場景中實現簡單的2D醫學影像可視化

在這里插入圖片描述

2.實現過程

包括數據準備,dicom三方庫在UE工程中的集成,dicom文件中像素值,窗寬窗位Tag的解析,紋理的生成,顯示處理的材質等,以實現最終在UE場景中顯示2D醫學影像

2.1 數據準備

(1)基于開源的dicom數據,鏈接在文章第三部分參考資料中

在這里插入圖片描述

(2)在Radiant Viewer中選擇一張dicom查看,如下圖所示,也是此次本地使用的單張單幀dicom測試數據

在這里插入圖片描述

2.2 創建項目

創建引擎自帶的 C++項目,這里不再贅述

在這里插入圖片描述

2.3 dcmtk庫集成

由于gdcm庫在集成過程中,有較多的沖突需要解決,為了集成方便起見,所以本文這里直接對dcmtk庫進行集成。(直接使用github上編譯好的庫,也可以下載源碼自己本地編譯)

(1)以插件的形式集成三方庫,這也是目前UE官方所推薦的方式。這里使用的是空白的插件模板。

在這里插入圖片描述
在這里插入圖片描述

(2)插件目錄,其中后續使用的usf等shader相關文件,都放在Shaders文件夾中。
第三方庫dcmtk的相關內容,都放在插件source中的ThirdParty文件夾下

在這里插入圖片描述

(3)下載dcmtk庫,直接從github上下載dcmtkrelease版本(https://github.com/DCMTK/dcmtk/releases)
其中包含了需要的頭文件,以及靜態庫lib和動態庫dll等。(也可以下載源碼,自己本地編譯)

在這里插入圖片描述

(4)在插件的Build.cs中配置對三方庫的引用,防止找不到頭文件或者庫等報錯

在這里插入圖片描述

插件的build.cs完整代碼如下所示:

// Copyright Epic Games, Inc. All Rights Reserved.using System.IO;
using UnrealBuildTool;public class DicomVIS : ModuleRules
{public DicomVIS(ReadOnlyTargetRules Target) : base(Target){PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;PublicIncludePaths.AddRange(new string[] {// ... add public include paths required here ...});PrivateIncludePaths.AddRange(new string[] {// ... add other private include paths required here ...});PublicDependencyModuleNames.AddRange(new string[]{"Core","ImageWrapper"// ... add other public dependencies that you statically link with here ...});PrivateDependencyModuleNames.AddRange(new string[]{"CoreUObject","Engine","Slate","SlateCore",// for custom shaders"RenderCore"});DynamicallyLoadedModuleNames.AddRange(new string[]{// ... add any modules that your module loads dynamically here ...});PublicIncludePaths.AddRange(new string[] { Path.Combine(ModuleDirectory, "ThirdParty/dcmtk/include")	});string libPath = Path.Combine(ModuleDirectory, "ThirdParty/dcmtk/lib");string[] allLibs = Directory.Exists(libPath) ? Directory.GetFiles(libPath, "*.lib") : new string[0];PublicAdditionalLibraries.AddRange(allLibs);string dllPath = Path.Combine(ModuleDirectory, "ThirdParty/dcmtk/bin");string[] allDlls = Directory.Exists(dllPath) ? Directory.GetFiles(dllPath, "*.dll") : new string[0];foreach (string currentDll in allDlls){string dllName = Path.GetFileName(currentDll);PublicDelayLoadDLLs.Add(dllName);// copy dll to project directory binaries dirstring targetDllPath = Path.Combine(PluginDirectory, "../../Binaries/Win64/" + dllName);RuntimeDependencies.Add(targetDllPath, currentDll);}}
}

(5)集成過程中可能會遇到的問題

① 引入dcmtk庫相關頭文件時,verify、check等宏沖突

報錯如下所示:

在這里插入圖片描述

解決方法:

// DCMTK uses their own verify and check macros.
// Also, they include some effed up windows headers which for example include min and max macros for that
// extra bit of _screw you_
#pragma push_macro("verify")
#pragma push_macro("check")
#undef verify
#undef check#include "dcmtk/dcmdata/dcdatset.h"
#include "dcmtk/dcmdata/dcdeftag.h"
#include "dcmtk/dcmdata/dcfilefo.h"
#include "dcmtk/dcmdata/dcpixel.h"
#include "dcmtk/dcmimgle/dcmimage.h"#pragma pop_macro("verify")
#pragma pop_macro("check")

"UpdateResourceW": 不是 "UTexture2D" 的成員,原因是dcmtk中引用了windows的相關頭文件WinBase.h中已經定義了相關的宏

在這里插入圖片描述

報錯如下所示:

在這里插入圖片描述

解決方法:前置聲明

在這里插入圖片描述

2.4 流程&原理

使用dcmtk庫解析dicom數據中的像素數據,以及窗寬窗位等數據,再按照dicom標準的顯示處理流程處理即可。
(完整源碼在本文2.6部分,此部分僅作為原理說明)

(1)使用dcmtk庫解析dicom數據中的像素值,和窗寬窗位tag信息,這三個信息是顯示的必要參數

直接根據相關tag解析即可,本文這里使用的無符號的16bit測試數據,其他類型暫無考慮(原理相同,參數修改下即可)

在這里插入圖片描述

(2)窗寬窗位特殊處理

在上一篇文章中介紹了常規的dicom數據顯示流程,即先根據slopeintercept進行modality變換,在根據windowCenterwindowWidth等進行VOI變換。但本文這里是直接將沒有經過modality變換的原始像素值直接生成了2D紋理,后續的顯示處理都在shader中處理,所以這里直接對窗寬窗位應用modality反變換,這樣就在shader中節約了一次modality變換的消耗

在這里插入圖片描述

(3)創建紋理并更新像素數據

在這里插入圖片描述

(4)最終顯示:使用材質處理完成后,在PlaneStaticMesh的載體上顯示即可

2.5 材質

關于dicom顯示過程中的一些特殊處理,如VOI變換等,可以使用Material Function等方式,為了后續使用的方便,本文這里使用usfshader方式實現

(1)在插件中添加對shader文件夾的映射,以便可以在材質編輯器中使用。

// find shaders
FString shaderDir = FPaths::Combine(FPaths::ProjectPluginsDir(), "DicomVIS/Shaders/");
AddShaderSourceDirectoryMapping("/DicomVIS", shaderDir);

在這里插入圖片描述

(2)在UE編輯器中創建材質,并設置為Unlit無光照模式,以避免UE中光照對dicom醫學影像造成的顏色偏差等

在這里插入圖片描述

(3)該材質的主要節點如下所示。其中SliceTex參數為dicom像素值生成的2D紋理,WindowWidthWindowCenter為窗寬窗位信息,DataRange為數據的范圍,如本文使用的G16格式紋理,則該值為65535;若材質為G8格式的紋理,則該值為255

在這里插入圖片描述

(4)新建usf,用于dicom顯示過程中的VOI變換

float GetVOITransformation(float inputValue, float windowCenter, float windowWidth, float range)
{return saturate((inputValue - windowCenter + 0.5 / range) / (windowWidth - 1.0 / range) + 0.5);
}

在這里插入圖片描述

(5)新建自定義材質節點,并設置輸入和輸出的參數類型

在這里插入圖片描述

(6)設置自定義材質節點的Code包含頭文件路徑,以便可以在材質中使用usf中的函數

在這里插入圖片描述

2.6 應用實現

包括具體的實現步驟,可以在UE中Editor環境下加載Dicom數據,生成2D紋理和最終顯示。
本文這里只演示了16位無符號的dicom數據處理流程,其他類型的類似,需要修改生成材質的格式等參數即可

(1)dicom解析,以及生成紋理的相關功能,本文這里基于ActorCompoent實現,具體C++代碼如下所示:

SliceDataLoader.h:

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Engine/StaticMeshActor.h"
// DCMTK uses their own verify and check macros.
// Also, they include some effed up windows headers which for example include min and max macros for that
// extra bit of _screw you_
#pragma push_macro("verify")
#pragma push_macro("check")
#undef verify
#undef check#include "dcmtk/dcmdata/dcdatset.h"
#include "dcmtk/dcmdata/dcdeftag.h"
#include "dcmtk/dcmdata/dcfilefo.h"
#include "dcmtk/dcmdata/dcpixel.h"
#include "dcmtk/dcmimgle/dcmimage.h"#pragma pop_macro("verify")
#pragma pop_macro("check")#include "SliceDataLoader.generated.h"#define UpdateResource UpdateResourceUCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class DICOMVIS_API USliceDataLoader : public UActorComponent
{GENERATED_BODY()public:	// Sets default values for this component's propertiesUSliceDataLoader();// The dicom data path, that is the relative path of ue game project directory.UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dicom")FString TargetFilePath = "Data/test.dcm";// Plane static mesh componentUPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dicom")AStaticMeshActor* pPlaneMesh = nullptr;// 2d slice materialUPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dicom")UMaterial* pMaterial = nullptr;// The dicom pixel data texture2DUPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dicom")UTexture2D* pTexture2D;// Window Center of dicomUPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dicom")float WindowCenter;// Window width of dicomUPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dicom")float WindowWidth;// The min value of dicom dataUPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dicom")float Min = 0;// The range of dicom data, range = max - minUPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dicom")float Range = 1;// slope value of dicomUPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dicom")float Slope = 0;// intercept value of dicomUPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dicom")float Intercept = 0;// dicom image widthUPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dicom")int Width = 0;// dicom image heightUPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dicom")int Height = 0;// dicom image depthUPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dicom")int Depth = 0;// Load dicom data from load file path, parse pixel data to texture2DUFUNCTION(CallInEditor, BlueprintCallable, Category = "Dicom")void LoadDicom();protected:// Called when the game startsvirtual void BeginPlay() override;// use dicom pixel data to generate texture (uint16)void GenerateTexture(UTexture2D*& pTexture, uint32 width, uint32 height, uint16* pixelData);public:	// Called every framevirtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
};

SliceDataLoader.cpp:

// Fill out your copyright notice in the Description page of Project Settings.#include "SliceDataLoader.h"
#include <Kismet/KismetSystemLibrary.h>
#include <ImageUtils.h>// Sets default values for this component's properties
USliceDataLoader::USliceDataLoader()
{// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features// off to improve performance if you don't need them.PrimaryComponentTick.bCanEverTick = true;// ...
}void USliceDataLoader::LoadDicom()
{FString dicomFilePath = UKismetSystemLibrary::GetProjectDirectory() + TargetFilePath;if (!FPaths::FileExists(dicomFilePath)){UE_LOG(LogTemp, Error, TEXT("dicom file is not exist, please check!"));return;}// ToDo: use other thread to processAsyncTask(ENamedThreads::GameThread, [=, this]() {DcmFileFormat fileFormat;if (fileFormat.loadFile(TCHAR_TO_ANSI(*dicomFilePath)).good()){UE_LOG(LogTemp, Log, TEXT("dicom file loaded successfully!"));DcmDataset* dataset = fileFormat.getDataset();dataset->chooseRepresentation(EXS_LittleEndianImplicit, nullptr);Float64 windowCenter;dataset->findAndGetFloat64(DCM_WindowCenter, windowCenter);this->WindowCenter = windowCenter;Float64 windowWidth;dataset->findAndGetFloat64(DCM_WindowWidth, windowWidth);this->WindowWidth = windowWidth;Float64 slope;dataset->findAndGetFloat64(DCM_RescaleSlope, slope);this->Slope = slope;Float64 intercept;dataset->findAndGetFloat64(DCM_RescaleIntercept, intercept);this->Intercept = intercept;Uint16 bitsAllocated;dataset->findAndGetUint16(DCM_BitsAllocated, bitsAllocated);this->Depth = bitsAllocated;Uint8 pixelRepresentation = 0;dataset->findAndGetUint8(DCM_PixelRepresentation, pixelRepresentation);bool isSigned = pixelRepresentation == 1;DicomImage* dcmImage = new DicomImage(TCHAR_TO_ANSI(*dicomFilePath));if (dcmImage->getStatus() != EIS_Normal){UE_LOG(LogTemp, Error, TEXT("dicom file image loaded failed!"));return;}const int width = dcmImage->getWidth();this->Width = width;const int height = dcmImage->getHeight();this->Height = height;DcmElement* pixelDataElement;dataset->findAndGetElement(DCM_PixelData, pixelDataElement);// Tips:current just support r16 formatif (bitsAllocated == 16){TArray<int> resArray;if (!isSigned){uint16* pixelData = nullptr;pixelDataElement->getUint16Array(pixelData);this->GenerateTexture(this->pTexture2D, this->Width, this->Height, pixelData);}}}});
}// Called when the game starts
void USliceDataLoader::BeginPlay()
{Super::BeginPlay();// ...}void USliceDataLoader::GenerateTexture(UTexture2D*& pTexture, uint32 width, uint32 height, uint16* pixelData)
{//FImageUtils::CreateTexture2DEPixelFormat pixelFormat = EPixelFormat::PF_G16;if (pTexture == nullptr){pTexture = UTexture2D::CreateTransient(width, height, pixelFormat);pTexture->AddToRoot();pTexture->MipGenSettings = TMGS_NoMipmaps;pTexture->CompressionSettings = TC_Grayscale;// srgb may not effect of 16 bit.pTexture->SRGB = true;pTexture->NeverStream = true;pTexture->Filter = TextureFilter::TF_Nearest;pTexture->AddressX = TextureAddress::TA_Clamp;pTexture->AddressY = TextureAddress::TA_Clamp;}FTexture2DMipMap& mipMap = pTexture->GetPlatformData()->Mips[0];uint16* byteArray = static_cast<uint16*>(mipMap.BulkData.Lock(LOCK_READ_WRITE));long size = width * height;FMemory::Memcpy(byteArray, pixelData, size * sizeof(uint16));mipMap.BulkData.Unlock();pTexture->UpdateResource();// 更新材質if (pMaterial){UMaterialInstanceDynamic* pMaterialInsDy = UMaterialInstanceDynamic::Create(pMaterial, this);pMaterialInsDy->SetTextureParameterValue(FName("SliceTex"), pTexture);// inverset tranform window center and width by slope and intercept;FFloat16 transWL = (this->WindowCenter - this->Intercept) / this->Slope * 1 / 65535.0;FFloat16 transWW = (this->WindowWidth) / this->Slope * 1 / 65535.0;pMaterialInsDy->SetScalarParameterValue(FName("WindowCenter"), transWL);pMaterialInsDy->SetScalarParameterValue(FName("WindowWidth"), transWW);pMaterialInsDy->SetScalarParameterValue(FName("DataRange"), 65535.0);auto pStaticMeshComponent = pPlaneMesh->GetStaticMeshComponent();pStaticMeshComponent->SetMaterial(0, pMaterialInsDy);}
}// Called every frame
void USliceDataLoader::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}

(2)在場景中添加Plane,用于影像在UE中顯示的載體

在這里插入圖片描述

(3)在UE場景中添加任意的Actor,并添加上文創建的SliceDataLoader組件

在這里插入圖片描述

(4)在該組件的細節面板中,選擇測試用的dicom文件的相對路徑,以及需要應用的材質(上文創建的用于dicom顯示處理的材質)等參數

在這里插入圖片描述

(5)Editor下點擊Load Dicom按鈕,即可實現對本地Dicom文件的加載解析,2D紋理的生成,以及最終在UE場景中顯示正確的Dicom影像

在這里插入圖片描述

3.參考資料

  • 【UE4】使用動態庫(DLL)提示找不到dll該怎么解決呢:傳送門
  • 醫學圖像數據集集錦(附下載):傳送門
  • Download Train and Test Data:傳送門
  • Volume Rendering (Raymarching) Plugin for Unreal Engine:傳送門
  • DCMTK:傳送門
  • GDCM:傳送門
  • UTexture::UpdateResource() overwrote by winbase.h #define:傳送門
  • UE4 #include <windows.h>之后UpdateResource報錯:傳送門
  • UE4custom node引用自定義.ush .usf文件:傳送門
  • UE4 Gamma校正、sRGB、Linear:傳送門

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/89682.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/89682.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/89682.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

lua(xlua)基礎知識點記錄一

1. 關于 (…) 操作符 編譯階段優化&#xff1a;Lua 編譯器會對常量字符串進行優化處理&#xff0c;將連續的字符串拼接操作 (…) 合并為單個字符串。這種優化僅適用于編譯期確定的常量字符串&#xff0c;不適用于運行時生成的動態字符串。 示例&#xff1a;local str "He…

【Python數據采集】Python爬取小紅書搜索關鍵詞下面的所有筆記的內容、點贊數量、評論數量等數據,繪制詞云圖、詞頻分析、數據分析

Python爬取小紅書搜索關鍵詞下面的所有筆記的內容、點贊數量、評論數量等數據&#xff0c;繪制詞云圖、詞頻分析、數據分析 使用 Python 編寫一個簡單的爬蟲程序來從小紅書抓取與指定關鍵詞相關的筆記數據&#xff0c;并對這些數據進行基本的數據分析&#xff0c;包括詞云圖和…

最大子數組和問題-詳解Kadane算法

最大子數組和問題-詳解Kadane算法一、問題定義與暴力解法1.1 問題描述1.2 暴力解法的低效性二、Kadane算法的核心原理2.1 動態規劃思想的應用2.2 優化空間復雜度三、Kadane算法的Java實現3.1 基礎版本&#xff08;處理所有情況&#xff09;3.2 算法正確性驗證四、Kadane算法的變…

Mongoose網絡庫深度解析:從單線程到多線程的架構演進

0. 引言&#xff1a;C/C網絡編程的困境與突破 在C/C開發領域&#xff0c;網絡編程一直是一個令人頭疼的問題。與Python的requests庫或Go的net/http包不同&#xff0c;C/C缺乏統一的包管理體系和標準化的網絡API。開發者往往需要面對gcc/msvc版本差異、平臺兼容性問題、以及各種…

Jfinal+SQLite處理 sqlite數據庫執行FIND_IN_SET報錯

方法一原代碼sql " and FIND_IN_SET(s.M_ID," ids ")"; 修改為 sql " where s.M_ID"getInSql(ids);public static String getInSql(String ids) {String[] idArray ids.split(",");StringBuilder sql new StringBuilder(" I…

day24——Java高級技術深度解析:單元測試、反射、注解與動態代理

文章目錄一、單元測試&#xff1a;JUnit框架精要1.1 單元測試核心概念1.2 JUnit快速入門實戰基礎步驟&#xff1a;斷言機制驗證結果1.3 JUnit核心注解解析二、反射機制&#xff1a;框架設計的基石2.1 反射核心概念2.2 獲取Class對象的三種方式2.3 反射操作類成分獲取并執行構造…

網頁的性能優化,以及具體的應用場景

下面是每個性能優化技術的具體應用場景示例&#xff0c;結合代碼說明如何在實際項目中使用這些優化方法&#xff1a; 1. 批量DOM操作與DocumentFragment 應用場景&#xff1a;動態渲染大量列表項&#xff08;如評論區、商品列表&#xff09; 問題&#xff1a;逐個添加DOM元素會…

Fiddler 中文版 API 調試與性能優化實踐 官方中文網全程支持

在現代開發中&#xff0c;性能問題往往是產品上線后最容易被忽視的一環&#xff0c;尤其是API接口性能。一旦接口響應時間過長或在高并發場景下出現性能瓶頸&#xff0c;可能直接影響用戶體驗和系統穩定性。對于開發者來說&#xff0c;如何精確地找到瓶頸所在&#xff0c;如何模…

嵌入式硬件篇---機械臂運動學解算(3自由度)

實際 3 自由度機械臂的解算是機器人控制的核心&#xff0c;涉及運動學正解&#xff08;關節角度→末端位姿&#xff09;和逆解&#xff08;目標位姿→關節角度&#xff09;。以下從結構建模、解算方法、代碼實現和應用場景四個維度詳細展開&#xff0c;結合工業級機械臂的典型場…

在攝像機視圖中想像在普通 3D 視口里那樣隨意移動

有兩條最常用的方法&#xff1a;1. 「鎖定相機到視圖」(Lock Camera to View)步驟進入相機視圖&#xff1a;按 Numpad 0&#xff08;若無數字鍵盤&#xff0c;可在 Edit → Preferences → Input 勾選 Emulate Numpad 后用主鍵盤 0&#xff09;。右側呼出 N 面板&#xff0c;切…

An End-to-End Attention-Based Approach for Learning on Graphs NC 2025

NC 2025 | 一種基于端到端注意力機制的圖學習方法 Nature Communications IF=15.7 綜合性期刊 1區 參考:https://mp.weixin.qq.com/s/cZ-d8Sf8wtQ9wfcGOFimCg 今天介紹一篇發表在 Nature Communications 的圖學習論文《An end-to-end attention-based approach for learnin…

【牛客刷題】小紅的數字串

文章目錄 一、題目描述 1.1 輸入描述 1.2 輸出描述 1.3 示例1 二、高效解法 2.1 核心算法設計 2.2 算法設計理念 2.2.1 算法流程詳解 2.2.2 復雜度分析 2.3 算法優勢分析 2.3.1 關鍵優化點 2.3.2 正確性驗證 2.4 邊界處理 2.5 總結與擴展 一、題目描述 小紅拿到了一個數字串(由…

微算法科技技術創新,將量子圖像LSQb算法與量子加密技術相結合,構建更加安全的量子信息隱藏和傳輸系統

隨著信息技術的發展&#xff0c;數據的安全性變得尤為重要。在傳統計算模式下&#xff0c;即便采用復雜的加密算法&#xff0c;也難以完全抵御日益增長的網絡攻擊威脅。量子計算技術的出現為信息安全帶來了新的解決方案。然而&#xff0c;量子圖像處理領域仍面臨復雜度高、效率…

博客摘錄「 Springboot入門到精通(超詳細文檔)」2025年7月4日

1.Spring Boot返回Json數據及數據封裝1. Controller 中使用RestController注解即可返回 Json 格式的數據首先看看RestController注解包含了什么東西&#xff0c; ResponseBody 注解是將返回的數據結構轉換為 Json 格式Target({ElementType.TYPE}) Retention(RetentionPolicy.RU…

企業安全防護:堡壘機技術解析

目錄 一、堡壘機&#xff1a;企業IT運維的安全守門人 1.1 核心價值矩陣 1.2堡壘機典型部署架構 二、堡壘機如何構建安全防線 2.1 四層防護體系 2.2 關鍵工作流程 三、堡壘機關鍵技術指標對比表 四、智能堡壘機的發展趨勢 一、堡壘機&#xff1a;企業IT運維的安全守門人…

傳輸層協議 TCP

TCP 協議TCP 全稱為 "傳輸控制協議(Transmission Control Protocol"). 人如其名, 要對數據的傳輸進行一個詳細的控制TCP 協議段格式源/目的端口號: 表示數據是從哪個進程來, 到哪個進程去32 位序號/32 位確認號4 位 TCP 報頭長度: 表示該 TCP 頭部有多少個 32 位 bit…

RT-Thread的概念和移植

一、操作系統的概念 操作系統&#xff08;英語&#xff1a;Operating System&#xff0c;縮寫&#xff1a;OS&#xff09;是一組主管并控制計算機操作、運用和運行硬件、軟件資源和提供公共服務來組織用戶交互的相互關聯的系統軟件程序。根據運行的環境&#xff0c;操作系統可以…

基于單片機傾角測量儀/角度測量/水平儀

傳送門 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品題目速選一覽表 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品題目功能速覽 概述 本設計實現了一種基于單片機的高精度數字傾角測量儀。系統核心由傾角傳感器&#xff08;ADXL345傾…

深度學習 -- 初步認識Torch

深度學習 – 初步認識Torch 文章目錄深度學習 -- 初步認識Torch一&#xff0c;認識人工智能1.1 人工智能的本質1.2 人工智能的實現過程二&#xff0c;認識Torch2.1簡介2.2 概述2.3 Tensor的創建2.3.1 torch.tensor2.3.2 torch.Tensor三&#xff0c;創建線性和隨機張量3.1創建線…

BGP的“聰明選路”遇上了TCP的“路徑潔癖”,需人工調和

在路由器R1上有兩條外網&#xff0c;WAN1和WAN2。R1上做了域名分流功能&#xff0c;全局網址分到WAN1&#xff0c;指定域名分到WAN2&#xff08;優先級更高&#xff09;。癥狀是用戶反饋部分網頁無法打開。于是各種檢查嘗試...... 2天過去了......最終結論是&#xff1a;即使S…