【高性能计算】opencl语法及相关概念(五):图像的仿射变换缩放

news2024/11/18 17:26:37

目录

  • 简介
  • 宿主机程序
  • 设备端函数
  • 缩放效果图

简介

要使用仿射变换完成图像等宽高比缩放,可以按照以下步骤进行操作:

  1. 定义仿射变换矩阵:首先,定义一个仿射变换矩阵,用于描述缩放操作。该矩阵是一个2x3的矩阵,包含平移、缩放和旋转的参数。对于缩放而言,我们只需要调整矩阵中的缩放参数。

    其中,scale_xscale_y 分别表示在 x 和 y 方向上的缩放因子。

  2. 构建仿射变换矩阵:使用上述定义的缩放因子,将其填充到仿射变换矩阵的相应位置。

  3. 应用仿射变换:对于每个图像像素,根据仿射变换矩阵的逆矩阵将其映射到原始图像中的位置。然后,使用插值方法计算映射后位置的像素值。

    常用的插值方法包括最近邻插值、双线性插值和双三次插值。根据具体需求和性能要求,选择合适的插值方法。

  4. 创建新图像:根据变换后的坐标和插值结果,生成新的缩放后的图像。

本文使用的插值方法是双线性插值。

宿主机程序

#include <iostream>
#include <fstream>
#include <sstream>
#include <string.h>
#include <algorithm>
#ifdef __APPLE__
#include <OpenCL/cl.h>
#else
#include <CL/cl.h>
#endif
#include <opencv2/opencv.hpp>
struct AffineMatrix{
    float i2d[6];   
    float d2i[6];  
    void invertAffineTransform(float imat[6], float omat[6]){
        float i00 = imat[0];  float i01 = imat[1];  float i02 = imat[2];
        float i10 = imat[3];  float i11 = imat[4];  float i12 = imat[5];
        float D = i00 * i11 - i01 * i10;
        D = D != 0 ? 1.0 / D : 0;
        float A11 = i11 * D;
        float A22 = i00 * D;
        float A12 = -i01 * D;
        float A21 = -i10 * D;
        float b1 = -A11 * i02 - A12 * i12;
        float b2 = -A21 * i02 - A22 * i12;
        omat[0] = A11;  omat[1] = A12;  omat[2] = b1;
        omat[3] = A21;  omat[4] = A22;  omat[5] = b2;
    }

    void compute(const cv::Size& from, const cv::Size& to){
        float scale_x = to.width / (float)from.width;
        float scale_y = to.height / (float)from.height;
        float scale = std::min(scale_x, scale_y); 
        i2d[0] = scale;  i2d[1] = 0;  i2d[2] = 
            -scale * from.width  * 0.5  + to.width * 0.5 + scale * 0.5 - 0.5;

        i2d[3] = 0;  i2d[4] = scale;  i2d[5] = 
            -scale * from.height * 0.5 + to.height * 0.5 + scale * 0.5 - 0.5;

        invertAffineTransform(i2d, d2i);
    }
};
//在第一个平台中创建只包括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;
    }
 
    // 创建输出的图像对象
    int outputWidth=640;
    int outputHeight=640;
    imageObjects[1] = CreateOutputImage(context,outputWidth,outputHeight);
    if(imageObjects[1] == 0)
    {
        std::cerr << "Error creating CL output image object." << std::endl;
        Cleanup(context, commandQueue, program, kernel, imageObjects, sampler);
        return 1;
    }

    AffineMatrix affine;
    affine.compute(cv::Size(width, height), cv::Size(outputWidth, outputHeight));

    // 创建一个包含 float 数组数据的缓冲区对象
    cl_mem kbuffer = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float) * 6, affine.d2i, NULL);

    // 创建采样器对象
    //寻址模式(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_EDGE
        CL_SAMPLER_FILTER_MODE, CL_FILTER_NEAREST, // 过滤模式为 CL_FILTER_NEAREST
        0 // 列表结束符
    };

    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, "affine_transformation", 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_mem), (void*)&kbuffer);
    //传递宽高:
    errNum |= clSetKernelArg(kernel, 4, sizeof(int), &width);
    errNum |= clSetKernelArg(kernel, 5, sizeof(int), &height);
    errNum |= clSetKernelArg(kernel, 6, sizeof(int), &outputWidth);
    errNum |= clSetKernelArg(kernel, 7, sizeof(int), &outputHeight);
    if (errNum != CL_SUCCESS)
    {
        std::cerr << "Error setting kernel arguments." << std::endl;
        Cleanup(context, commandQueue, program, kernel, imageObjects, sampler);
        return 1;
    }
 
    size_t globalWorkSize[2] = { 10000,10000 };
    // size_t localWorkSize[2] =  { RoundUp(localWorkSize[0], width),
    //                               RoundUp(localWorkSize[1], height) };
 
    // 将内核排队
    errNum = clEnqueueNDRangeKernel(commandQueue, kernel, 2, NULL,
                                    globalWorkSize, NULL,
                                    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 [outputWidth * outputHeight * 4];
    size_t origin[3] = { 0, 0, 0 };
    size_t region[3] = { size_t(outputWidth), size_t(outputHeight), 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] 设置为 1
    errNum = 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, outputWidth, outputHeight);
    delete [] buffer;
    Cleanup(context, commandQueue, program, kernel, imageObjects, sampler);
    return 0;
}

