OpenCV中的矩阵操作

        OpenCV中的矩阵操作主要围绕Mat类展开,涵盖创建、访问、运算及变换等。

1. 创建矩阵

  • 零矩阵/单位矩阵‌:
    Mat zeros = Mat::zeros(3, 3, CV_32F); // 3x3浮点零矩阵
    Mat eye = Mat::eye(3, 3, CV_32F);      // 3x3单位矩阵
  • 自定义初始化‌:
    Mat A = (Mat_<float>(3,3) << 1,2,3,4,5,6,7,8,9);

2. 访问与修改元素

  • 使用at方法‌(注意数据类型):
    float elem = A.at<float>(0,0); // 访问(0,0)元素
    A.at<float>(1,1) = 10;         // 修改(1,1)元素
  • 多通道矩阵‌(如RGB图像):
    Vec3b pixel = img.at<Vec3b>(i,j); // 获取三通道像素值
    pixel = 255;                   // 修改蓝色通道,实际上取的pixel[0]
    pixel[0] = 255;                // 修改蓝色通道
    pixel[1] = 255;                // 修改绿色通道  
    pixel[2] = 255;                // 修改红色通道img.at<Vec3b>(14,25) [0]= 25;//B    
    img.at< Vec3b >(14,25) [1]= 25;//G    
    img.at< Vec3b >(14,25 [2]= 25;//R 
  • 使用ptr方法:
    Mat a(Size(720,1024),CV_8UC3);
    for(int i=0;i<a.rows;i++){for(int j=0;j<a.cols;j++){a.ptr(i,j)[0]=0;a.ptr(i,j)[1]=0;a.ptr(i,j)[2]=255;}
    }
    for(int i=0;i<a.rows;i++){for(int j=0;j<a.cols;j++){a.ptr<Vec3b>(i,j)[0]=0;a.ptr<Vec3b>(i,j)[1]=0;a.ptr<Vec3b>(i,j)[2]=255;}
    }
  • 迭代器访问元素:
    Mat a(Size(720,1024),CV_8UC3);
    for(auto iter=a.begin<Vec3b>();iter!=a.end<Vec3b>();iter++){iter[0]=255;iter[1]=0;iter[2]=0;
    }

3. 矩阵运算

  • 基本运算‌(需尺寸/类型一致):
    使用"+"和"-"符号进行矩阵加减运算。

  • cv::Mat a= Mat::eye(Size(3,2), CV_32F);
    cv::Mat b= Mat::ones(Size(3,2), CV_32F);
    cv::Mat c= a+b;
    cv::Mat d= a-b;
  • 矩阵乘法(A*B)‌:
    使用"*"号计算矩阵与标量相乘,矩阵与矩阵相乘。 A*B是以数学运算中矩阵相乘的方式实现的,即Mat矩阵A和B被当做纯粹的矩阵做乘法运算,这就要求A的列数等       于B的行数时,才能定义两个矩阵相乘。如A是m×n矩阵,B是n×p矩阵,它们的乘积AB是一个m×p矩阵。

    另外:参与点乘的两个Mat矩阵的数据类型(type)只能是 CV_32F、 CV_64FC1、 CV_32FC2、 CV_64FC2 这4种类        型中的一种。若选用其他类型,比如CV_8UC1,编译器会报错。
    #include "core/core.hpp"     
    #include "iostream"  using namespace std;   
    using namespace cv;  int main(int argc,char *argv[])    
    { Mat A=Mat::ones(2,3,CV_32FC1);Mat B=Mat::ones(3,2,CV_32FC1);Mat AB;A.at<float>(0,0)=1;A.at<float>(0,1)=2;A.at<float>(0,2)=3;A.at<float>(1,0)=4;A.at<float>(1,1)=5;A.at<float>(1,2)=6;B.at<float>(0,0)=1;B.at<float>(0,1)=2;B.at<float>(1,0)=3;B.at<float>(1,1)=4;B.at<float>(2,0)=5;B.at<float>(2,1)=6;AB=A*B;cout<<"A=\n"<<A<<endl<<endl;cout<<"B=\n"<<B<<endl<<endl;cout<<"AB=\n"<<AB<<endl<<endl;system("pause");
    }
  • 矩阵dot
    Opencv中.dot操作才算得上是真正的“点乘”,A.dot(B)操作相当于数学向量运算中的点乘,也叫向量的内积、数量积。
        double dot(InputArray m) const;

    dot说明:

    1).  对两个向量执行点乘运算,就是对这两个向量对应位一一相乘之后求和的操作,点乘的结果是一个标量。   

    对于向量a和向量b:

    a和b的点积公式为:

    要求向量a和向量b的行列数相同。

    Mat矩阵的dot方法扩展了一维向量的点乘操作,把整个Mat矩阵扩展成一个行(列)向量,之后执行向量的点乘运算,仍然要求参与dot运算的两个Mat矩阵的行列数完全一致。

    2).  dot方法声明中显示返回值是double,所以A.dot(B)结果是一个double类型数据,不是Mat矩阵,不能把A.dot(B)结果赋值给Mat矩阵。

    #include "core/core.hpp"     
    #include "iostream"  using namespace std;   
    using namespace cv;  int main(int argc,char *argv[])    
    { Mat A=Mat::ones(2,3,CV_8UC1);Mat B=Mat::ones(2,3,CV_8UC1);A.at<uchar>(0,0)=1;A.at<uchar>(0,1)=2;A.at<uchar>(0,2)=3;A.at<uchar>(1,0)=4;A.at<uchar>(1,1)=5;A.at<uchar>(1,2)=6;B.at<uchar>(0,0)=1;B.at<uchar>(0,1)=2;B.at<uchar>(0,2)=3;B.at<uchar>(1,0)=4;B.at<uchar>(1,1)=5;B.at<uchar>(1,2)=6;double AB=A.dot(B);cout<<"A=\n"<<A<<endl<<endl;cout<<"B=\n"<<B<<endl<<endl;cout<<"double类型的AB=\n"<<AB<<endl<<endl;system("pause");
    }
  • 矩阵mul(元素乘法)
    Opencv中mul会计算两个Mat矩阵对应位的乘积,所以要求参与运算的矩阵A的行列和B的行列数一致。计算结果是跟A或B行列数一致的一个Mat矩阵。
        MatExpr mul(InputArray m, double scale=1) const;
    以简单的情况为例,对于2*2大小的Mat矩阵A和B:
  • 对A和B执行mul运算:

    mul说明:
    1).  mul操作不对参与运算的两个矩阵A、B有数据类型上的要求,但要求A,B类型一致,不然报错。

    2).  Mat AB=A.mul(B),若声明AB时没有定义AB的数据类型,则默认AB的数据类型跟A和B保存一致。

    3).  若AB精度不够,可能产生溢出,溢出的值被置为当前精度下的最大值。

    #include "core/core.hpp"     
    #include "iostream"  using namespace std;   
    using namespace cv;  int main(int argc,char *argv[])    
    { Mat A=Mat::ones(2,3,CV_8UC1);Mat B=Mat::ones(2,3,CV_8UC1);A.at<uchar>(0,0)=60;A.at<uchar>(0,1)=2;A.at<uchar>(0,2)=3;A.at<uchar>(1,0)=4;A.at<uchar>(1,1)=5;A.at<uchar>(1,2)=6;B.at<uchar>(0,0)=60;B.at<uchar>(0,1)=2;B.at<uchar>(0,2)=3;B.at<uchar>(1,0)=4;B.at<uchar>(1,1)=5;B.at<uchar>(1,2)=6;Mat AB=A.mul(B);cout<<"A=\n"<<A<<endl<<endl;cout<<"B=\n"<<B<<endl<<endl;cout<<"AB=\n"<<AB<<endl<<endl;system("pause");
    }
  • 矩阵转置
    矩阵转置是将矩阵的行与列顺序对调(第i行转变为第i列)形成一个新的矩阵。OpenCV通过Mat类的t()函数实现。
    / 转置Mat m1= Mat::eye(2,3, CV_32F);    Mat m1t = m1.t();cout<<"m1  = "<<endl<<m1<<endl<<endl;cout<<"m1t  = "<<endl<<m1t<<endl<<endl;
  • 矩阵求逆
    逆矩阵在某些算法中经常出现,在OpenCV中通过Mat类的inv()方法实现。
    // 求逆
    Mat meinv = me.inv();
    cout<<"me  = "<<endl<<me<<endl<<endl;
    cout<<"meinv = "<<endl<<meinv<<endl<<endl;

