ubuntu20.04下C++實現點云的多邊形區域過濾(2種實現:1、pcl的CropHull濾波器;2、CUDA上實現射線法)

在點云目標檢測中,經常會有一系列的誤識別,為了減小誤識別的概率,可以通過區域過濾來刪除不需要的點云,如下圖所示
在這里插入圖片描述
本例中點云的場景為路口交通場景,已經把雷達坐標系的xoy面轉換至點云中的地平面,具體原理和操作參考:https://blog.csdn.net/m0_64293675/article/details/145208953?spm=1001.2014.3001.5502
這樣可以將區域的劃分從3維變成2維,只需要給出多邊形區域的X和Y坐標,z軸無限延伸即可。
區域過濾的第一種方法是使用PCL庫的CropHull濾波器,也就是常說的凸包算法,第二種方法是射線法,即從點出發畫一條射線(例如水平向右),統計該射線與多邊形邊的交點個數。如果交點個數為奇數,點在多邊形內;偶數,則在多邊形外。

C++實現點云的多邊形區域過濾的2種方法

  • 1、使用PCL庫的CropHull濾波器
  • 2、射線法的CUDA實現

1、使用PCL庫的CropHull濾波器

需要安裝pcl庫,apt安裝即可,建議安裝版本大于等于1.8,ubuntu20.04用ap安裝的pcl默認版本是1.10.0,符合要求。如果想從源碼安裝,自行baidu。

sudo apt install libpcl-dev
  • cut_roi.cpp
#include <iostream>
#include <vector>
#include <chrono>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/crop_hull.h>
#include <pcl/surface/convex_hull.h>using namespace std;// 不需要intensity的可以用typedef pcl::PointXYZ PointT;
typedef pcl::PointXYZI PointT;// 刪除一個多邊形區域內的點
// cloud 輸入點云
// polygon 多邊形區域的頂點坐標
pcl::PointCloud<PointT>::Ptr removePointsInPolygon(pcl::PointCloud<PointT>::Ptr cloud,const vector<pair<float, float>> &polygon)
{// 創建多邊形點云pcl::PointCloud<PointT>::Ptr hullPoints(new pcl::PointCloud<PointT>);for (const auto &vertex : polygon){// 根據PointT 的內容對應賦值PointT p;p.x = vertex.first;p.y = vertex.second;p.z = 0.0f;p.intensity = 0.0f;hullPoints->push_back(p);}// 添加第一個點使多邊形閉合hullPoints->push_back(hullPoints->points[0]);// 創建凸包對象pcl::ConvexHull<PointT> hull;hull.setInputCloud(hullPoints);hull.setDimension(2); // 2D多邊形// 存儲凸包結果的容器pcl::PointCloud<PointT>::Ptr hullCloud(new pcl::PointCloud<PointT>);vector<pcl::Vertices> hullPolygons;hull.reconstruct(*hullCloud, hullPolygons);// 創建裁剪對象pcl::CropHull<PointT> cropFilter;cropFilter.setHullCloud(hullCloud);cropFilter.setHullIndices(hullPolygons);cropFilter.setDim(2); // 2D操作// 執行裁剪(保留多邊形外的點)pcl::PointCloud<PointT>::Ptr filteredCloud(new pcl::PointCloud<PointT>);cropFilter.setInputCloud(cloud);cropFilter.setCropOutside(false); // 保留多邊形外部的點,刪除內部的點cropFilter.filter(*filteredCloud);return filteredCloud;
}// 刪除多個多邊形區域內的點
pcl::PointCloud<PointT>::Ptr removePointsInPolygons(pcl::PointCloud<PointT>::Ptr cloud,const vector<vector<pair<float, float>>> &polygons)
{for (const auto &polygon : polygons){cloud = removePointsInPolygon(cloud, polygon);}return cloud;
}int main()
{using clock = chrono::high_resolution_clock;using ms = chrono::milliseconds;using ns = chrono::nanoseconds;pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);//while (1){pcl::io::loadPCDFile("../test.pcd", *cloud);//示例多區域的頂點(x,y) 順時針逆時針都可可以vector<vector<pair<float, float>>> polygons = {{{79.5060272217, 79.175064086},{79.2747802734, 58.571964263},{81.6638717651, 41.394405365},{86.0577163696, 30.583795547},{101.274185181, 24.103635788},{122.022064209, 20.140935897},{149.628707886, 18.349731445},{195.621643066, 9.6359605789},{198.321121216, 69.765792846},{138.335754395, 130.86445617}},{{77.3776473999, -91.604118347},{80.9268569946, -45.400650024},{109.261535645, -20.841529846},{158.885635376, -19.598711013},{219.02204895, -22.8725452423},{188.727401733, -147.86555481},{159.747970581, -147.89741516},{126.374259949, -128.46434021}},{{59.590133667, 55.9770889282},{59.0997047424, 34.932685852},{54.9787826538, 34.951171875},{54.4650382996, 52.371749877}}};auto start1 = clock::now();// 刪除多邊形區域內的點pcl::PointCloud<PointT>::Ptr filteredCloud = removePointsInPolygons(cloud, polygons);auto end1 = clock::now();ns duration1 = chrono::duration_cast<ns>(end1 - start1);cout << "CPU上 使用pcl庫的CropHull濾波器刪除多個多邊形區域內的點 耗時: " << duration1.count() / 1000000.0 << " 毫秒" << endl;// 保存結果// pcl::io::savePCDFile("../filtered.pcd", *filteredCloud);cout << "num_input: " << cloud->size() << endl;cout << "num_output: " << filteredCloud->size() << endl;}return 0;
}
  • CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(lidar_process)add_definitions(-std=c++11)set(CMAKE_CXX_STANDARD 11)set(CMAKE_BUILD_TYPE Release)