设备端函数

__kernel void affine_transformation(__read_only image2d_t srcImg,
                                    __write_only image2d_t dstImg,
                                    sampler_t sampler,
                                    __global float* mykernel,
                                    int srcWidth,
                                    int srcHeight,
                                    int dstWidth,
                                    int dstHeight)

{

    int dstx = get_global_id(0);
    int dsty = get_global_id(1);
    if (dstx >= dstWidth || dsty >= dstHeight)  return;
    //默认填充灰色:
    float c0 = 114, c1 = 114, c2 = 114;
    float src_x = 0; float src_y = 0;

    src_x = mykernel[0] * dstx + mykernel[1] * dsty + mykernel[2];
    src_y = mykernel[3] * dstx + mykernel[4] * dsty + mykernel[5];
    //printf("%f,%f\n",src_x,src_y);
    if(src_x < -1 || src_x >= srcWidth || src_y < -1 || src_y >= srcHeight)
    {
    }
    else
    {
        int y_low = floor(src_y);
        int x_low = floor(src_x);
        int y_high = y_low + 1;
        int x_high = x_low + 1;
        int fill_value=114;
        float ly    = src_y - y_low;
        float lx    = src_x - x_low;
        float hy    = 1 - ly;
        float hx    = 1 - lx;
        float w1    = hy * hx, w2 = hy * lx, w3 = ly * hx, w4 = ly * lx;
        float4 v1=(float4)(fill_value, fill_value, fill_value,1.0);
        float4 v2=(float4)(fill_value, fill_value, fill_value,1.0);
        float4 v3=(float4)(fill_value, fill_value, fill_value,1.0);
        float4 v4=(float4)(fill_value, fill_value, fill_value,1.0);
        if(y_low >= 0){
            if (x_low >= 0)
                v1=convert_float4(read_imageui(srcImg, sampler, (int2)(x_low, y_low)));
            if (x_high < srcWidth)
                v2=convert_float4(read_imageui(srcImg, sampler, (int2)(x_high, y_low)));
        }
        
        if(y_high < srcHeight){
            if (x_low >= 0)
                v3=convert_float4(read_imageui(srcImg, sampler, (int2)(x_low, y_high)));
            if (x_high < srcWidth)
                v4=convert_float4(read_imageui(srcImg, sampler, (int2)(x_high, y_high)));
        }

        c0 = floor(w1 * v1.x + w2 * v2.x + w3 * v3.x + w4 * v4.x + 0.5f);
        c1 = floor(w1 * v1.y + w2 * v2.y + w3 * v3.y + w4 * v4.y + 0.5f);
        c2 = floor(w1 * v1.z + w2 * v2.z + w3 * v3.z + w4 * v4.z + 0.5f);
       // printf("%f\n",convert_float4(read_imageui(srcImg, sampler, (int2)(3,3)).x);
    }

    int2 dstindex= (int2) (dstx, dsty);
    float4 outColor = (float4)(c0, c1, c2, 1.0f);
    int4 clampedPixel = convert_int4(clamp(outColor, 0.0f, 255.0f));
    write_imagei(dstImg, dstindex, clampedPixel);
}
    

   

