【高性能计算】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.rhkb.cn/news/114391.html

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

相关文章

亚马逊美国站上半年“日本商店”畅销品类了解一下吧!

近日&#xff0c;亚马逊美国站公布了2023年上半年“日本商店”&#xff08;JAPAN STORE&#xff09;的热门品类以及各品类销量排名前三的商品。据了解&#xff0c;亚马逊与日本贸易振兴机构 (JETRO) 合作&#xff0c;于2021年11月推出“日本商店”&#xff0c;支持日本卖家出海…

Ansible之playbooks剧本

文章目录 一.playbooks介绍1.playbooks简述2.playbooks剧本格式3.playbooks组成部分4.运行playbooks及检测文件配置 二.模块实战实例1.playbooks模块实战实例2.vars模块实战实例3.指定远程主机sudo切换用户4.when模块实战实例5.with_items迭代模块实战实例6.Templates 模块实战…

Unity 之 参数类型之值类型参数的用法

文章目录 基本数据类型结构体结构体的进一步补充 总结&#xff1a; 当谈论值类型参数时&#xff0c;我们可以从基本数据类型和结构体两个方面详细解释。值类型参数指的是以值的形式传递给函数或方法的数据&#xff0c;而不是引用。 基本数据类型 基本数据类型的值类型参数&…

vue去掉循环数组中的最后一组的某个样式style/class

vue去掉循环数组中的最后一组的某个样式style/class 需求&#xff1a;要实现这样的排列 现状 发现&#xff0c;最后一个格子并没有跟下面绿色线对齐。 最后发现 是因为 每个格子都给了 margin-right&#xff1a;36px&#xff0c;影响到了最后一个格子 所以要 将最后一个格子的…

OpenCV(十一):图像仿射变换

目录 1.图像仿射变换介绍 仿射变换&#xff1a; 仿射变换矩阵&#xff1a; 仿射变换公式&#xff1a; 2.仿射变换函数 仿射变换函数&#xff1a;warpAffine() 图像旋转&#xff1a;getRotationMatrix2D() 计算仿射变换矩阵&#xff1a;getAffineTransform() 3.demo 1.…

浅谈城市轨道交通视频监控与AI视频智能分析解决方案

一、背景分析 地铁作为重要的公共场所交通枢纽&#xff0c;流动性非常高、人员大量聚集&#xff0c;轨道交通需要利用视频监控系统来实现全程、全方位的安全防范&#xff0c;这也是保证地铁行车组织和安全的重要手段。调度员和车站值班员通过系统监管列车运行、客流情况、变电…

【Vue】集成百度地图

Vue 集成 百度地图 1、获取百度地图 ak 密钥 2、登录网址 https://lbsyun.baidu.com/ 3、注册百度地图开放平台账号&#xff0c;填写认证信息&#xff0c;并且创建应用 安装 npm install vue-baidu-map --savemain.js import BaiduMap from vue-baidu-map;Vue.use(BaiduM…

mybatisPlus多数据源方案

背景 在微服务李娜一般一个服务只有一个数据源&#xff0c;但是在有的老项目或者一些特定场景需要多数据源链接不同的数据库&#xff0c;本文以mybatisPlus为基础给出解决方案 多数据源场景分类 情形一&#xff1a;项目启动就确定了情形一&#xff1a;一些sass系统里面动态确…

[管理与领导-63]:IT基层管理者 - 潜技能 - 1 - 职场中的陷阱 - 看清楚职场中的霸凌现象

目录 前言&#xff1a; 1&#xff1a;打击自尊心 2&#xff1a;孤立他人 3&#xff1a;恶意针对 4&#xff1a;当众羞辱 5&#xff1a;持续性否定 前言&#xff1a; 职场中&#xff0c;什么样的人都有。 害人之心不可有&#xff0c;防人之心不可无。 前者教人从善&…

chatGPT训练过程

强化学习基础 强化学习是指智能体在不确定环境中最大化其获得的奖励从而达到自主决策的目的。其执行过程为&#xff1a;智能体依据策略决策从而执行动作&#xff0c;然后感知环境获取环境的状态&#xff0c;进而得到奖励(以便下次再到相同状态时能采取更优的动作)&#xff0c;…

