Opencv IplImage 和 Mat 使用介绍

news2024/11/18 9:47:42

1. IPIImage 使用介绍

IplImage是OpenCV中CxCore部分基础的数据结构,用来表示图像,其中Ipl是Intel Image Processing Library的简写。以下是IplImage的结构分析。参见:OpenCV中文网站

typedef struct _IplImage
    {
        int  nSize;         /* IplImage大小 */
        int  ID;            /* 版本 (=0)*/
        int  nChannels;     /* 大多数OPENCV函数支持1,2,3 或 4 个通道 */
        int  alphaChannel;  /* 被OpenCV忽略 */
        int  depth;         /* 像素的位深度: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,
                               IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F 可支持 */
        char colorModel[4]; /* 被OpenCV忽略 */
        char channelSeq[4]; /* 同上 */
        int  dataOrder;     /* 0 - 交叉存取颜色通道, 1 - 分开的颜色通道.
                               cvCreateImage只能创建交叉存取图像 */
        int  origin;        /* 0 - 顶—左结构,
                               1 - 底—左结构 (Windows bitmaps 风格) */
        int  align;         /* 图像行排列 (4 or 8). OpenCV 忽略它,使用 widthStep 代替 */
        int  width;         /* 图像宽像素数 */
        int  height;        /* 图像高像素数*/
        struct _IplROI *roi;/* 图像感兴趣区域. 当该值非空只对该区域进行处理 */
        struct _IplImage *maskROI; /* 在 OpenCV中必须置NULL */
        void  *imageId;     /* 同上*/
        struct _IplTileInfo *tileInfo; /*同上*/
        int  imageSize;     /* 图像数据大小(在交叉存取格式下imageSize=image->height*image->widthStep),单位字节*/
        char *imageData;  /* 指向排列的图像数据 */
        int  widthStep;   /* 排列的图像行大小,以字节为单位 */
        int  BorderMode[4]; /* 边际结束模式, 被OpenCV忽略 */
        int  BorderConst[4]; /* 同上 */
        char *imageDataOrigin; /* 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的 */
    }
    IplImage;

1. 1 元素访问

对我们来说比较重要的两个元素是:char *imageData以及widthStep。imageData存放图像像素数据,而widStep类似CvMat中的step,表示以字节为单位的行数据长度

一个m*n的单通道字节型图像,其imageData排列如下:
在这里插入图片描述
如果我们要遍历图像中的元素,只需:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
uchar* tmp;
for(int i=0;i<img->height;i++)
	for(int j=0;j<img->width;j++)
		*tmp=((uchar *)(img->imageData + i*img->widthStep))[j];

这种直接访问的方法速度快,但容易出错,我们可以通过定义指针来访问。即:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
ucha* data=(uchar *)img->imageData;
int step = img->widthStep/sizeof(uchar);
uchar* tmp;
for(int i=0;i<img->height;i++)
	for(int j=0;j<img->width;j++)
		*tmp=data[i*step+j];

而多通道(三通道)字节图像中,imageData排列如下:
在这里插入图片描述

//IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
uchar* data=(uchar *)img->imageData;
int step = img->widthStep/sizeof(uchar);
int channels = img->nChannels;
uchar *b,*g,*r;
for(int i=0;i<img->height;i++)
     for(int j=0;j<img->width;j++){
           *b=data[i*step+j*chanels+0];
           *g=data[i*step+j*chanels+1];
           *r=data[i*step+j*chanels+2];
      }

如果要修改某像素值,则直接赋值。

1.2 使用cvGet2D()函数访问:

cvGet*D系列函数可以用来返回特定位置的数组元素(一般使用cvGet2D),原型如下:

CvScalar cvGet1D( const CvArr* arr, int idx0 );
CvScalar cvGet2D( const CvArr* arr, int idx0, int idx1 );
CvScalar cvGet3D( const CvArr* arr, int idx0, int idx1, int idx2 );
CvScalar cvGetND( const CvArr* arr, int* idx );

idx0,idx1,idx2分别用来指示元素数组下标,即cvGet2D返回(idx0,idx1)处元素的值。因此,单通道图像像素访问方式如下:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
double tmp;
for(int i=0;i<img->height;i++)
	for(int j=0;j<img->width;j++)
		tmp=cvGet2D(img,i,j).val[0];

多通道字节型/浮点型图像:

IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
double tmpb,tmpg,bmpr;
for(int i=0;i<img->height;i++)
	for(int j=0;j<img->width;j++){
		tmpb=cvGet2D(img,i,j).val[0];
		tmpg=cvGet2D(img,i,j).val[1];
		tmpr=cvGet2D(img,i,j).val[2];
	}

如果是修改元素的值,可用cvSet*D(一般是cvSet2D)函数:

void cvSet1D( CvArr* arr, int idx0, CvScalar value );
void cvSet2D( CvArr* arr, int idx0, int idx1, CvScalar value );
void cvSet3D( CvArr* arr, int idx0, int idx1, int idx2, CvScalar value );
void cvSetND( CvArr* arr, int* idx, CvScalar value );

这种方法对于任何图像的访问方式是一样的,比较简单,但效率较低,不推荐使用。

2. Mat 使用介绍

2.1 Mat的介绍

Mat其实就是matrix(矩阵)的缩写,在opencv中,我们用Mat类的对象存储图像。
在opencv中,Mat类分为两个部分。

  • header部分

图像有很多属性。如:大小,宽和高,数据类型,通道数。这些数据存储在矩阵头中

  • data部分:放置像素点实际值

Mat和Matlab里的数组格式有点像,但一般是二维向量,如果是灰度图,一般存放 <uchar>类型;如果是RGB彩色图,存放 <Vec3b>类型。

单通道灰度图数据存放格式
在这里插入图片描述
多通道的图像中,每列并列存放通道数量的子列,如RGB三通道彩色图:
在这里插入图片描述
注意通道的顺序反转了:BGR。通常情况内存足够大的话图像的每一行是连续存放的,也就是在内存上图像的所有数据存放成一行,这中情况在访问时可以提供很大方便。可以用 isContinuous()函数来判断图像数组是否为连续的。

2.2 Mat的常见属性及类型

Mat的常见属性

在这里插入图片描述
属性部分存储了一系列的矩阵属性:行数、列数、通道数、数据类型、矩阵数据的大小等,以及指向了矩阵数据的指针等。

  • cols :矩阵列数
  • rows:矩阵行数
  • channels:通道数
  • type:数据类型
  • total:矩阵总元素数
  • data:指向矩阵数据块的指针

Mat 数据类型type

表示了矩阵中元素的类型以及矩阵的通道个数,它是一系列的预定义的变量,其命名规则为CV_(位数)+(数据类型)+(通道数)。具体的有以下值:
在这里插入图片描述
这里U(unsigned integer)表示的是无符号整数,S(signed integer),F(float)是浮点数。

例如:CV_16UC2: 表示的是元素类型是一个16位的无符号整数,通道为2. C1,C2,C3,C4则表示通道是1,2,3,4

type一般是在创建Mat对象时设定,如果要取得Mat的元素类型,则无需使用type,使用下面的depth

depth

矩阵中元素的一个通道的数据类型,这个值和type是相关的。例如 type为 CV_16SC2,一个2通道的16位的有符号整数。那么,depth则是CV_16S。depth也是一系列的预定义值:

将type的预定义值去掉通道信息就是depth值:CV_8U CV_8S CV_16U CV_16S CV_32S CV_32F CV_64F

elemSize

矩阵一个元素占用的字节数,例如:type是CV_16SC3,那么elemSize = 3 * 16 / 8 = 6 bytes

elemSize1

矩阵元素一个通道占用的字节数,例如:type是CV_16CS3,那么elemSize1 = 16 / 8 = 2 bytes = elemSize / channels

2.3 Mat的操作

2.3.1 Mat的创建

>  1. Mat ()
>  2. Mat (int rows, int cols, int type)
>  3. Mat (Size size, int type)
>  4. Mat (int rows, int cols, int type, const Scalar &s)
>  5. Mat (Size size, int type, const Scalar &s)
>  6. Mat (int ndims, const int *sizes, int type) 
>  7. Mat (int ndims, const int *sizes, int type, const Scalar &s)
    1. 使用无参数构造函数,创建Mat对象
Mat image = Mat();
image.create(4, 4, CV_8UC3);//创建一个4x4大小的像素块,每个像素都是三通道每个通道的位数都是8位
    1. 使用带行、列、类型这个三个参数的构造函数创建Mat对象
Mat m = Mat(4, 4, CV_8UC3); //创建一个4x4大小的像素块,每个像素都是三通道每个通道的位数都是8位
  • 3.使用行、列、类型、Scalar向量四个参数的构造函数创建Mat对象