4. 矩阵扩展方法

  •  计算矩阵非零元素个数
    计算物体的像素或面积常需要用到计算矩阵中的非零元素个数,OpenCV中使用countNonZero()函数实现。
    // 非零元素个数
    int nonZerosNum = countNonZero(me); // me为输入矩阵或图像
    cout<<"me  = "<<endl<<me<<endl;
    cout<<"me中非零元素个数 = "<<nonZerosNum<<endl<<endl;
  • 归一化

    函数:
    void cv::normalize( InputArray src, OutputArray dst, double alpha = 1, double beta = 0, int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray() );
    
    参数:
    src (InputArray): 输入数组或图像,通常为单通道或多通道的矩阵(如 cv::Mat 类型)。这是需要被标准化的源数据。
    dst (OutputArray): 输出标准化后的数组或图像。大小和类型取决于输入和参数设置。
    alpha (double): 归一化后的最小值或缩放系数,具体含义取决于 norm_type。如果选择了 NORM_MINMAX,alpha 表示归一化后数据的最小值。如果是 NORM_L2、NORM_L1 或 NORM_INF,alpha 是缩放的目标值。
    beta (double): 归一化后的最大值,当 norm_type 为 NORM_MINMAX 时有效。这个参数只会在该类型下使用,以设置归一化后的最大值。
    norm_type (int): 归一化的类型。常见的有以下几种:
    NORM_INF: 将数组的每个元素除以绝对值的最大值。
    NORM_L1: 将数组的每个元素除以元素绝对值之和。
    NORM_L2: 将数组的每个元素除以元素平方和的平方根(欧几里得范数)。
    NORM_MINMAX: 线性缩放,使得数组的最小值和最大值分别为 alpha 和 beta。
    dtype (int): 输出数据类型。如果设置为 -1,则输出与输入类型相同。否则,可以显式指定输出类型(如 CV_32F、CV_8U 等)。
    mask (InputArray): 可选的掩码数组(通常是二值图像)。只对掩码中为非零的像素进行标准化处理。
    返回值:
    该函数没有返回值,但它会通过 dst 输出标准化后的结果。
    cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
    cv::Mat dst;// 将图像归一化到 [0, 255] 范围内
    cv::normalize(src, dst, 0, 255, cv::NORM_MINMAX);
  • 变形

    函数:
    C++: Mat Mat::reshape(int cn, int rows=0) const
    参数:

    cn: 表示通道数(channels), 如果设为0,则表示保持通道数不变,否则则变为设置的通道数。rows: 表示矩阵行数。 如果设为0,则表示保持原有的行数不变,否则则变为设置的行数。
     

    int main()
    {Mat data = Mat(20, 30, CV_32F);  //设置一个20行30列1通道的一个矩阵cout << "行数: " << data.rows << endl;cout << "列数: " << data.cols << endl;cout << "通道: " << data.channels() << endl;cout << endl;Mat dst = data.reshape(0, 1);//通道数不变,将矩阵序列化1行N列的行向量cout << "行数: " << dst.rows << endl;cout << "列数: " << dst.cols << endl;cout << "通道: " << dst.channels() << endl;system("pause");return 0;
    }
  • 计算两个矩阵之间的差异或误差
    函数:
    
    // 单数组范数
    double cv::norm(InputArray src, int normType = NORM_L2, InputArray mask = noArray());// 两数组差异范数
    double cv::norm(InputArray src1, InputArray src2, int normType = NORM_L2, InputArray mask = noArray());
    
    参数:
    src1和src2是输入的数组,可以是 cv::Mat 或 cv::Mat_<T> 类型的对象。它可以是一维或多维数组。
    normType 是一个可选参数,用于指定计算范数的类型。常见的取值为 NORM_L1、NORM_L2、NORM_INF,分别表示计算 L1 范数、L2 范数和无穷范数。默认值为 NORM_L2。
    对不同范数类型的解释:
    NORM_L1:计算 L1 范数,也称为曼哈顿范数。对于一维数组,它表示数组中所有元素的绝对值之和。对于多维数组,它表示所有元素绝对值之和的最大值。
    NORM_L2:计算 L2 范数,也称为欧几里得范数。对于一维数组,它表示数组中所有元素的平方和的平方根。对于多维数组,它表示所有元素平方和的平方根。
    NORM_INF:计算无穷范数,也称为最大绝对值范数。对于一维数组,它表示数组中绝对值最大的元素的绝对值。对于多维数组,它表示所有元素绝对值的最大值。
    mask 是一个可选的掩码数组,用于指定哪些元素应该包含在范数计算中。它必须与 src 的尺寸相同,且类型为 CV_8UC1 或 CV_8SC1。
  • 矩阵的全局最大最小值
    求输入矩阵的全局最大最小值及其位置,可使用函数:
    void minMaxLoc(InputArray src, CV_OUT double* minVal,CV_OUT double* maxVal=0, CV_OUT Point* minLoc=0,CV_OUT Point* maxLoc=0, InputArray mask=noArray());

    参数:
    src – 输入单通道矩阵(图像).
    minVal – 指向最小值的指针, 如果未指定则使用NULL
    maxVal – 指向最大值的指针, 如果未指定则使用NULL
    minLoc – 指向最小值位置(2维情况)的指针, 如果未指定则使用NULL
    maxLoc – 指向最大值位置(2维情况)的指针, 如果未指定则使用NULL
    mask – 可选的蒙版,用于选择待处理子区域

    // 求极值 最大、最小值及其位置Mat img = imread("Lena.jpg",0);imshow("original image",img);double minVal=0,maxVal=0;cv::Point minPt, maxPt;minMaxLoc(img,&minVal,&maxVal,&minPt,&maxPt);cout<<"min value  = "<<minVal<<endl;cout<<"max value  = "<<maxVal<<endl;cout<<"minPt = ("<<minPt.x<<","<<minPt.y<<")"<<endl;cout<<"maxPt = ("<<maxPt.x<<","<<maxPt.y<<")"<<endl;cout<<endl;cv::Rect rectMin(minPt.x-10,minPt.y-10,20,20);cv::Rect rectMax(maxPt.x-10,maxPt.y-10,20,20);cv::rectangle(img,rectMin,cv::Scalar(200),2);cv::rectangle(img,rectMax,cv::Scalar(255),2);imshow("image with min max location",img);cv::waitKey();