缩放效果图

缩放前:
请添加图片描述
缩放后:
请添加图片描述

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

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

相关文章

实时操作系统Freertos开坑学习笔记:(三):任务的挂起与恢复、中断管理

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、任务挂起与恢复的API函数1.具体函数描述①vTaskSuspend()任务挂起&#xff08;暂停&#xff09;函数②vTaskResume()任务恢复函数③xTaskResumeFromISR()在…

PAT 1167 Cartesian Tree

个人学习记录&#xff0c;代码难免不尽人意。 A Cartesian tree is a binary tree constructed from a sequence of distinct numbers. The tree is heap-ordered, and an inorder traversal returns the original sequence. For example, given the sequence { 8, 15, 3, 4, 1…

机器学习-波士顿房价预测

目录 一.数据处理 读入数据 数据形状变换 数据集划分 数据归一化处理 将上面封装成load data函数 二. 模型设计 完整封装运行代码&#xff1a; 根据loss值进行梯度计算 控制部分变量的变化图像&#xff1a; 一.数据处理 读入数据 # 导入需要用到的package import numpy as np…

迷你上下标数字转换器

将输入字符串中的数字转换成迷你数字字符&#xff0c;您可以复制带迷你数字的纯文本到任意地方。 (本笔记适合初通Python&#xff0c;熟悉六大基本数据类型(str字符串、int整型、float浮点型、list列表、tuple元组、set集合、dict字典)常规应用的 coder 翻阅) 【学习的细节是欢…

1.1 计算机网络在信息时代中的作用

思维导图&#xff1a; 正文&#xff1a; 我的理解&#xff1a; 这段话是一本书或课程的第一章简介&#xff0c;它的目的是为读者或学生提供一个关于计算机网络基础知识的框架或大纲。 首先&#xff0c;它强调了这章是整本书的一个概览&#xff0c;会先介绍计算机网络在信息时…

Oracle数据库尚硅谷学习笔记

文章目录 Oracle数据库体系结构简介补充SQL初步导入sql文件别名连接符distinct去重的坑 过滤和排序数据日期格式比较运算其它比较运算符逻辑运算优先级排序 单行函数SQL中不同类型的函数单行函数字符数值日期转换通用 使用条件表达式嵌套查询 多表查询等值连接非等值连接左外连…

大数据组件-Flink环境搭建

&#x1f947;&#x1f947;【大数据学习记录篇】-持续更新中~&#x1f947;&#x1f947; 个人主页&#xff1a;beixi 本文章收录于专栏&#xff08;点击传送&#xff09;&#xff1a;【大数据学习】 &#x1f493;&#x1f493;持续更新中&#xff0c;感谢各位前辈朋友们支持…

盛元广通生态环境监测实验室管理系统LIMS

系统背景&#xff1a; 当环境问题已经被普罗大众都开始关心那已经是世界的焦点了&#xff0c;我们在面临水污染、空气污染日益加剧的今天&#xff0c;为解决这些问题&#xff0c;做好监测预警&#xff0c;需要更可靠的数据支撑和智能化管理手段来指导我们决策和行动&#xff0…

【docker】Mac M1 构建 x64 linux镜像

亲测教程 文章目录 首先构建环境 首先 首先你需要有一个 Dockerfile 比如&#xff1a;这里以一个 python 项目举例 FROM python:3.10-slimWORKDIR /appCOPY requirements.txt requirements.txt RUN pip install --no-cache-dir -r requirements.txtCOPY . .CMD [ "pyth…

Android Studio新版本New UI及相关设置丨遥遥领先版

1、前言 俗话说工欲善其事必先利其器嘛&#xff0c;工具用不好怎么行呢&#xff0c;借着Android Studio的更新&#xff0c;介绍一下新版本中的更新内容&#xff0c;以及日常开发中那些好用的设置。 2、关于新版本 2.1、最新正式版本 Android Studio Giraffe | 2022.3.1 Pat…