Mat m = Mat(4, 4, CV_8UC3, Scalar(0, 255, 255)); 
//创建一个4x4大小的像素块,每个像素都是三通道每个通道的位数都是8位,指定三通道颜色值向量Scalar(0, 255, 255)

同样表示创建一个4x4的像素块,唯一的区别是颜色不是默认值,而是我们指定的三通道颜色值向量Scalar(0, 255, 255)。其中Scalar向量数目永远是等于通道数目。其他赋值情况也一样

  • 4.使用大小、类型个参数的构造函数创建Mat对象。
Mat m = Mat(Size(4, 4), CV_8UC3); //创建一个4x4大小的像素块,每个像素都是三通道每个通道的位数都是8位
  • 5.使用大小、类型、Scalar向量三个参数的构造函数创建Mat对象
Mat m = Mat(Size(4, 4), CV_8UC3, Scalar(255, 0, 0)); //创建一个4x4大小的像素块,每个像素都是三通道每个通道的位数都是8位
    1. 使用zeros(),eye(), ones()创建对象
Mat img = zeros(100,100,CV_8UC3); // 全0矩阵
Mat img1 = eye(100,100,CV_8UC3); // 对角为1的对角矩阵
Mat img2 = ones(100,100,CV_8UC3); // 全1矩阵
    1. 使用逗号数组创建对象
Mat img = (Mat_<double>(2,2) << 0,1,1,0); // 按行填充
Mat A = (Mat_<double>(4, 4) <<
		0.5, 0.4, 0.6, 1,
		0.2, 0.3, 0.1, 2,
		0.7, 0.8, 0.9, 3,
		0, 0, 0, 1);

Mat对象创建,常用的是创建空白图像。如下演示了三种

Mat src = imread("……");
Mat m4 = Mat::zeros(src.size(),src.type())

Mat m5 = Mat::zeros(Size(512,512),CV_8UC3);

Mat m6 = Mat::ones(Size(512,512),CV_8UC3);

Mat kernel = (Mat_<char>(3,3)<<0,-1,0,-1,5,-1,0,-1,0); 位数,只有灰度

当对图像直接赋值,如果为多通道时:

Mat m3 = Mat::zeros(Size(8, 8), CV_8UC3);
m3 = 145;

结果如下:
在这里插入图片描述
只有第一个通道的值被赋值了

正确的写法如下:

Mat m3 = Mat::zeros(Size(8, 8), CV_8UC3);
m3 = Scalar(129,39,0);

在这里插入图片描述

2.3.2 像素读写

uchar:灰度图像像素,单个值
Vec3b:彩色图像像素,3个值

单个像素的访问:pixel = image.at<uchar>(row, col);

c++中像素遍历和读写:

    1. 数组遍历
void pixel_visit_Demo(Mat& image) {
	int h = image.rows;
	int w = image.cols;
	int dims = image.channels();
	for (int row = 0; row < h; row++) {
		for (int col = 0; col < w; col++) {
			if (dims == 1) {//灰度图像
				int pv = image.at<uchar>(row, col);
				image.at<uchar>(row, col) = 255 - pv;
			}
			if (dims == 3) {//彩色图像
				Vec3b bgr = image.at<Vec3b>(row, col);
				image.at<Vec3b>(row, col)[0] = 255 - bgr[0];
				image.at<Vec3b>(row, col)[1] = 255 - bgr[1];
				image.at<Vec3b>(row, col)[2] = 255 - bgr[2];
			}
		}
	}
}
    1. 指针方式遍历(比for快一点)
void pixel_visit_Demo(Mat& image) {
	int h = image.rows;
	int w = image.cols;
	int dims = image.channels();
	for (int row = 0; row < h; row++) {
		uchar* curren_row = image.ptr<uchar>(row);
		for (int col = 0; col < w; col++) {
			if (dims == 1) {//灰度图像
				int pv = *curren_row;
				*curren_row++ = 255 - pv;
			}
			if (dims == 3) {//彩色图像
				*curren_row++ = 255 - *curren_row;  // b
				*curren_row++ = 255 - *curren_row;  // g
				*curren_row++ = 255 - *curren_row;  / r
			}
		}
	}
}

对于彩色图,对单个的像素点后移通道数量次数即可,如上++了三次。

2.3.3 图像的拷贝

再开始将拷贝之前,先给大家分享一下浅拷贝和深拷贝

浅拷贝:拷贝对象和被拷贝对象都指向同一个内存空间,修改任何一个对象的数据都会影响另外一个;
举个例子:小明和小红在沙漠中共用一个水瓶喝水,任何一个人喝了水,另外一个人都会剩下更少的水。

