【高性能计算】opencl语法及相关概念(四):结合opencv进行图像高斯模糊处理

目录

  • 高斯模糊简介
  • 主函数:host端
  • 设备端函数:mywork.cl
  • 效果图对比

高斯模糊简介

高斯模糊是一种常用的图像处理技术,用于减少图像中的噪点和细节,并实现图像的平滑效果。它是基于高斯函数的卷积操作,通过对每个像素周围的邻域像素进行加权平均来实现模糊效果。

具体而言,高斯模糊通过在图像上滑动一个卷积核,将卷积核与输入图像的对应像素进行一一相乘,并将结果相加,从而产生输出图像的每个像素值。这个卷积核是一个二维高斯函数,它的形状决定了模糊的程度。在高斯函数中,离中心像素越远的像素会被赋予更小的权重,从而降低了离中心像素的贡献,实现模糊的效果。

通过调整高斯核的大小和标准差参数,可以控制模糊的程度。较大的核和较大的标准差会导致更强烈的模糊效果,而较小的核和较小的标准差则会产生更细微的模糊。

主函数:host端

#include <iostream>
#include <fstream>
#include <sstream>
#include <string.h>#ifdef __APPLE__
#include <OpenCL/cl.h>
#else
#include <CL/cl.h>
#endif
#include <opencv2/opencv.hpp>//在第一个平台中创建只包括GPU的上下文
cl_context CreateContext()
{cl_int errNum;cl_uint numPlatforms;cl_platform_id firstPlatformId;cl_context context = NULL;// 选择第一个平台errNum = clGetPlatformIDs(1, &firstPlatformId, &numPlatforms);if (errNum != CL_SUCCESS || numPlatforms <= 0){std::cerr << "Failed to find any OpenCL platforms." << std::endl;return NULL;}// 接下来尝试通过GPU设备建立上下文cl_context_properties contextProperties[] ={CL_CONTEXT_PLATFORM,(cl_context_properties)firstPlatformId,0};context = clCreateContextFromType(contextProperties, CL_DEVICE_TYPE_CPU,NULL, NULL, &errNum);if (errNum != CL_SUCCESS){std::cout << "Could not create GPU context, trying CPU..." << std::endl;context = clCreateContextFromType(contextProperties, CL_DEVICE_TYPE_CPU,NULL, NULL, &errNum);if (errNum != CL_SUCCESS){std::cerr << "Failed to create an OpenCL GPU or CPU context." << std::endl;return NULL;}}return context;
}//在第一个设备上创建命令队列
cl_command_queue CreateCommandQueue(cl_context context, cl_device_id *device)
{cl_int errNum;cl_device_id *devices;cl_command_queue commandQueue = NULL;size_t deviceBufferSize = -1;// 首先获得设备的信息errNum = clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &deviceBufferSize);if (errNum != CL_SUCCESS){std::cerr << "Failed call to clGetContextInfo(...,GL_CONTEXT_DEVICES,...)";return NULL;}if (deviceBufferSize <= 0){std::cerr << "No devices available.";return NULL;}//为设备分配内存devices = new cl_device_id[deviceBufferSize / sizeof(cl_device_id)];errNum = clGetContextInfo(context, CL_CONTEXT_DEVICES, deviceBufferSize, devices, NULL);if (errNum != CL_SUCCESS){std::cerr << "Failed to get device IDs";return NULL;}// 选择第一个设备并为其创建命令队列cl_queue_properties properties[] = {0};commandQueue = clCreateCommandQueueWithProperties(context, devices[0], properties, NULL);if (commandQueue == NULL){std::cerr << "Failed to create commandQueue for device 0";return NULL;}//释放信息*device = devices[0];delete [] devices;return commandQueue;
}//  创建OpenCL程序对象
cl_program CreateProgram(cl_context context, cl_device_id device, const char* fileName)
{cl_int errNum;cl_program program;std::ifstream kernelFile(fileName, std::ios::in);if (!kernelFile.is_open()){std::cerr << "Failed to open file for reading: " << fileName << std::endl;return NULL;}std::ostringstream oss;oss << kernelFile.rdbuf();std::string srcStdStr = oss.str();const char *srcStr = srcStdStr.c_str();program = clCreateProgramWithSource(context, 1,(const char**)&srcStr,NULL, NULL);if (program == NULL){std::cerr << "Failed to create CL program from source." << std::endl;return NULL;}errNum = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);if (errNum != CL_SUCCESS){// 输出错误信息char buildLog[16384];clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG,sizeof(buildLog), buildLog, NULL);std::cerr << "Error in kernel: " << std::endl;std::cerr << buildLog;clReleaseProgram(program);return NULL;}return program;
}//清除资源
void Cleanup(cl_context context, cl_command_queue commandQueue,cl_program program, cl_kernel kernel, cl_mem imageObjects[2],cl_sampler sampler)
{for (int i = 0; i < 2; i++){if (imageObjects[i] != 0)clReleaseMemObject(imageObjects[i]);}if (commandQueue != 0)clReleaseCommandQueue(commandQueue);if (kernel != 0)clReleaseKernel(kernel);if (program != 0)clReleaseProgram(program);if (sampler != 0)clReleaseSampler(sampler);if (context != 0)clReleaseContext(context);}
const char* GetOpenCLErrorString(cl_int errorCode)
{switch (errorCode) {case CL_SUCCESS:return "CL_SUCCESS";case CL_DEVICE_NOT_FOUND:return "CL_DEVICE_NOT_FOUND";case CL_INVALID_VALUE:return "CL_INVALID_VALUE";// 其他错误码的处理default:return "Unknown error code";}
}cl_mem LoadImage(cl_context context, char* fileName, int& width, int& height)
{cv::Mat image = cv::imread(fileName, cv::IMREAD_COLOR);if (image.empty()){std::cerr << "Error loading image" << std::endl;return 0;}/* 修改:将图像数据从 BGR 转换为 RGBA 格式 *///一般图像算法都为rgba的格式cv::cvtColor(image, image, cv::COLOR_BGR2RGBA);width = image.cols;height = image.rows;cl_image_format clImageFormat;clImageFormat.image_channel_order = CL_RGBA;clImageFormat.image_channel_data_type = CL_UNSIGNED_INT8;cl_int errNum;cl_mem clImage;cl_image_desc clImageDesc;memset(&clImageDesc, 0, sizeof(cl_image_desc));clImageDesc.image_type = CL_MEM_OBJECT_IMAGE2D;clImageDesc.image_width = width;clImageDesc.image_height = height;clImageDesc.image_row_pitch = 0;clImageDesc.image_slice_pitch = 0;clImageDesc.num_mip_levels = 0;clImageDesc.num_samples = 0;clImageDesc.image_depth = 1;/* 移除:不再需要使用缓冲区 */clImage = clCreateImage(context,CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,&clImageFormat,&clImageDesc,image.data,&errNum);if (errNum != CL_SUCCESS){std::cerr << "Error creating CL image object:" << GetOpenCLErrorString(errNum) << std::endl;return 0;}return clImage;
}void saveRGBAtoJPG(const char* filename, const char* buffer, int width, int height) {cv::Mat image(height, width, CV_8UC4, (void*)buffer);// 转换 RGBA 到 BGR 格式cv::cvtColor(image, image, cv::COLOR_RGBA2BGR);// 保存图像为 JPG 文件cv::imwrite(filename, image);
}//获取最接近的倍数
//任务均分:在并行计算中,经常需要将一个较大的任务或数据集分成多个小任务或数据块,分配给不同的处理单元并行执行。
//使用 RoundUp 函数可以将总任务数 globalSize 向上舍入到 groupSize 的倍数,确保每个处理单元都获得相等的任务数,避免了任务不均衡的情况。//内存对齐:在一些场景下,为了提高内存访问的效率,需要将数据按照一定的对齐方式存储,即确保数据的起始地址和长度都是某个特定数值的倍数。
//通过使用 RoundUp 函数,可以将数据长度 globalSize 向上舍入到 groupSize 的倍数,以满足对齐的要求,从而获得更好的内存访问性能。
size_t RoundUp(int groupSize, int globalSize)
{int r = globalSize % groupSize;if(r == 0){return globalSize;}else{return globalSize + groupSize - r;}
}
// 创建输出的图像对象
cl_mem CreateOutputImage(cl_context context, int width, int height)
{cl_image_format clImageFormat;clImageFormat.image_channel_order = CL_RGBA;clImageFormat.image_channel_data_type = CL_UNSIGNED_INT8;cl_int errNum;cl_mem clImage;cl_image_desc clImageDesc;memset(&clImageDesc, 0, sizeof(cl_image_desc));clImageDesc.image_type = CL_MEM_OBJECT_IMAGE2D;clImageDesc.image_width = width;clImageDesc.image_height = height;clImageDesc.image_row_pitch = 0;clImageDesc.image_slice_pitch = 0;clImageDesc.num_mip_levels = 0;clImageDesc.num_samples = 0;clImageDesc.image_depth = 1;clImage = clCreateImage(context,CL_MEM_WRITE_ONLY,&clImageFormat,&clImageDesc,NULL,&errNum);if (errNum != CL_SUCCESS){std::cerr << "Error creating output CL image object: " << GetOpenCLErrorString(errNum) << std::endl;return 0;}return clImage;
}int main()
{cl_context context = 0;cl_command_queue commandQueue = 0;cl_program program = 0;cl_device_id device = 0;cl_kernel kernel = 0;//这段代码定义了一个长度为 2 的 cl_mem 数组 imageObjects,并初始化所有元素为 0。cl_mem imageObjects[2] = { 0, 0 };//图像采样器 (cl_sampler) 可以与图像对象 (cl_mem) 一起使用,//用于在内核函数中从图像中获取特定位置像素的值。它控制着采样的方式,//以及在读取图像时如何处理越界的、边界问题,以及如何进行插值以获得平滑的结果。cl_sampler sampler = 0;cl_int errNum;// 创建上下文context = CreateContext();if (context == NULL){std::cerr << "Failed to create OpenCL context." << std::endl;return 1;}// 创建命令队列commandQueue = CreateCommandQueue(context, &device);if (commandQueue == NULL){Cleanup(context, commandQueue, program, kernel, imageObjects, sampler);return 1;}// 确保设备支持这种图像格式cl_bool imageSupport = CL_FALSE;clGetDeviceInfo(device, CL_DEVICE_IMAGE_SUPPORT, sizeof(cl_bool),&imageSupport, NULL);if (imageSupport != CL_TRUE){std::cerr << "OpenCL device does not support images." << std::endl;Cleanup(context, commandQueue, program, kernel, imageObjects, sampler);return 1;}// 加载图像int width, height;char* imagePath = "/work/myopencl/build/test.jpg";imageObjects[0] = LoadImage(context, imagePath, width, height);if (imageObjects[0] == 0){std::cerr << "Error loading: " << std::string("123.png") << std::endl;Cleanup(context, commandQueue, program, kernel, imageObjects, sampler);return 1;}// 创建输出的图像对象imageObjects[1] = CreateOutputImage(context, width, height);if(imageObjects[1] == 0){std::cerr << "Error creating CL output image object." << std::endl;Cleanup(context, commandQueue, program, kernel, imageObjects, sampler);return 1;}// 创建采样器对象//寻址模式(Addressing Mode)是一种定义在像素采样过程中如何处理超出纹理边界的采样坐标的方法。它决定了当采样坐标超过纹理边界时,如何获取纹理中的值。//CL_FALSE:这是一个布尔值参数,表示使用非规范化的采样坐标。非规范化坐标意味着采样坐标在整数范围内,而不是标准化到 [0, 1] 的范围。//CL_ADDRESS_CLAMP_TO_EDGE:这个参数指定了图像采样器的地址模式,CL_ADDRESS_CLAMP_TO_EDGE 表示超出图像边界的采样坐标将被截断到最近的边缘像素的颜色值。//CL_FILTER_NEAREST:这个参数指定了图像采样器的过滤方式,CL_FILTER_NEAREST 表示使用最近邻插值,也就是返回与采样坐标最近的像素值,不进行插值计算。cl_sampler_properties samplerProps[] = {CL_SAMPLER_NORMALIZED_COORDS, CL_FALSE, // 非规范化坐标CL_SAMPLER_ADDRESSING_MODE, CL_ADDRESS_CLAMP_TO_EDGE, // 寻址模式为 CL_ADDRESS_CLAMP_TO_EDGECL_SAMPLER_FILTER_MODE, CL_FILTER_NEAREST, // 过滤模式为 CL_FILTER_NEAREST0 // 列表结束符};sampler = clCreateSamplerWithProperties(context, samplerProps, &errNum);if (errNum != CL_SUCCESS){std::cerr << "Failed to create sampler: " << GetOpenCLErrorString(errNum) << std::endl;return 0;}// 创建OpenCL程序对象program = CreateProgram(context, device, "/work/myopencl/resource/mywork.cl");if (program == NULL){Cleanup(context, commandQueue, program, kernel, imageObjects, sampler);return 1;}// 创建OpenCL核kernel = clCreateKernel(program, "gaussian_filter", NULL);if (kernel == NULL){std::cerr << "Failed to create kernel" << std::endl;Cleanup(context, commandQueue, program, kernel, imageObjects, sampler);return 1;}// 设定参数//该操作的目的是将 clSetKernelArg 函数的返回值(错误码)累积到 errNum 变量中errNum = clSetKernelArg(kernel, 0, sizeof(cl_mem), &imageObjects[0]);errNum |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &imageObjects[1]);errNum |= clSetKernelArg(kernel, 2, sizeof(cl_sampler), &sampler);errNum |= clSetKernelArg(kernel, 3, sizeof(cl_int), &width);errNum |= clSetKernelArg(kernel, 4, sizeof(cl_int), &height);if (errNum != CL_SUCCESS){std::cerr << "Error setting kernel arguments." << std::endl;Cleanup(context, commandQueue, program, kernel, imageObjects, sampler);return 1;}size_t localWorkSize[2] = { 16, 16 };size_t globalWorkSize[2] =  { RoundUp(localWorkSize[0], width),RoundUp(localWorkSize[1], height) };// 将内核排队errNum = clEnqueueNDRangeKernel(commandQueue, kernel, 2, NULL,globalWorkSize, localWorkSize,0, NULL, NULL);if (errNum != CL_SUCCESS){std::cerr << "Error queuing kernel for execution." << std::endl;Cleanup(context, commandQueue, program, kernel, imageObjects, sampler);return 1;}// 将输出缓冲区读回主机char *buffer = new char [width * height * 4];size_t origin[3] = { 0, 0, 0 };size_t region[3] = { size_t(width), size_t(height), 1};//在 OpenCL 中,clEnqueueReadImage 函数用于从图像对象中读取数据到主机内存。该函数的 origin 和 region 参数用于指定要读取的区域。//origin 参数是一个包含三个元素的数组,即 [x, y, z],指定了要读取的起始位置在图像中的坐标。//origin[0] 表示 x 坐标,origin[1] 表示 y 坐标,origin[2] 表示 z 坐标。对于二维图像,我们通常将 origin[2] 设置为 0。//region 参数也是一个包含三个元素的数组,即 [width, height, depth],指定了要读取的区域的尺寸。//region[0] 表示区域的宽度,region[1] 表示区域的高度,region[2] 表示区域的深度。对于二维图像,我们可以将 region[2] 设置为 1errNum = clEnqueueReadImage(commandQueue, imageObjects[1], CL_TRUE,origin, region, 0, 0, buffer,0, NULL, NULL);if (errNum != CL_SUCCESS){std::cerr << "Error reading result buffer." << std::endl;Cleanup(context, commandQueue, program, kernel, imageObjects, sampler);return 1;}std::cout << std::endl;std::cout << "Executed program succesfully." << std::endl;//保存输出图像saveRGBAtoJPG("result.jpg", buffer, width, height);delete [] buffer;Cleanup(context, commandQueue, program, kernel, imageObjects, sampler);return 0;
}

设备端函数:mywork.cl

__kernel void gaussian_filter(__read_only image2d_t srcImg,__write_only image2d_t dstImg,sampler_t sampler,int width, int height)
{float kernelWeights[9] = { 1.0f, 2.0f, 1.0f,2.0f, 4.0f, 2.0f,1.0f, 2.0f, 1.0f };int2 startImageCoord = (int2) (get_global_id(0) - 1, get_global_id(1) - 1);int2 endImageCoord   = (int2) (get_global_id(0) + 1, get_global_id(1) + 1);int2 outImageCoord = (int2) (get_global_id(0), get_global_id(1));if (outImageCoord.x < width && outImageCoord.y < height){int weight = 0;float4 outColor = (float4)(0.0f, 0.0f, 0.0f, 0.0f);for( int y = startImageCoord.y; y <= endImageCoord.y; y++){for( int x = startImageCoord.x; x <= endImageCoord.x; x++){outColor += convert_float4(read_imageui(srcImg, sampler, (int2)(x, y)))/255.0f * (kernelWeights[weight] / 16.0f);weight += 1;}}//写入输出图像//write_imagef(dstImg, outImageCoord, outColor);//正常的高斯模糊后的图像//write_imagef(dstImg, outImageCoord, (float4)(1.0f,outColor.yzw));//二次处理float4 multipliedPixel = outColor * 255.0f;int4 clampedPixel = convert_int4(clamp(multipliedPixel, 0.0f, 255.0f));write_imagei(dstImg, outImageCoord, clampedPixel);}
}

int2 是 OpenCL 中的内建类型之一,用于表示二维整数向量。它由两个 int 类型的组成,分别表示 x 和 y 坐标。

read_imagef(srcImg, sampler, (int2)(x, y)) 是一个 OpenCL 内建函数,用于从图像对象中的某个二维点坐标读取指定位置的4通道像素值。

具体来说,read_imagef() 函数的作用是在给定的图像对象 srcImg 中,使用指定的采样器 sampler,读取位于 (x, y) 坐标位置的像素值。

该函数返回一个 float4 类型的像素值,其中的四个分量分别表示红色、绿色、蓝色和透明度(RGBA)。这是一个浮点型的 RGBA 值,范围通常是从 0.0 到 1.0。

注:image2d_t 是 OpenCL 中用于表示二维图像的类型。它并不是用来表示具体的内存类型,而是用来表示一个图像对象的引用。

在 OpenCL 中,图像对象是存储在设备内存中的二维图像数据。image2d_t 类型的对象实际上是对图像数据的引用,可以用于在内核函数中对图像数据进行读取和写入操作。

图像数据可以存储在不同的设备内存类型中,如全局内存、纹理内存等,具体取决于实际的硬件和内存配置。在创建图像对象时,您需要明确指定图像的内存类型,并在内核函数中使用相应的函数进行图像操作。

在内核函数中,可以使用像 read_imagefwrite_imagef 这样的函数来读取和写入 image2d_t 类型的图像对象。这些函数可以根据图像的内存类型进行相应的操作,以实现对图像数据的读写。

总结来说,image2d_t 并不是一个具体的内存类型,它是用来表示二维图像数据对象的引用,并提供一组操作函数来访问和修改图像数据。具体的图像数据存储在设备的某种内存类型中,如全局内存或纹理内存。

效果图对比

模糊后:
模糊后
模糊前:
模糊前

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

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

相关文章

使用acme,自动续签免费的SSL,无忧http升级https

使用acme自动续签免费的SSL 安装acme.sh颁发域名将证书安装到nginx下配置nginx的ssl自动续签 这里只进行最简单的操作 安装acme.sh 进入你的用户目录&#xff0c;如果你使用root登陆&#xff0c;那么你的用户目录就是 /root/ curl https://get.acme.sh | sh -s emailmyexam…

Linux环境基础开发工具

xshellssh xshell--充当客户端&#xff0c;提供远程登录服务 yum 背景知识 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序. 但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放…

Elasticsearch:利用矢量搜索进行音乐信息检索

作者&#xff1a;Alex Salgado 欢迎来到音乐信息检索的未来&#xff0c;机器学习、矢量数据库和音频数据分析融合在一起&#xff0c;带来令人兴奋的新可能性&#xff01; 如果你对音乐数据分析领域感兴趣&#xff0c;或者只是热衷于技术如何彻底改变音乐行业&#xff0c;那么本…

隧道结构健康监测系统,保障隧道稳定安全运行

隧道是地下隐蔽工程&#xff0c;会受到潜在、无法预知的地质因素影响&#xff0c;早期修建的隧道经常出现隧道拱顶开裂、地表沉降、隧道渗漏水、围岩变形、附近建筑物倾斜等隧道的健康问题变得日益突出&#xff0c;作为城市生命线不可或缺的一部分&#xff0c;为了确保隧道工程…

GraphQL渗透测试案例及防御办法

什么是GraphQL GraphQL 是一种 API 查询语言&#xff0c;旨在促进客户端和服务器之间的高效通信。它使用户能够准确指定他们在响应中所需的数据&#xff0c;从而有助于避免有时使用 REST API 看到的大型响应对象和多个调用。 GraphQL 服务定义了一个合约&#xff0c;客户端可…

计算机视觉与人工智能在医美人脸皮肤诊断方面的应用

一、人脸皮肤诊断方法 近年来&#xff0c;随着计算机技术和人工智能的不断发展&#xff0c;中医领域开始逐渐探索利用这些先进技术来辅助面诊和诊断。在皮肤望诊方面&#xff0c;也出现了一些现代研究&#xff0c;尝试通过图像分析技术和人工智能算法来客观化地获取皮肤相关的…

【工作笔记-0038】mongodb mongorestore 命令行导入 bson.gz数据

1. 导出的集合文件格式如下&#xff08;也就是导出的表文件&#xff09;&#xff1a; 例如&#xff1a; D:\Files\xxxx集合名称.bson.gz 怎样导出&#xff0c;这里不做介绍&#xff0c;用 mongodb compass 或者 studio 3t 都可以 2. 下载命令行导入工具&#xff1a; 官方…

ZLMeidaKit在Windows上启动时:计算机中丢失MSVCR110.dll,以及rtmp推流后无法转换为flv视频流解决

场景 ZLMediaKit在Windows上实现Rtmp流媒体服务器以及模拟rtmp推流和http-flv拉流播放&#xff1a; ZLMediaKit在Windows上实现Rtmp流媒体服务器以及模拟rtmp推流和http-flv拉流播放_zlm流媒体服务器_霸道流氓气质的博客-CSDN博客 按照以上教程启动MediaServer.exe时提示&am…

Docker Storage

文章目录 存储持久化存储类型Volumes使用场景管理Volume挂载Volume备份恢复Volume Bind mounts使用场景挂载bind tmpfs挂载tmpfs 存储持久化 在容器中所有创建的文件都是存储在容器可写层 当容器不存在后数据不会持久化&#xff0c;并且如果另一个进程需要数据&#xff0c;很…

在 Amazon 搭建无代码可视化的数据分析和建模平台

现代企业常常会有利用数据分析和机器学习帮助解决业务痛点的需求。如制造业中&#xff0c;利用设备采集上来的数据做预测性维护&#xff0c;质量控制&#xff1b;在零售业中&#xff0c;利用客户端端采集的数据做渠道转化率分析&#xff0c;个性化推荐等。 亚马逊云科技开发者…

HTML5

写在前面 一、简单认识HTML 1.1 什么是网页【2023/08/31】 网站是指因特网上根据一定的规则&#xff0c;使用HTML等制作的用于展示特定内容相关的网页集合。 网页是网站中的一“页”&#xff0c;通常是HTML格式的文件&#xff0c;它要通过浏览器来阅读。 网页是构成网站的…

【微服务】服务发现和管理技术框架选型调研

选型背景 方案对比 结论 结合实际业务和开发需要&#xff0c;着重考虑性能可靠性、功能和社区支持程度三方面&#xff0c;认为Nacos更适合作为服务发现和管理的技术框架。具体理由如下&#xff1a; 性能更好&#xff0c;可靠性更高 经过阿里、APISIX、SpringCloudAlibaba,阿…

华为数通方向HCIP-DataCom H12-821题库(单选题:201-220)

第201题 BGP 协议用​​ beer default-route-advertise​​ 命令来给邻居发布缺省路由,那么以下关于本地 BGP 路由表变化的描述&#xff0c;正确的是哪一项? A、在本地 BGP 路由表中生成一条活跃的缺省路由并下发给路由表 B、在本地 BGP 路由表中生成一条不活跃的缺省路由&…

基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作

文献计量学是指用数学和统计学的方法&#xff0c;定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体&#xff0c;注重量化的综合性知识体系。特别是&#xff0c;信息可视化技术手段和方法的运用&#xff0c;可直观的展示主题的研究发展历程、研究现状、研究…

vr健康管理服务情景化教学弥补现代医学教学中的诸多不足之处

高职高专临床医学院校以培养岗位胜任力为目的&#xff0c;该专业是一门专业性、实践性较强的医学学科&#xff0c;要求培养出来的学生具有较强的临床实践能力&#xff0c;医学生所学的全部知识&#xff0c;都应与实践相结合&#xff0c;解决临床的实际问题&#xff0c;为患者解…

ArrayList、LinkedList、Collections.singletonList、Arrays.asList与ImmutableList.of

文章目录 ListArrayListLinkedListArrayList与LinkedList的区别快速构建list集合Collections.singletonListArrays.asListImmutableList.of Java集合类型有三种&#xff1a;set(集)、list(列表)和map(映射)&#xff0c;而List集合是很常用的一种集合类型&#xff0c; List 我…

2023年MySQL-8.0.34保姆级安装教程

重点放前面&#xff1a;演示环境为windows环境。 MySQL社区版本安装教程如下&#xff1a; 一、MySQL安装包下载二、安装配置设置三、配置环境变量 大体分为3个步骤&#xff1a;①安装包的下载&#xff1b;②安装配置设置&#xff1b;③配置环境变量 一、MySQL安装包下载 下载官…

架构设计基础设施保障IaaS存储

目录 1. 云硬盘2. 对象存储3. 表单上传案例4. 服务上传验证5. 云数据库6. 云数据库操作7. 服务连接云数据库8. 新一代原生数据库9 阿里云PolarDB生产最佳实践 1. 云硬盘 HDD&#xff08;普通云盘&#xff09; 特征&#xff1a; 性能一般&#xff0c; IOPS大概在数百左右。 应…

江苏移动基于OceanBase稳步创新推进核心数据库分布式升级

*本文首发自《中国电信业》 数字经济时代&#xff0c;数据库作为企业核心数据存储、处理、挖潜等方面的关键载体&#xff0c;重要性日益凸显。对于运营商而言&#xff0c;数据库具有行业用户数量多、访问数量多、业务复杂度高、数据安全性高、响应要求性高以及需要 7*24 小时服…

illegal cyclic inheritance involving trait Iterable_2种解决方式

一、报错内容 /Users/liyangda/Code/DemoProject/demo-scala/src/scala/old04/T4.scala:11:20 illegal cyclic inheritance involving trait Iterableval value List(1, 2, 3, 4, 5, 6, 7, 8)二、问题解决 1、方式一&#xff1a;降低scala版本 可以选择降低Scala的版本&…