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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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;没有额外的大量科…