深拷贝:拷贝对象和被拷贝对象指向不同的内容空间,修改数据时互不影响。
举个例子:小明和小红各有一个水瓶,各自喝各自的水对对方不影响。

深拷贝和浅拷贝都各有优缺点:
在这里插入图片描述

  • 1 拷贝构造函数进行拷贝

这种拷贝方式属于浅拷贝,下面代码中的img和img2都指向相同的内存空间,修改img或者img2,另外一个中的变量也会跟着变化。

Mat img = imread("test.jpg", CV_LOAD_IMAGE_COLOR);
Mat img2(img); // 拷贝构造函数

2 赋值运算符进行拷贝
这种拷贝方式属于浅拷贝,下面代码中的img和img2都指向相同的内存空间,修改img或者img2,另外一个中的变量也会跟着变化。

Mat img = imread("test.jpg", CV_LOAD_IMAGE_COLOR);
Mat img2 = img; // 赋值运算符

3 使用Rect截取拷贝
这种拷贝方式属于浅拷贝,下面代码中的img2指向的内存空间为img的子内存空间。

Mat img = imread("test.jpg", CV_LOAD_IMAGE_COLOR);
Mat img2(img, Rect(200,200,300,300));

4 使用clone()函数拷贝
这种拷贝方式属于深拷贝,img和img2分别指向不同的内存空间,修改img或img2 的数据,不影响另一个变量。

Mat img = imread("test.jpg", CV_LOAD_IMAGE_COLOR);
Mat img2 = img.clone();

5 使用copyTo()函数拷贝
这种拷贝方式属于深拷贝,img和img2分别指向不同的内存空间,修改img或img2 的数据,不影响另一个变量。

Mat img = imread("test.jpg", CV_LOAD_IMAGE_COLOR);
Mat img2;
img.copyTo(img2);

2.4 Mat 矩阵运算

    Mat imageadd = image1 + image2;
	//imshow("加法", imageadd);

	Mat imageadd1;
	Mat imageadd2;
	add(image1, image2, imageadd1);
	add(image1, 2, imageadd2);//函数重载
	//imshow("加法", imageadd);

	Mat imagesub = image1 - image2;//运算符重载
	//imshow("减法", imagesub);

	Mat imageAbsdiff;
	absdiff(image1, image2, imageAbsdiff);
	//imshow("减法绝对值", imageAbsdiff);

	Mat imagesub1;
	subtract(image1, image2, imagesub1);
	//imshow("减法", imagesub);

	Mat imageweighted;
	addWeighted(image1, 0.5, image2, 0.2, 50, imageweighted);
	//imshow("加权", imageweighted);

	Mat imagemultiply;
	multiply(image1, image2, imagemultiply, 1.0, CV_32FC1);
	//imshow("点乘", imagemultiply);

	Mat imagedivide;
	divide(image1, image2, imagedivide, 1.0, -1);
	//imshow("点除", imagedivide);

	//非
	Mat image2not;
	Mat mask = Mat::zeros(image2.size(), CV_8UC1);

	mask(Rect(200, 100, 200, 200)) = 255;

	bitwise_not(image2, image2not, mask);
	//imshow("非", image2not);

	//或
	Mat image2or;
	bitwise_or(image2, imagesub, image2or, mask);
	//imshow("或", image2or);
	
    //异或
	Mat image2xor;
	bitwise_xor(image2, imageadd2, image2xor, mask);
	imshow("异或", image2xor);

	//与
	Mat image2and;
	bitwise_and(image2, imagesub, image2and, mask);
	//imshow("与", image2and);

2.5 Mat 转换

2.5.1 Mat与二维指针相互转换

对于一个Mat,有时需要将其转为二维指针传递

int** mat2ptrarray(Mat& pic)
{
    int** data;
    data = new int* [pic.rows];
    for (int i = 0; i < pic.rows; i++)
    {
        data[i] = new int[pic.cols];
        for (int j = 0; j < pic.cols; j++)
        {
            data[i][j] = pic.at<int>(i, j);
        }
    }
    return data;
}

释放指针指向的内存空间

for (int i = 0; i < pic.rows; i++)
 {
     delete[] data[i];
 }
 delete[] data;

将二维指针的数据再拼回到Mat中(这个是按单通道的例子)