5. 矩阵切片与ROI

  • 获取子矩阵
    Mat roi = A(Rect(0,0,2,2));   // 左上角2x2区域
    Mat rows = A.rowRange(0,2);   // 前两行
  • 矩阵的ROI(感兴趣区域)
    在OpenCV中,矩阵的ROI(Region of Interest,感兴趣区域)指的是在原矩阵中指定的一块区域。你可以从这个区域中提取数据,或者在不影响原矩阵的情况下对这个区域进行操作。
    要设置ROI,你可以使用cv::Rect对象来定义感兴趣区域的坐标和大小,然后使用Mat::operator()来访问这个区域。

    // 定义ROI
    cv::Rect roi(x, y, width, height);  // x, y 是左上角的坐标,width 和 height 是区域的宽度和高度// 使用ROI
    cv::Mat submat = image(roi);

    一旦你有了ROI的引用(如submat),你就可以像操作普通矩阵一样操作它了。任何对submat的修改都不会影响原始的image矩阵,除非你明确地复制了这些修改。

    // 例如,将ROI区域内的所有像素值设置为0
    submat = cv::Scalar(0, 0, 0);  // 对于彩色图像,三个通道都需要设置为0

    如果你希望保留原始图像不变,同时又想在其他地方使用修改后的ROI,你可以将submat复制到一个新的矩阵。

    cv::Mat newImage = image.clone();  // 克隆原始图像以保留原始数据
    newImage(roi) = submat.clone();    // 将修改后的ROI复制到新图像的相应位置