# set(CMAKE_BUILD_TYPE Debug)
cmake_policy(SET CMP0074 NEW)find_package(PCL)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})include_directories("include/")add_executable(lidar_process src/cut_roi.cpp)target_link_libraries(lidar_process ${PCL_LIBRARIES})
  • 編譯運行
 mkdir buildcd buildcmake ..make./lidar_process

2、射線法的CUDA實現

需要安裝合適版本的CUDA,可以參考:https://blog.csdn.net/m0_64293675/article/details/141166292?spm=1001.2014.3001.5502

  • cut_roi_kernel.cuh
#ifndef CUT_LIDAR_ROI_CUH
#define CUT_LIDAR_ROI_CUH#include <iostream>
#include <vector>
#include <cuda_runtime.h>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>// 點云數據結構
struct Point_cuda
{float x;float y;float z;
};// 多邊形信息結構體
struct PolygonInfo {int start_idx;      // 在頂點數組中的起始索引int num_vertices;   // 多邊形的頂點數int is_negative;    // 0=將該區域刪除, 1=將該區域保留
};// CUDA核函數:判斷點是否在單個多邊形內,若返回true 表示點在多邊形內
__device__ bool isPointInSinglePolygon(float px, float py, const float2* polygon, int num_vertices);// CUDA核函數:標記點是否在任何一個多邊形內
__global__ void markPointsInPolygonsKernel(const float3* points, const float2* all_vertices, const PolygonInfo* polygons_info,int num_points, int num_polygons, int* flags);// CUDA核函數:壓縮點云(保留flags[idx]標記為0的點,不保留flags[idx]標記為1的點)
__global__ void compactPointsKernel(const float3* points, const int* flags, int num_points, float3* output, int* output_index);// CUDA實現點云多區域裁剪
std::vector<Point_cuda>  removePointsInPolygonsCUDA(std::vector<Point_cuda>  cloud, const std::vector<std::vector<std::pair<float,float>>>& polygons,const std::vector<int>& polygon_types);
#endif
  • cut_roi_kernel.cu