Mat ImgData(int** pImgdata, int width, int height)
{
    Mat Img;
    Img.create(height, width, CV_8U);//这里按照uchar类型
 
    for (int i = 0; i < height; i++)   //行数--高度
    {
        for (int j = 0; j < width; j++)        //列数 -- 宽度
        {
            Img.at<uchar>(i, j) = pImgdata[i][j];
        }
    }
    return Img;
}

2.5.2 Mat与一维数组相互转换

    //---------------------数组和Mat------------------------
	int height = image.rows;
	int width = image.cols;

	//转16位一维数组
	uint8_t* array1 = new uint8_t[height * width * 3];
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			for (int k = 0; k < 3; k++)
			{
				array1[i * width * 3 + j * 3 + k] = image.at<cv::Vec3b>(i, j)[k];
			}		
		}
	}

	Mat image3(height, width, CV_8UC3, array1);

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

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

相关文章

70页幻灯片图解“工信领域数据安全管理办法”等五部委数据法规

国家安全是民族复兴的根基。党的二十大报告指出&#xff0c;“加快建设制造强国、质量强国、航天强国、交通强国、网络强国、数字中国”、“推进国家安全体系和能力现代化”、“强化经济、重大基础设施、金融、网络、数据、生物、资源、核、太空、海洋等安全保障体系建设”。数…

02-redis篇 redis事务处理及使用方式

目录 1. 事务简介: -> 1.1 必须满足: ACID四个特性(原子性,一致性,隔离性,持久性) -> 1.2 简单理解: 一个业务,也可以看成是一个逻辑工作单元; 2. redis 操作事务的基本指令 -> 指令: -> 图式: 3. 模拟多事务操作(watch乐观锁) 3.1 不开启乐观锁watch操作…

Linux Python安装

1.到官网下载适合自己的版本 Python Source Releases | Python.orgThe official home of the Python Programming Languagehttps://www.python.org/downloads/source/2.下载好压缩包之后&#xff0c;将压缩包解压开 3.将开发环境的依赖包准备好 yum -y install zlib-devel bz…

阅读笔记 MulDA: DAGA向多语言方向的拓展

阅读笔记 MulDA: DAGA向多语言方向的拓展 文章目录阅读笔记 MulDA: DAGA向多语言方向的拓展前言概述IntroductionMulDA: Our Multilingual Data Augmentation Framework1、Labeled Sequence Translation2、Synthetic Data Generation with Language Models3、Semi-supervised M…

Tableau可视化设计案例-05Tableau进阶

文章目录Tableau可视化设计案例05Tableau进阶1.数据集合并1.1 数据导入界面1.2超市销售情况符号地图1.3智能显示1.4 仪表盘高级应用Tableau可视化设计案例 本文是Tableau的案例&#xff0c;为B站视频的笔记&#xff0c;B站视频 参考&#xff1a;https://www.bilibili.com/vide…

怎么使用CAM350检查Gerber?

文章目录什么是Gerber文件&#xff1f;Gerber中的文件由那些组成&#xff1f;怎么使用CAM350检查Gerber&#xff1f; ——导入CAM350的基础操作&#xff1a;对层的操作什么是Gerber文件&#xff1f; Gerber文件是设计完后PCB(brd文件)板文件后交给板厂制造成品的文件。Gerber一…

代码随想录刷题记录 day50 每日温度+下一个更大元素 I

代码随想录刷题记录 day50 每日温度下一个更大元素 I 739. 每日温度 思想 1.暴力解 两次for 超时了 2.单调栈 花了点时间理解的。 单调栈的基础入门题。找到一个数组中右边的第一个大于 等于 或者小于当前元素的下标的位置 以时间换空间&#xff0c;用一个栈来记录右边第…

明道云联合RestCloud打造APaaS+IPaaS融合解决方案

背景介绍 APaaSIPaaS发展趋势 随着企业规模的扩张以及业务需求变化越来越快&#xff0c;企业现有IT系统无法快速应对前端敏捷化的需求。企业IT架构将朝着敏捷化、低代码化、服务化方向发展&#xff0c;而APaaSIPaaS解决方案在这种需求下应运而生&#xff0c;IPaaS可以把现有固…

ARAS plm安装,各种踩坑

目录准备工作sql server安装NET Framework安装许可申请IIS服务开启IIS无法启动报错 HTTP 错误 500.19 - Internal Server Error错误变为 aras Error: Cannot access OAuth Server due to 500 (Internal Server Error)**Aras安装准备工作 sql server安装 登录出现的几个错误 s…