6. Mat深拷贝

在OpenCV中,cv::Mat对象通常用于存储图像数据。当你创建一个cv::Mat对象并将其赋值给另一个cv::Mat对象时,默认情况下是浅拷贝(shallow copy),这意味着两个对象指向相同的内存地址。如果你修改了任一对象的内存内容,另一个对象的内存内容也会相应改变,这可能导致不可预期的行为或错误。
如何进行深拷贝?
方法1:使用cv::Mat::clone()
这是进行深拷贝的最直接方法。clone()方法会创建一个新的cv::Mat对象,并复制原始矩阵的数据到一个全新的内存区域。

cv::Mat original = cv::imread("path_to_image.jpg");
cv::Mat copy = original.clone();// 现在,original和copy指向不同的内存区域,修改它们不会相互影响。

方法2:使用cv::Mat::copyTo()
另一个方法是使用copyTo()方法,这也可以用来创建数据的深拷贝。

cv::Mat original = cv::imread("path_to_image.jpg");
cv::Mat copy;
original.copyTo(copy);// 现在,original和copy也是独立的,修改它们不会相互影响。

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

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

相关文章

【C++进阶】函数:深度解析 C++ 函数的 12 大进化特性

目录 一、函数基础 1.1 函数定义与声明 1.2 函数调用 1.3 引用参数 二、函数重载&#xff1a;同名函数的「多态魔法」&#xff08;C 特有&#xff09; 2.1 基础实现 2.2 重载决议流程图 2.3 与 C 语言的本质区别 2.4 实战陷阱 三、默认参数&#xff1a;接口的「弹性设…