IntelliJ IDEA(Windows 版)的所有快捷键

&#x1fa81;&#x1f341; 希望本文能够给您带来一定的帮助&#x1f338;文章粗浅&#xff0c;敬请批评指正&#xff01;&#x1f341;&#x1f425; 大家好 本文参考了 IntelliJ IDEA 的官网&#xff0c;列举了IntelliJ IDEA&#xff08;Windows 版&#xff09;的所有快捷…

微服务-OpenFeign基本使用

一、前言 二、OpenFeign基本使用 1、OpenFeign简介 OpenFeign是一种声明式、模板化的HTTP客户端&#xff0c;它使得调用RESTful网络服务变得简单。在Spring Cloud中使用OpenFeign&#xff0c;可以做到像调用本地方法一样使用HTTP请求访问远程服务&#xff0c;开发者无需关注…

垃圾回收 - 复制算法

GC复制算法是Marvin L.Minsky在1963年研究出来的算法。说简单点&#xff0c;就是只把某个空间的活动对象复制到其它空间&#xff0c;把原空间里的所有对象都回收掉。这是一个大胆的想法。在此&#xff0c;我们将复制活动对象的原空间称为From空间&#xff0c;将粘贴活动对象的新…

如何快速搭建母婴行业的微信小程序?

如果你想为你的母婴行业打造一个独特的小程序&#xff0c;但没有任何编程经验&#xff0c;别担心&#xff01;现在有许多小程序制作平台提供了简单易用的工具&#xff0c;让你可以轻松地建立自己的小程序。接下来&#xff0c;我将为你详细介绍搭建母婴行业小程序的步骤。 首先&…

mysql(九)mysql主从复制

目录 前言概述提出问题主从复制的用途工作流程 主从复制的配置创建复制账号配置主库和从库启动主从复制从另一个服务器开始主从复制主从复制时推荐的配置sync_binloginnodb_flush_logs_at_trx_commitinnodb_support_xa1innodb_safe_binlog 主从复制的原理基于语句复制优点&…

线程的组织(TCB)

线程隶属于进程&#xff0c;是操作系统进行任务调度的最小单位。 Thread线程知识小结_迷茫的羔羊羊的博客-CSDN博客? 线程控制块TCB的结构如下&#xff1a; 将多个线程的线程控制块TCB组成一张线程表&#xff1a;

【前端demo】动态赋值CSS

文章目录 效果过程html实现oninput与onchange事件统一配置CSS 代码HTMLCSSJS 其他demo 效果 动态显示CSS样式&#xff0c;由:root统一配置。 效果预览&#xff1a;https://codepen.io/karshey/pen/BavLrwy 参考&#xff1a; Dynamic CSS Variables(codepen.io) 漫谈document…

开源风雷CFD软件多物理场耦合接口开发路线分享!!!

本文将基于开发过程中积累的经验&#xff0c;介绍风雷如何基于preCICE开发适配器。 preCICE是一个开源的多物理场数值模拟耦合库&#xff0c;可以用于多个求解器联合求解一个复杂的多场问题&#xff0c;支持在大规模并行系统上应用&#xff0c;具有良好的并行效率。并且可以对…

危险边缘:揭示 Python 编程中易被忽视的四个安全陷阱

今天我们将要谈论一个非常重要的话题&#xff1a;Python 编程中的安全问题。作为一门广受欢迎的编程语言&#xff0c;Python 已经成为了许多开发者、计算机专业学生以及打工人的必备技能。 原文链接食用更佳 危险边缘&#xff1a;揭示 Python 编程中易被忽视的四个安全问题 然…

算法基础-数学知识-欧拉函数、快速幂、扩展欧几里德、中国剩余定理

算法基础-数学知识-欧拉函数、快速幂、扩展欧几里德、中国剩余定理 欧拉函数AcWing 874. 筛法求欧拉函数 快速幂AcWing 875. 快速幂AcWing 876. 快速幂求逆元 扩展欧几里德&#xff08;裴蜀定理&#xff09;AcWing 877. 扩展欧几里得算法AcWing 878. 线性同余方程 中国剩余定理…