Python数据分析挖掘案例:Python爬虫助力疫情数据追踪

通过学习Python数据分析挖掘案例&#xff0c;可以掌握通过Python爬虫获取的数据进行处理以及可视化分析的主要方法和技能&#xff0c;并为后续相关课程学习及将来从事数据分析工作奠定基础。 新冠病毒疫情在武汉突然爆发&#xff0c;确诊病例、疑似病例、死亡病例等数据牵动着每…

Binary number

A binary number is a number expressed in the base-2 numeral system or binary numeral system, a method of mathematical expression which uses only two symbols: typically “0” (zero) and “1” (one). The base-2 numeral system is a positional notation with a…

5G FWA市场一跃而上,四信多款5G终端赋能FWA典型应用

随着国家政策相继出台&#xff0c;全球5G基础设施建设日益完善&#xff0c;带动千行百业的巨大变革。以工业互联网、远程医疗、车联网、消费级硬件等为例的应用场景均在5G加持下实现跨越式升级。与此同时&#xff0c;5G FWA作为弥合光纤欠发达地区数字鸿沟挑战的“杀手级应用”…

【kafka】学习笔记(一)

学习笔记一、概述1.1、MQ1.2、kafka1.3、消息队列的两种模式1.3.1、点对点1.3.2、订阅与发布1.4、Kafka基础架构二、安装2.1、 集群规划2.2、 下载安装2.3、 集群启动脚本三、Kafka命令行操作3.1、主题命令行操作3.2、生产者命令行操作3.3、消费者命令行操作四、 Kafka 生产者4…

常用的Linux命令介绍

ls&#xff1a; 如何区分一个文件类型是 文件夹 还是 普通文件&#xff1a; “-” 类型 表示是 普通文件 “d” 类型 表示是 文件夹 cd&#xff1a; cd -返回进入此目录前所在的目录 cd ~如果是root用户&#xff0c;相当于 cd /root&#xff1b;如果是普通用户&#xff0c;相…

7、操作系统之间的文件传输

Windows 与 Linux 在Windows与Linux中传输文件的常用方式有两种&#xff0c;一种是使用使用XFTP工具&#xff0c;另一种是使用rz sz 命令的方式进行 lrzsz 安装 yum install lrzsz -y 1&#xff09;rz 将文件从window上传到Linux 2&#xff09;sz 将文件从linux传输到window …

常用排序算法哪个效率更高之从理论到实践

前面整理了一篇关于排序算法的基础类库&#xff1a;基本排序算法类SortHelper 这里我们来看看这几个算法哪个效率更高一点呢&#xff1f; 1、先从理论来看看这几个算法 1、冒泡排序法 基本思想&#xff1a;两两比较待排序数据元素的大小&#xff0c;发现两个数据元素的次序…

RSA和AES的使用

文章目录为什么要对数据传输加密对称加密和非对称加密密钥的几种格式非对称加密算法----RSA算法产生公私密钥对对称加解密算法AES为什么要结合使用这两种算法利用RSA来加密传输AES的密钥&#xff0c;用AES来加密数据&#xff0c;思路如下&#xff1a;特点分析&#xff1a;参考链…

【探索Spring底层】14.谈谈参数解析器

文章目录1. 参数解析器概述2. 常见参数的解析1. 参数解析器概述 参数解析器是Spring-Web包提供的组件&#xff0c;并且SpringMVC中提供了很多参数解析器。 常见的参数解析器如下 org.springframework.web.method.annotation.RequestParamMethodArgumentResolverabbc908org.s…

部署并启动项目在linux(CentOS7)上,一名合格的程序猿不能不会(ಥ_ಥ)

各位小伙伴大家好呀哈哈哈~ 遇到问题不要慌─≡Σ(((つ•̀ω•́)つ让我先发个朋友圈~( • ̀ω•́ )✧ 我们知道项目的正常运行是需要先部署在服务器上&#xff0c;然后才能正常使用&#xff0c;我们一般都是在idea下写好然后直接部署在tomcat上或者其他服务器&#xff0c;但…

多维表需求管理表自动生成TAPD需求

【实现效果&#xff1a;】业务同学使用多维表管理客户需求&#xff0c;和产品团队经过评审之后&#xff0c;一键把多维表里对应的需求生成TAPD需求/缺陷单 【准备工作】 准备一个多维表&#xff0c;比如维格表、金山轻维表等 可以参考这两个模版&#xff1a; 金山轻维表&am…