#include "cut_roi_kernel.cuh"// CUDA錯誤檢查宏
#define CHECK_CUDA_ERROR(call) \
do { \cudaError_t err = call; \if (err != cudaSuccess) { \std::cerr << "CUDA error at " << __FILE__ << ":" << __LINE__ \<< " - " << cudaGetErrorString(err) << std::endl; \exit(EXIT_FAILURE); \} \
} while(0)// CUDA核函數:判斷點是否在單個多邊形內,若返回true 表示點在多邊形內
__device__ bool isPointInSinglePolygon(float px, float py, const float2* polygon, int num_vertices) 
{int crossings = 0;for (int i = 0; i < num_vertices; i++) {int next = (i + 1) % num_vertices;float2 v1 = polygon[i];float2 v2 = polygon[next];// 檢查射線是否穿過邊if (((v1.y <= py) && (v2.y > py)) || ((v1.y > py) && (v2.y <= py))) {float x = v1.x + (py - v1.y) * (v2.x - v1.x) / (v2.y - v1.y);if (x > px) {crossings++;}}}// 奇數交點表示在多邊形內return (crossings % 2 == 1);
}// CUDA核函數:標記點是否在任何一個多邊形內
__global__ void markPointsInPolygonsKernel(const float3* points, const float2* all_vertices, const PolygonInfo* polygons_info,int num_points, int num_polygons, int* flags) 
{int idx = blockIdx.x * blockDim.x + threadIdx.x;if (idx >= num_points) return;float px = points[idx].x;float py = points[idx].y;// 初始化標記為0(點不在任何多邊形內)int inside_any = 0;// 遍歷所有多邊形for (int p = 0; p < num_polygons; p++) {PolygonInfo poly_info = polygons_info[p];const float2* poly_vertices = &all_vertices[poly_info.start_idx];// 檢查點是否在當前多邊形內bool inside_current = isPointInSinglePolygon(px, py, poly_vertices, poly_info.num_vertices);// 根據多邊形類型更新標記if (inside_current) {// 點在多邊形內,如果is_negative == 0,表示要將該區域內的點刪除,需要將inside_any標志記為1//如果is_negative == 1,表示要將該區域內的點保留,inside_any標志不變(仍為0)if (poly_info.is_negative == 0) {inside_any = 1;break; // 點在一個區域,無需檢查其他多邊形}        }}flags[idx] = inside_any;
}// CUDA核函數:壓縮點云(保留flags[idx]標記為0的點,不保留flags[idx]標記為1的點)
__global__ void compactPointsKernel(const float3* points, const int* flags, int num_points, float3* output, int* output_index) 
{int idx = blockIdx.x * blockDim.x + threadIdx.x;if (idx >= num_points) return;// 獲取輸出索引if (flags[idx] == 0) {int pos = atomicAdd(output_index, 1);output[pos] = points[idx];}
}// CUDA實現點云多區域裁剪
std::vector<Point_cuda>  removePointsInPolygonsCUDA(std::vector<Point_cuda>  cloud, const std::vector<std::vector<std::pair<float,float>>>& polygons,const std::vector<int>& polygon_types) 
{// 1. 準備數據int num_points = cloud.size();int num_polygons = polygons.size();// 2. 準備主機端數據結構thrust::host_vector<float3> h_points(num_points);thrust::host_vector<float2> h_all_vertices;thrust::host_vector<PolygonInfo> h_polygons_info(num_polygons);// 轉換點云數據for (int i = 0; i < num_points; i++) {h_points[i] = make_float3(cloud[i].x, cloud[i].y, cloud[i].z);}std::cout<<"num_input:"<<num_points<<std::endl;// 構建多邊形頂點數組和索引信息int vertex_offset = 0;for (int p = 0; p < num_polygons; p++) {const auto& poly = polygons[p];int num_vertices = poly.size();h_polygons_info[p].start_idx = vertex_offset;h_polygons_info[p].num_vertices = num_vertices;h_polygons_info[p].is_negative = polygon_types[p];for (const auto& vertex : poly) {h_all_vertices.push_back(make_float2(vertex.first, vertex.second));}vertex_offset += num_vertices;}// 3. 分配設備內存thrust::device_vector<float3> d_points = h_points;thrust::device_vector<float2> d_all_vertices = h_all_vertices;thrust::device_vector<PolygonInfo> d_polygons_info = h_polygons_info;thrust::device_vector<int> d_flags(num_points, 0);// 4. 創建輸出索引thrust::device_vector<int> d_output_index(1, 0);// 5. 配置核函數參數dim3 blockSize(256);dim3 gridSize((num_points + blockSize.x - 1) / blockSize.x);// 6. 執行標記核函數markPointsInPolygonsKernel<<<gridSize, blockSize>>>(thrust::raw_pointer_cast(d_points.data()),thrust::raw_pointer_cast(d_all_vertices.data()),thrust::raw_pointer_cast(d_polygons_info.data()),num_points,num_polygons,thrust::raw_pointer_cast(d_flags.data()));CHECK_CUDA_ERROR(cudaDeviceSynchronize());// 7. 統計需要保留的點數thrust::host_vector<int> h_flags = d_flags;int num_inside = thrust::count(h_flags.begin(), h_flags.end(), 1);int num_outside = num_points - num_inside;// 8. 分配輸出內存thrust::device_vector<float3> d_output(num_outside);// 重置輸出索引thrust::fill(d_output_index.begin(), d_output_index.end(), 0);// 9. 執行壓縮核函數compactPointsKernel<<<gridSize, blockSize>>>(thrust::raw_pointer_cast(d_points.data()),thrust::raw_pointer_cast(d_flags.data()),num_points,thrust::raw_pointer_cast(d_output.data()),thrust::raw_pointer_cast(d_output_index.data()));CHECK_CUDA_ERROR(cudaDeviceSynchronize());// 10. 復制結果回主機thrust::host_vector<float3> h_output = d_output;std::cout<<"num_output:"<<num_outside<<std::endl;// 11. 賦值std::vector<Point_cuda> filteredCloud;for (int i = 0; i < num_outside; i++) {Point_cuda tmp;tmp.x = h_output[i].x;tmp.y = h_output[i].y;tmp.z = h_output[i].z;filteredCloud.emplace_back(tmp);}return filteredCloud;
}
  • main.cpp
#include <iostream>
#include <chrono>
#include <vector>
#include <cmath>
#include <algorithm>
#include <fstream>
#include <sstream>
#include "cut_roi_kernel.cuh"
#include <cuda_runtime.h>using namespace std;
// 讀取離線點云.bin文件, 這里避免用pcl庫,以免還需安裝pcl,當然也可以使用pcl的io讀取.pcd格式的點云文件。
vector<Point_cuda> read_bin_files(string filename)
{vector<Point_cuda> pc_data_;std::ifstream file(filename, std::ios::binary);if (!file){std::cerr << "無法打開文件: " << filename << std::endl;return pc_data_;}// 讀取文件直到文件末尾while (file.peek() != EOF){Point_cuda point;// 依次讀取 x, y, z 坐標file.read(reinterpret_cast<char *>(&point.x), sizeof(float));file.read(reinterpret_cast<char *>(&point.y), sizeof(float));file.read(reinterpret_cast<char *>(&point.z), sizeof(float));pc_data_.push_back(point);}file.close();return pc_data_;
}// 保存刪掉區域后的點云文件為txt,cloud compare軟件也可以可視化.txt格式的點云文件
void write_all_pc_to_file(string filename, vector<Point_cuda> all_Point)
{// 打開文件以寫入數據std::ofstream outFile(filename);// 檢查文件是否成功打開if (outFile.is_open()){// 遍歷 vector 并將每個元素寫入文件for (auto num : all_Point){outFile << num.x << "," << num.y << "," << num.z << std::endl;}// 關閉文件outFile.close();std::cout << "數據已成功保存到" << filename << "文件。" << std::endl;}else{std::cerr << "無法打開文件。" << std::endl;}
}int main()
{using clock = chrono::high_resolution_clock;using ms = chrono::milliseconds;using ns = chrono::nanoseconds;// while (1){vector<Point_cuda> test_data = read_bin_files("../test.bin");//示例多區域的頂點(x,y) 順時針逆時針都可可以vector<vector<pair<float, float>>> polygons = {{{79.5060272217, 79.175064086},{79.2747802734, 58.571964263},{81.6638717651, 41.394405365},{86.0577163696, 30.583795547},{101.274185181, 24.103635788},{122.022064209, 20.140935897},{149.628707886, 18.349731445},{195.621643066, 9.6359605789},{198.321121216, 69.765792846},{138.335754395, 130.86445617}},{{77.3776473999, -91.604118347},{80.9268569946, -45.400650024},{109.261535645, -20.841529846},{158.885635376, -19.598711013},{219.02204895, -22.8725452423},{188.727401733, -147.86555481},{159.747970581, -147.89741516},{126.374259949, -128.46434021}},{{59.590133667, 55.9770889282},{59.0997047424, 34.932685852},{54.9787826538, 34.951171875},{54.4650382996, 52.371749877}}};std::vector<int> polygon_types; // 0=將該區域刪除, 1=將該區域保留for(int i = 0; i < polygons.size(); i++){polygon_types.push_back(0);}auto start1 = clock::now();vector<Point_cuda> filteredCloud = removePointsInPolygonsCUDA(test_data, polygons, polygon_types);auto end1 = clock::now();ns duration1 = chrono::duration_cast<ns>(end1 - start1);cout << "CUDA 射線法刪除多個多邊形區域內的點 耗時: " << duration1.count() / 1000000.0 << " 毫秒" << endl;write_all_pc_to_file("../filtered.txt", filteredCloud);}return 0;
}
  • CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(lidar_process)add_definitions(-std=c++11)set(CMAKE_CXX_STANDARD 11)set(CMAKE_BUILD_TYPE Release)
# set(CMAKE_BUILD_TYPE Debug)
cmake_policy(SET CMP0074 NEW)# find_package(PCL)
# include_directories(${PCL_INCLUDE_DIRS})
# link_directories(${PCL_LIBRARY_DIRS})
# add_definitions(${PCL_DEFINITIONS})find_package(CUDA)
include_directories(${CUDA_INCLUDE_DIRS})# 根據自己的cuda路徑和版本修改
include_directories("/usr/local/cuda-11.8/targets/x86_64-linux/include""/usr/local/cuda/include""/usr/local/include")
link_directories("/usr/local/cuda/lib64""/usr/local/cuda/targets/x86_64-linux/lib""/usr/local/lib")include_directories("include/")cuda_add_executable(lidar_processsrc/cut_roi_kernel.cusrc/main.cpp
)
  • 編譯運行
 mkdir buildcd buildcmake ..make./lidar_process

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

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

相關文章

Java 大視界 -- Java 大數據在智能家居場景聯動與用戶行為模式挖掘中的應用(389)

Java 大視界 -- Java 大數據在智能家居場景聯動與用戶行為模式挖掘中的應用(389) 引言: 正文: 一、傳統智能家居的 “劇本困境”:按流程走,不管人需 1.1 設備與用戶的 “理解差” 1.1.1 場景聯動 “太機械” 1.1.2 行為識別 “太粗糙” 1.1.3 技術落地的 “體驗坑” 二、…

7 ABP Framework 支持的 UI 框架

ABP Framework 支持的 UI 框架 該頁面詳細介紹了 ABP Framework 支持的三種 UI 框架&#xff08;Angular、Blazor、MVC/Razor Pages&#xff09;&#xff0c;以及它們的架構、依賴、項目結構和共享基礎設施。 框架概述 ABP 提供三種獨立又可組合使用的 UI 框架&#xff0c;它們…

C++中的`if`語句多操作條件執行及順序保證技術指南

C中的if語句多操作條件執行及順序保證技術指南 1. 引言 在C編程中&#xff0c;if語句是控制程序流程的基本結構。隨著C17引入if語句的初始化部分&#xff0c;開發者獲得了在條件判斷前執行初始化操作的能力。然而&#xff0c;實際開發中常遇到更復雜的場景&#xff1a;?在條件…

基于SpringBoot+Uniapp的非遺文化宣傳小程序(AI問答、協同過濾算法、Echarts圖形化分析)

“ &#x1f388;系統亮點&#xff1a;AI問答、協同過濾算法、Echarts圖形化分析”01系統開發工具與環境搭建前后端分離架構項目架構&#xff1a;B/S架構運行環境&#xff1a;win10/win11、jdk17小程序端&#xff1a;技術&#xff1a;Uniapp&#xff1b;UI庫&#xff1a;colorU…

[TG開發]簡單的回聲機器人

你好! 如果你想了解如何在Java上編寫Telegram機器人&#xff0c;你來對地方了!準備啟動機器人API基于HTTP請求&#xff0c;但在本書中我將使用Rubenlagus的Java庫安裝庫你可以使用不同的方法安裝TelegramBots庫, 我這里使用Maven<dependency><groupId>org.telegram…

Ubuntu下快速安裝Tomcat教程

Apache Tomcat 是一個開源的軟件服務器,用于部署和運行 Java Servlet 和 JSP(JavaServer Pages)。本文將詳細介紹如何在 Ubuntu 系統上安裝并配置 Apache Tomcat。無論你是要開發企業級應用還是學習 Java Web 開發,Tomcat 都是一個不可或缺的工具。 Tomcat 基礎功能 Tomca…

并發編程(八股)

概述并行:同一個時間點,多個線程同時執行 并發:同一個時間段,多個線程交替執行,微觀上是一個一個的執行,宏觀上感覺是同時執行 核心問題: 多線程訪問共享數據存在資源競用問題 不可見性 java內存模型(jmm) 變量數據都存在于主內存里,每個線程還有自己的工作內存(本地內存),規定…

如何在 Spring Boot 中設計和返回樹形結構的組織和部門信息

如何在 Spring Boot 中設計和返回樹形結構的組織和部門信息 文章目錄如何在 Spring Boot 中設計和返回樹形結構的組織和部門信息1. 需求分析一、數據庫表設計1.1 organization 表設計1.2 department 表設計1.3 模擬數據二、后端設計2.1 實體類設計Organization 實體類Departmen…

Java畢業設計選題推薦 |基于SpringBoot的水產養殖管理系統 智能水產養殖監測系統 水產養殖小程序

&#x1f525;作者&#xff1a;it畢設實戰小研&#x1f525; &#x1f496;簡介&#xff1a;java、微信小程序、安卓&#xff1b;定制開發&#xff0c;遠程調試 代碼講解&#xff0c;文檔指導&#xff0c;ppt制作&#x1f496; 精彩專欄推薦訂閱&#xff1a;在下方專欄&#x1…

排序概念、插入排序及希爾排序

一、排序基本概念1.就地排序&#xff1a;使用恒定的額外空間來產生輸出就地排序只是在原數組空間進行排序處理&#xff0c;也就是輸入的數組和得到的數組是同一個2.內部排序和外部排序&#xff1a;待排序數據可以一次性載入到內存中為內部排序&#xff0c;反之數據量過大就是外…

【排序算法】④堆排序

系列文章目錄 第一篇&#xff1a;【排序算法】①直接插入排序-CSDN博客 第二篇&#xff1a;【排序算法】②希爾排序-CSDN博客 第三篇&#xff1a;【排序算法】③直接選擇排序-CSDN博客 第四篇&#xff1a;【排序算法】④堆排序-CSDN博客 第五篇&#xff1a;【排序算法】⑤冒…

Android領域驅動設計與分層架構實踐

引言在Android應用開發中&#xff0c;隨著業務邏輯日益復雜&#xff0c;傳統的MVC或簡單MVP架構往往難以應對。領域驅動設計(Domain-Driven Design, DDD)結合分層架構&#xff0c;為我們提供了一種更系統化的解決方案。本文將探討如何在Android項目中應用DDD原則與分層架構&…

Android12 Framework電話功能UI定制

文章目錄簡介代碼中間按鈕Fragment創建VideoCallFragmentFragment管理添加按鍵掛斷電話功能相關文章簡介 Android版本&#xff1a;12 芯片平臺&#xff1a;展銳 如下圖為通話中的UI&#xff0c;打電話出去時顯示的UI與此也差不多&#xff0c;但來電時UI是不一樣的 這個界面是…

高并發場景下分布式ID生成方案對比與實踐指南

高并發場景下分布式ID生成方案對比與實踐指南 在分布式系統中&#xff0c;唯一且全局有序的ID生成器是很多業務的底層組件。隨著系統并發量不斷攀升&#xff0c;如何在高并發場景下保證ID的唯一性、性能、可用性和可擴展性&#xff0c;成為后端架構師需要重點考慮的問題。本文將…

Emscripten 指南:概念與使用

Emscripten 指南&#xff1a;概念與使用 什么是 Emscripten&#xff1f; Emscripten 是一個開源的編譯器工具鏈&#xff0c;用于將 C/C 代碼編譯成高效的 WebAssembly&#xff08;Wasm&#xff09;和 JavaScript。它基于 LLVM 編譯器架構&#xff0c;允許開發者&#xff1a; ?…

使用鏡像網站 打開克隆 GitHub 網站倉庫內容 git clone https://github.com/

GitHub 網站有時因 DNS 解析問題或網絡限制&#xff0c;國內訪問可能會受限。使用鏡像網站打開網站 使用鏡像網站&#xff1a;GitHub 有一些鏡像網站&#xff0c;可替代官網訪問&#xff0c;如https://hub.fastgit.org、https://gitclone.com、https://github.com.cnpmjs.org等…

Linux隨記(二十二)

一、redhat6.5 從openssh5.3 升級到openssh10 - 報錯處理【升級后賬號密碼一直錯誤 和 sshd dead but subsys locked】 虛擬機測試情況 - 正常&#xff1a;情況一、 升級后賬號密碼一直錯誤 情況二、 執行service sshd status出現 sshd dead but subsys locked

機器學習之TF-IDF文本關鍵詞提取

目錄 一、什么是 TF-IDF&#xff1f; 1.語料庫概念理解 二、TF-IDF 的計算公式 1. 詞頻&#xff08;TF&#xff09; 2. 逆文檔頻率&#xff08;IDF&#xff09; 3. TF-IDF 值 三、關鍵詞提取之中文分詞的實現 四、TF-IDF簡單案例實現 &#xff08;1&#xff09;數據集…

Flutter屏幕和字體適配(ScreenUtil)

一、簡介 flutter_screenutil 是一個 Flutter 插件&#xff0c;專門用于處理屏幕適配問題。它簡化了不同設備間尺寸差異的處理&#xff0c;確保你的應用在各種屏幕上都能保持良好的顯示效果。開發者可以通過簡單的調用來設置基于設計圖尺寸的控件寬高和字體大小。 項目地址&a…

mimiconda+vscode

安裝miniconda實現python包管理&#xff0c;并通過vscode進行編寫python代碼 miniconda簡單介紹 Miniconda 是 Anaconda 公司的一個輕量級 Python 發行版本&#xff0c;它包含了最基本的包管理器 conda 和 Python 環境&#xff0c;只帶最核心的組件&#xff0c;沒有額外的大量科…