spring boot 登入权限RBAC模式

首先准备好5张表 user_info表&#xff0c;用户的信息表 role表&#xff0c;角色表&#xff08;比如超级管理员、管理员、审核员、采购......&#xff09; 创建user_role表&#xff0c;user_info表&#xff0c;role表的中间表 注意了&#xff0c;role_id和user_id是 u…

C#里使用libxl来对列或行进行分组显示

有时候由于EXCEL里的行数很多, 需要把某些行进行隐藏起来,那么就需要使用到行或列进行隐藏的操作。 这时候需要使用函数GroupCols和GroupRows来对这些列或行进行分组。 分组不能出现交叉的情况,否则会抛出异常。 如下图所示: 可以使用下面的代码来输出上面的EXCEL: p…

LangChain 基础

一、LangChain 模块和体系 LangChain 是一个用于开发由大型语言模型&#xff08;LLMs&#xff09;驱动的应用程序的框架。 官方文档&#xff1a;https://python.langchain.com/docs/introduction/ LangChain 简化了LLM应用程序生命周期的每个阶段&#xff1a; 开发&#xf…

IDEA 快捷键ctrl+shift+f 无法全局搜索内容的问题及解决办法

本篇文章主要讲解IDEA、phpStrom、webStrom、pyCharm等jetbrains系列编辑器无法进行全局搜索内容问题的主要原因及解决办法。 日期&#xff1a;2025年3月22日 作者&#xff1a;任聪聪 现象描述&#xff1a; 1.按下ctrlshiftf 输入法转为了繁体。 2.快捷键ctrlshiftr 可以全局检…

2025年- G24-Lc98-217.包含重复(使用hashSet解决)-java版

1.题目描述 2.思路 思路一&#xff1a; 我的想法是直接用集合来判断&#xff0c;如果集合的元素不能添加说明之前已经存在这个元素&#xff0c;也就是发现了重复元素&#xff0c;所以返回false。 补充一&#xff1a; Map、ArrayList的定义和声明 3.代码实现 class Soluti…

MySQL事务全解析:从概念到实战

在数据库操作中&#xff0c;事务是一个至关重要的概念&#xff0c;它确保了数据的完整性和一致性。今天&#xff0c;就让我们深入探讨MySQL事务的方方面面&#xff0c;从基础概念到实际应用&#xff0c;全面掌握这一技能。 一、为什么需要事务 假设张三要给李四转账100元&…

CVPR 2025 | 文本和图像引导的高保真3D数字人高效生成GaussianIP

小小宣传一下CVPR 2025的工作GaussianIP。 arXiv&#xff1a;https://arxiv.org/abs/2503.11143 Github&#xff1a;https://github.com/silence-tang/GaussianIP 欢迎star, issue~ 摘要 文本引导的3D人体生成随着高效3D表示及2D升维方法&#xff08;如SDS&#xff09;的发展…

Model Context Protocol:下一代AI系统集成范式革命

在2023年全球AI工程化报告中,开发者面临的核心痛点排名前三的分别是:模型与业务系统集成复杂度(58%)、上下文管理碎片化(42%)、工具调用标准化缺失(37%)。传统API集成模式在对接大语言模型时暴露明显短板:RESTful接口无法承载动态上下文,GraphQL缺乏工具编排能力,gR…