《穷爸爸与富爸爸》时间是最宝贵的资产,只有它对所有人都是公平的

《穷爸爸与富爸爸》时间是最宝贵的资产&#xff0c;只有它对所有人都是公平的 罗伯特清崎&#xff0c;日裔美国人&#xff0c;投资家、教育家、企业家。 萧明 译 文章目录 《穷爸爸与富爸爸》时间是最宝贵的资产&#xff0c;只有它对所有人都是公平的[toc]摘录各阶层现金流图支…

WebSocket 协议及其使用案例

文章目录 前言一、初识 WebSocket 协议1.1 什么是 WebSocket 协议1.2 WebSocket 与 HTTP 的关系1.3 WebSocket 握手的过程1.4 WebSocket 解决了什么问题 二、WebSocket 数据帧格式2.1 WebSocket 数据帧格式图示2.2 各字段的详细说明 三、SpringBoot 项目中引入 WebSocket3.1 创…

STM32 FREERTOS osDelayUntil()异常

问题&#xff1a; 在使用osDelayUntil&#xff08;&#xff09;进行固定延时时发现不起作用&#xff0c;程序不能按照预期的延时进行执行&#xff08;比延时要快&#xff09;。 #define taskMBSysManage_Delay_TIME 1000 TickType_t xLastWakeTime; xLastWakeTime xTaskGe…

计算机视觉-卷积神经网络

目录 计算机视觉的发展历程 卷积神经网络 卷积&#xff08;Convolution&#xff09; 卷积计算 感受野&#xff08;Receptive Field&#xff09; 步幅&#xff08;stride&#xff09; 感受野&#xff08;Receptive Field&#xff09; 多输入通道、多输出通道和批量操作 …

算法通关村十三关 | 进制转换问题处理模板

1. 七进制数 题目&#xff1a;LeetCode504&#xff1a;504. 七进制数 - 力扣&#xff08;LeetCode&#xff09; 思路 进制转换&#xff0c;对几转换就是对几求余&#xff0c;最后将所有的余数反过来即可、如果num< 0&#xff0c;先取绝对值&#xff0c;再进行操作。 100转7…

【二等奖方案】大规模金融图数据中异常风险行为模式挖掘赛题「Aries」解题思路

第十届CCF大数据与计算智能大赛&#xff08;2022 CCF BDCI&#xff09;已圆满结束&#xff0c;大赛官方竞赛平台DataFountain&#xff08;简称DF平台&#xff09;正在陆续释出各赛题获奖队伍的方案思路&#xff0c;欢迎广大数据科学家交流讨论。 本方案为【大规模金融图数据中…

Nginx笔记(安装+使用)

Nginx开源版安装、启动 版本区别 Nginx开源版 Nginx plus 商业版 openresty Tengine 安装 将.tar.gz放到linux系统下, 使用tar -zxvf减压 进入减压目录>>>命令安装指令&#xff1a;安装到usr/local/nginx路径下 ./configure --prefix/usr/local/nginxmake &…

【OpenCV入门】第四部分——阈值

文章结构 阈值概述阈值处理函数二值化阈值处理二值化阈值处理反二值化处理 零处理低于阈值零处理超出阈值零处理 截断处理自适应处理Otsu方法 阈值概述 在PhotoShop里头&#xff0c;有一个工具可以快速抠出一幅图像中的轮廓&#xff0c;这个工具就是阈值。OpenCV也提供了阈值&…

MR混合现实汽车维修情景实训教学演示

MR混合现实技术应用于汽车维修课堂中&#xff0c;能够赋予学生更加真实&#xff0c;逼真地学习环境&#xff0c;让学生在情景体验中不断提高自己的专业能力。 MR混合现实汽车维修情景实训教学演示具体体现在&#xff1a; 1. 虚拟维修指导&#xff1a;利用MR技术&#xff0c;可…

【C++设计模式】详解装饰模式

2023年8月31日&#xff0c;周四上午 这是我目前碰到的最难的设计模式..... 非常难以理解而且比较灵活多半&#xff0c;学得贼难受&#xff0c;写得贼费劲..... 2023年8月31日&#xff0c;周四晚上19:48 终于写完了&#xff0c;花了一天的时间来学习装饰模式和写这篇博客。 …