多模态大模型常见问题

1.视觉编码器和 LLM 连接时&#xff0c;使用 BLIP2中 Q-Former那种复杂的 Adaptor 好还是 LLaVA中简单的 MLP 好&#xff0c;说说各自的优缺点&#xff1f; Q-Former&#xff08;BLIP2&#xff09;&#xff1a; 优点&#xff1a;Q-Former 通过查询机制有效融合了视觉和语言特征…

EasyRTC轻量级Webrtc音视频通话SDK,助力带屏IPC在嵌入式设备中的应用

一、市场背景 随着人们生活水平的提高&#xff0c;对于家居安全和远程监控的需求日益增长&#xff0c;带屏IPCam不仅满足了用户实时查看监控画面的需求&#xff0c;还提供了诸如双向语音通话、智能报警等丰富的功能&#xff0c;极大地提升了用户体验。 此外&#xff0c;技术的…

Linux安装JDK

1、下载JDK https://www.oracle.com/cn/java/technologies/downloads/#java11 2、安装 2.1、创建安装目录 mkdir /usr/local/jdk 2.1、将下载的tar.gz上传到服务器 使用tar -zxvf jdk-8u311-linux-x64.tar.gz解压后剪切到 /usr/local/jdk目录&#xff1a;mv xxx /usr/local/j…

基于基于eFish-SBC-RK3576工控板的智慧城市边缘网关

此方案充分挖掘eFish-SBC-RK3576的硬件潜力&#xff0c;可快速复制到智慧园区、交通枢纽等场景。 方案亮点 ‌接口高密度‌&#xff1a;单板集成5GWiFi多路工业接口&#xff0c;减少扩展复杂度。‌AIoT融合‌&#xff1a;边缘端完成传感器数据聚合与AI推理&#xff0c;降低云端…

CSS 学习笔记 - 蓝桥杯重点整理

1. CSS 基础语法 核心知识点 选择器 声明块结构三种引入方式&#xff1a;行内/内部/外部常用选择器类型&#xff1a;标签/类/ID/通配符 <!-- 行内样式 --> <p style"color: red;">红色文字</p><!-- 内部样式 --> <style>/* 标签选…

UML的使用

process on 在线使用 UML概念 UML &#xff1a;统一建模语言(Unified Modeling Language&#xff0c;是用来设计软件的可视化建模语言。 1. 类图 1.1 概念 类图&#xff08;Class Diagram&#xff09;是UML中用于描述系统静态结构的图形化工具。它展示了系统的类、接口、它…

【C++】入门

1.命名空间 1.1 namespace的价值 在C/C中&#xff0c;变量&#xff0c;函数和后面要学到的类都是大量存在的&#xff0c;这些变量&#xff0c;函数和类的名称将存在于全局作用域中&#xff0c;可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化&#xff0c;…

数据库练习2

目录 1.向heros表中新增一列信息&#xff0c;添加一些约束&#xff0c;并尝试查询一些信息 2.课堂代码练习 插入语句 INSERT INTO 删除语句DELETE和TRUNCATE 更新语句UPDATE和replace 查询语句SELECT 条件查询 查询排序 聚合函数 分组查询 3.题目如下 一、单表查询 …

w266农产品直卖平台的设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

2025新版懒人精灵零基础安装调试+lua基础+UI设计交互+常用方法封装+项目实战+项目打包安装板块-视频教程(初学者必修课)

2025新版懒人精灵零基础安装调试lua基础UI设计交互常用方法封装项目实战项目打包安装板块-视频教程(初学者必修课)&#xff1a; 1.懒人精灵核心API基础和lua基础视频教程&#xff1a;https://www.bilibili.com/video/BV1Vm9kYJEfM/ 温馨提示&#xff1a;所有视频请用电脑浏览…

CCF-CSP认证 202206-2寻宝!大冒险!

题目描述 思路 有一张绿化图和藏宝图&#xff0c;其中绿化图很大&#xff08;二维数组在限定的空间内无法存储&#xff09;&#xff0c;而藏宝图是绿化图中的一部分&#xff0c;对于绿化图和藏宝图&#xff0c;左下角的坐标为(0, 0)&#xff0c;右上角的坐标是(L, L)、(S, S)&…