C++OpenCV(2):图像处理基础概念与操作

🔆 文章首发于我的个人博客:欢迎大佬们来逛逛
🔆 OpenCV项目地址及源代码:点击这里

文章目录

  • 图形读取与显示
    • 加载图片
    • 显示图片
    • 打印图片信息
    • 保存图片
  • 色彩模型转换
    • RGB颜色模型
    • HSV颜色模型
    • HLS模型
    • LAB模型
  • 图像像素读写操作
  • 像素算数运算
  • 图形文字绘制
    • 绘制线
    • 绘制圆
    • 绘制矩形
    • 绘制椭圆
    • 绘制文字
    • 其他绘制函数

图形读取与显示

通过 imread 我们可以读取一个图片

其形式如下:

void imshow(const String& winname, InputArray mat);

而我们需要传递一个InputArray类型的参数,实际上就是 cv::Mat

如果创建cv::Mat呢?

可以通过它的很多的构造函数

先来了解一下图片的颜色通道

  • 颜色通道
    • RGB 图像有4 个默认通道:红色、绿色和蓝色各有一个通道,以及一个用于编辑图像复合通道(主通道)
  • 彩色深度
    • 8位色,每个像素所能显示的彩色数为2的8次方,即256种颜色。
    • 16位增强色,16位彩色,每个像素所能显示的彩色数为2的16次方,即65536种颜色。
    • 24位真彩色,每个像素所能显示的彩色数为24位,即2的24次方,约1680万种颜色。
    • 32位真彩色,即在24位真彩色图像的基础上再增加一个表示图像透明度信息的Alpha通道。
      • Alpha通道:一张图片的透明和半透明度

我们使用如下的形式来描述它的通道类型:

CV_<bit_depth>(S|U|F)C<number_of_channels>

其中:

  • bit_depth:位数,就是我们上面讲的彩色深度
  • S|U|F:即 signed ,unsigned int,float 来存储
  • number_of_channels:通道,有单通道,双通道,三通道,和四通道等等

加载图片

Mat类型的结构如下:

class  Mat
{public/*flag: 1.数字签名 2.维度3.通道数4.连续性*/int flags;					int dims; 					//数据维数int rows,cols; 				//数据行列uchar *data;				//存储的数据		const uchar* datastart;		//数据开始const uchar* dataend;		//数据结束const uchar* datalimit;		//数据边界//其他成员  //.....//其他方法//.....public: 		//构造方式// 默认构造函数 Mat A;Mat ()// 常用构造函数 Mat A(10,10,CV_8UC3);Mat (int rows, int cols, int type)//Mat A(300, 400, CV_8UC3,Scalar(255,255,255));Mat (int ndims, const int *sizes, int type, const Scalar &s)Mat (Size size, int type)Mat (int rows, int cols, int type, const Scalar &s)Mat (Size size, int type, const Scalar &s)Mat (int ndims, const int *sizes, int type)Mat (const Mat &m)Mat (int rows, int cols, int type, void *data, size_t step=AUTO_STEP)Mat (Size size, int type, void *data, size_t step=AUTO_STEP)Mat (int ndims, const int *sizes, int type, void *data, const size_t *steps=0)Mat (const Mat &m, const Range &rowRange, const Range &colRange=Range::all())//Mat D (A, Rect(10, 10, 100, 100) );Mat (const Mat &m, const Rect &roi)Mat (const Mat &m, const Range *ranges)};

我们使用如下的几种方式来加载图片:

  • CV_8UC1:单通道
  • Scalar:使用BGR形式
  • clone/copyTo:从另一个Mat拷贝
void testShow() {cv::Mat	m1(200, 200, CV_8UC1);cv::imshow("1", m1);//std::cout << m << '\n';cv::Mat m2(200, 200, CV_8UC3, cv::Scalar(255, 0, 255));cv::imshow("2", m2);cv::Mat m3 = m2.clone();cv::imshow("3", m3);cv::Mat m4;m3.copyTo(m4);	cv::imshow("4", m4);//imreadcv::Mat m5 = cv::imread("images/mm.png", cv::ImreadModes::IMREAD_GRAYSCALE);cv::imshow("5", m5);
}

显示图片

我们使用函数:imshow

我们已经直到了它的第二个参数是一个类型,用来表示以何种形式显示图片:**cv::ImreadModes**

Mat imread( const String& filename, int flags = IMREAD_COLOR );
/****************************************************************
*				filename: 文件路径
*				flags   : 显示方式
*****************************************************************/
enum ImreadModes {IMREAD_UNCHANGED            = -1,	//按原样返回加载的图像(带有alpha通道,否则会被裁剪)IMREAD_GRAYSCALE            = 0, 	//单通道灰度图像IMREAD_COLOR                = 1, 	//3通道BGR彩色图像 IMREAD_ANYDEPTH             = 2, 	//16位/32位图像,其他则转换为8位IMREAD_ANYCOLOR             = 4, 	//图像以任何可能的颜色格式读取IMREAD_LOAD_GDAL            = 8, 	//gdal驱动程序加载映像IMREAD_REDUCED_GRAYSCALE_2  = 16,	//单通道灰度图像,并将图像大小减小1/2 IMREAD_REDUCED_COLOR_2      = 17,	//3通道BGR彩色图像,使图像大小减小1/2IMREAD_REDUCED_GRAYSCALE_4  = 32,	//单通道灰度图像,并将图像尺寸减小1/4IMREAD_REDUCED_COLOR_4      = 33,	//3通道BGR彩色图像,使图像大小减小1/4IMREAD_REDUCED_GRAYSCALE_8  = 64,	//单通道灰度图像,并将图像尺寸减小1/8IMREAD_REDUCED_COLOR_8      = 65,	//3通道BGR彩色图像,使图像大小减小1/8IMREAD_IGNORE_ORIENTATION   = 128	//不要根据EXIF的方向标志旋转图像
};

打印图片信息

我们可以打印Mat的信息,因为它实际上就是一个矩阵,我们可以采用多种形式来格式化输出

  • C语言形式
  • numpy形式
  • python形式

….

void testPrint() {cv::Mat m(10, 10, CV_8UC1);std::cout << "Mat: \n"<<m << '\n';//格式化std::cout << "C: \n" << cv::format(m, cv::Formatter::FMT_C);std::cout << "numpy: \n" << cv::format(m, cv::Formatter::FMT_NUMPY);
}

保存图片

使用函数: imwrite

第一个参数为保存的图片的路径,第二个参数为保存的图片。

其中路径我们可以使用 cv::String 来传递,就是个字符串。

void testSaveFile(cv::String filename) {auto m = cv::imread("./images/dog.png" ,cv::ImreadModes::IMREAD_GRAYSCALE);	cv::imshow("dog", m);cv::imwrite(filename, m);
}

色彩模型转换

什么是色彩模型?

颜色模型指的是某个三维颜色空间中的一个可见光子集,它包含某个色彩域的所有色彩。一般而言,任何一个色彩域都只是可见光的子集,任何一个颜色模型都无法包含所有的可见光(通俗一点讲就是表示颜色的一种方式

RGB颜色模型

在计算机体系中,最常见的色彩模型就是**RGB颜色**模型。

它具有三维坐标的模型形式:

在这里插入图片描述


  • RGB16:每个像素用16个比特位表示,占2个字节
    • RGB565:RGB分量分别使用5位、6位、5位:

在这里插入图片描述

  • RGB555:RGB分量分别使用5位、5位、5位:

在这里插入图片描述
对于RGB555,如何获取各个5位上的值,即分别获取 R,G,B所代表的值?
通过位运算即可获取。

   /*RGB 颜色模型*/struct XColor {unsigned int color : 15;};void getRGB555() {XColor col{};col.color = 0b110000010111100;std::cout << "R: " << (col.color >> 10) << '\n';std::cout << "G: " << ((col.color & 0x3F0) >> 5) << '\n';std::cout << "B: " << (col.color & 0x1F) << '\n';}
  • RGB24格式:每个像素用24比特位表示,占3个字节,在内存中RGB各排列顺序为:BGR:

在这里插入图片描述

  • RGB32格式:每个像素用32比特位表示,占4个字节,R,G,B分量分别用8个bit表示,存储顺序为B,G,R,最后8个字节保留

    • ARGB32:本质就是带alpha通道的RGB24,与RGB32的区别在与,保留的8个bit用来表示透明,也就是alpha的值

    在这里插入图片描述

    • 对于**RGB32**,如何获取各个8位上的值,即分别获取 R,G,B,Alpha所代表的值?

      • 通过位运算即可获取。
      void getRGB32() {int color = 0x0F0A2B0C;std::cout << "B: " << (color >> 24) << '\n';std::cout << "G: " << ((color & 0x00FF0000) >> 16) << '\n';std::cout << "R: " << ((color & 0x0000FF00) >> 8) << '\n';std::cout << "Alpha: " << (color & 0x000000FF) << '\n';
      }
      

HSV颜色模型

HSV(Hue, Saturation,Value)也被称为六角锥体模型,即色调,饱和度,明度

在这里插入图片描述

将RGB转换为HSV模型:

  • **cvtColor**函数:将图像从一种颜色模型转换为另一个。
  • 起到关键作用的是第三个参数:cv::ColorConversionCodes 是一个枚举,表示了你想要从谁转换到谁,这里我们让BGR形式转换为HSV形式。
cv::Mat res;
cv::cvtColor(m1, res, cv::ColorConversionCodes::COLOR_BGR2HSV);
cv::imshow("hsv", res);

在这里插入图片描述

在这里插入图片描述


HLS模型

HLS模型分别是色调,亮度,饱和度

在这里插入图片描述

上图可以看出,固定一个颜色(H),那么随着饱和度(S,Chroma)的增加,颜色越来越深。

cv::cvtColor(m1, res, cv::ColorConversionCodes::COLOR_BGR2HLS);
cv::imshow("hls", res);

在这里插入图片描述

在这里插入图片描述


LAB模型

Lab颜色模型由三个要素组成,一个要素是**亮度**(L),a 和b是两个颜色通道。

  • **a**包括的颜色是从深绿色(低亮度值)到灰色(中亮度值)再到亮粉红色(高亮度值)
  • **b**是从亮蓝色(低亮度值)到灰色(中亮度值)再到黄色(高亮度值)。
  • 因此,这种颜色混合后将产生具有明亮效果的色彩。
    在这里插入图片描述
cv::cvtColor(m1, res, cv::ColorConversionCodes::COLOR_BGR2Lab);
cv::imshow("Lab", res);

在这里插入图片描述

在这里插入图片描述

还有很多的颜色模型都可以在 cvtColor这个函数中找到。


图像像素读写操作

openCV基本类型介绍:

  • 基本类型:
typedef unsigned uint;
typedef signed char schar;
typedef unsigned char uchar;
typedef unsigned short ushort;
  • 封装类型:Vec类似于std::vector,只不过可以指定其大小,并且命名规则为 cv:: Vec大小+ 类型
typedef Vec<uchar, 2> Vec2b;
typedef Vec<uchar, 3> Vec3b;
typedef Vec<uchar, 4> Vec4b;typedef Vec<short, 2> Vec2s;
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;typedef Vec<ushort, 2> Vec2w;
typedef Vec<ushort, 3> Vec3w;
typedef Vec<ushort, 4> Vec4w;typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<int, 6> Vec6i;
typedef Vec<int, 8> Vec8i;

图像是由像素掉构成的,因此我们可以获取图像的每一个像素,这个像素是由(i,j)确定的,即在图片宽度与高度的范围下,每一个行的每一列都可以是一个像素。

我们使用 Mat 的 at 函数来获取某个位置的像素值。

注意像素具有channels的区别。

  • 如果是单通道: 则直接获取 uchar 表示一个像素(一字节)。
  • 如果是三通道: 则需要获取Vec3b 表示三个像素,可以通过[0],[1],[2]来分别操作。

以下操作对图片转换为负片,使用 255 - 当前像素值

#include <iostream>
#include <opencv2/opencv.hpp>class ImgPixel {
public:ImgPixel(std::string filename):m(cv::imread(filename)){}void show(std::string title) {cv::imshow(title, m);}void Visit_By_Array() {auto dims = m.channels(); //获取通道数for (int i = 0; i < m.rows; i++) {for (int j = 0; j < m.cols; j++) {if (dims == 1) {//如果是一通道,则直接操作uchar rets = m.at<uchar>(i, j);rets = 255 - rets;}if (dims == 3) {cv::Vec3b rets = m.at<cv::Vec3b>(i, j);
#if 0m.at<cv::Vec3b>(i, j)[0] = 255 - rets[0]; //转换为负片m.at<cv::Vec3b>(i, j)[1] = 255 - rets[1];m.at<cv::Vec3b>(i, j)[2] = 255 - rets[2];
#else //安全类型转换: 超过255的赋值为 255 小于0的赋值为 0m.at<cv::Vec3b>(i, j)[0] = cv::saturate_cast<uchar>(rets[0] + 100);m.at<cv::Vec3b>(i, j)[1] = cv::saturate_cast<uchar>(rets[1] + 100);m.at<cv::Vec3b>(i, j)[2] = cv::saturate_cast<uchar>(rets[2] + 100);
#endif}}}}
private:cv::Mat m;
};
int main(){ImgPixel img("dog.png");img.show("origin");img.Visit_By_Array();img.show("convert1");cv::waitKey(0);return 0;
}

安全类型转换:saturate_cast<T> 是openCV的一种安全转换函数,当我们对像素执行加减乘除的时候,有可能会超出 [ 0 , 255 ] [0,255] [0,255]
的范围,因此使用此函数来保证不会越界。

实际上这个函数就是:

  • 超过255:转为255
  • 小于0:转为0
template<> inline uchar saturate_cast<uchar>(int v)          { return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); }

像素算数运算

图像可以进行像素之间的算数运算,跟我们上节的对像素的简单减法是一样的:

我们有专门的函数:

  • add:像素加
  • subtract:像素减
  • multiply:像素乘
  • divide:像素除
  • addWeighted:对图片执行: α ⋅ i m g 1 + β ⋅ i m g 2 = r e s \alpha\cdot img_1 + \beta\cdot img_2 = res αimg1+βimg2=res 的操作,其中的 α \alpha α β \beta β就是透明度

除了基本的运算,还有二进制运算

  • and:像素按位与
  • or:按位或
  • **not:**按位取反
  • xor:按位异或

测试如下:

需要两个原图片执行下面的这些操作,我使用的图片是:(注意尺寸要一样)

在这里插入图片描述

然后自行执行下面代码。

在这里插入图片描述

#include <iostream>
#include <opencv2/opencv.hpp>class ImgOperation {
public:ImgOperation() :m1(cv::imread("dog.png")), m2(cv::imread("text.jpg")) {}void testAdd(std::string title="add") {cv::add(m1, m2, res);cv::imshow(title, res);cv::waitKey();}void testSub(std::string title = "subtract") {cv::subtract(m1, m2, res);cv::imshow(title, res);cv::waitKey();}void testMul(std::string title = "multiply") {cv::multiply(m1, m2, res);cv::imshow(title, res);cv::waitKey();}void testDivide(std::string title = "divide") {cv::divide(m1, m2, res);cv::imshow(title, res);cv::waitKey();}void testAddWeighted(std::string title="AddWeighted") {cv::addWeighted(m1, 0.1, m2, 0.9, 0, res);cv::imshow(title, res);cv::waitKey();}//BitWisevoid testBitWise() {cv::Mat _and, _or, _xor, _not;cv::bitwise_and(m1, m2, _and);cv::bitwise_or(m1, m2, _or);cv::bitwise_xor(m1, m2, _xor);cv::bitwise_not(m1, _not);cv::imshow("and", _and);cv::imshow("or", _or);cv::imshow("xor", _xor);cv::imshow("not", _not);}
private:cv::Mat m1;cv::Mat m2;cv::Mat res;
};int main()
{ImgOperation opt;//opt.testAdd();//opt.testSub();//opt.testMul();//opt.testDivide();//opt.testAddWeighted();	opt.testBitWise();cv::waitKey();return 0;
}

图形文字绘制

绘制线

使用**line**函数,原型如下:

void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,int thickness = 1, int lineType = LINE_8, int shift = 0);
//线的样式
enum LineTypes {FILLED  = -1,LINE_4  = 4, //!< 4-connected lineLINE_8  = 8, //!< 8-connected lineLINE_AA = 16 //!< antialiased line
};
/*******************************************************************
*			img: 			绘制在那个图像上
*			pt1:			起点
*			pt2:			终点
*			color:			颜色
*			thickness:		厚度(宽度) 
*			lineType:		线的样式
*					FILLED: 线填充的
*					LINE_4:	4邻接连接线
*					LINE_8: 8邻接连接线
*					LINE_AA:反锯齿连接线(高斯滤波)
*			shift: 			坐标点小数点位数(可忽略不写)
*********************************************************************/

在执行 imshow的之前,在图片上画一条线:

void testDrawLine() {//绘制线cv::line(m, cv::Point(0, 0), cv::Point(300, 300), cv::Scalar(0,255,0), 3, cv::LineTypes::LINE_AA);}

在这里插入图片描述


绘制圆

使用**circle函数来绘制或者填充圆**

void circle(InputOutputArray img, Point center, int radius,const Scalar& color, int thickness = 1,int lineType = LINE_8, int shift = 0);
//线的样式
enum LineTypes {FILLED  = -1,LINE_4  = 4, //!< 4-connected lineLINE_8  = 8, //!< 8-connected lineLINE_AA = 16 //!< antialiased line
};
/*******************************************************************
*			img: 			绘制在那个图像上
*			center:			圆心坐标
*			radius:			半径
*			color:			颜色
*			thickness:		厚度(宽度)
*								-1: 	填充圆
*								其他值:  空心
*			lineType:		 线的样式
*					FILLED: 线填充的
*					LINE_4:	4邻接连接线
*					LINE_8: 8邻接连接线
*					LINE_AA:反锯齿连接线(高斯滤波)
*			shift: 			坐标点小数点位数(可忽略不写)
*********************************************************************/

效果如下:

  • 填充效果需要把thickness置为-1。
void testDrawCircle() {cv::circle(m, cv::Point(150, 150), 50, cv::Scalar(0, 255, 0),-1); //填充圆cv::circle(m, cv::Point(150, 150), 52, cv::Scalar(0, 0, 255), 2, cv::LineTypes::LINE_AA); //空心圆}

在这里插入图片描述


绘制矩形

使用rectangle函数来绘制矩形。

void rectangle(InputOutputArray img, Rect rec,const Scalar& color, int thickness = 1,int lineType = LINE_8, int shift = 0);
/*******************************************************************
*			img: 			绘制在那个图像上
*			rec:			矩形大小  Rect(x,y,w,h);  
*					x,y:	起始坐标
*					w,h:	宽度和高度
*			color:			颜色
*			thickness:		厚度(宽度)
*								-1: 	填充矩形
*								其他值:  空心矩形
*			lineType:		线的样式
*					FILLED: 线填充的
*					LINE_4:	4邻接连接线
*					LINE_8: 8邻接连接线
*					LINE_AA:反锯齿连接线(高斯滤波)
*			shift: 			坐标点小数点位数(可忽略不写)
*********************************************************************/

效果如下:

void testDrawRectangle() {cv::rectangle(m, cv::Rect(0, 0, 50, 50), cv::Scalar(100, 45, 20),-1);}

在这里插入图片描述


绘制椭圆

使用ellipse来绘制椭圆:

void ellipse(InputOutputArray img, Point center, Size axes,double angle, double startAngle, double endAngle,
const Scalar& color, int thickness = 1,int lineType = LINE_8, int shift = 0);
/*******************************************************************
*			img: 			绘制在那个图像上
*			center:			椭圆圆心
*			axes:			矩形内置椭圆
*			angle:			倾斜角
*			startAngle:		扩展的弧度 0
*			endAngle:		 扩展的弧度  360
*			color:			颜色
*			thickness:		线宽度
*								-1: 	填充矩形
*								其他值:  空心矩形
*			lineType:		线的样式
*					FILLED: 线填充的
*					LINE_4:	4邻接连接线
*					LINE_8: 8邻接连接线
*					LINE_AA:反锯齿连接线(高斯滤波)
*			shift: 			坐标点小数点位数(可忽略不写)
*********************************************************************/

效果如下:

void testDrawEllipse() {cv::ellipse(m, cv::Point(100, 100),cv::Size(20,80),180,0,360, cv::Scalar(54, 54, 43));cv::ellipse(m, cv::Point(100, 100), cv::Size(20, 80), 90, 0, 360, cv::Scalar(54, 54, 43),-1);}

在这里插入图片描述


绘制文字

使用**putText来绘制文字,注意不支持中文!!!!!!!!!!!!!**

void putText( InputOutputArray img, const String& text, Point org,int fontFace, double fontScale, Scalar color,int thickness = 1, int lineType = LINE_8,bool bottomLeftOrigin = false );
/*******************************************************************
*			img: 			绘制在那个图像上
*			text:			绘制文字
*			org:			文本框左下角
*			fontFace:		字体
*			fontScale:		缩放
*			color:			颜色
*			thickness		线宽度
*			lineType:		线的样式
*					FILLED: 线填充的
*					LINE_4:	4邻接连接线
*					LINE_8: 8邻接连接线
*					LINE_AA:反锯齿连接线(高斯滤波)
*			bottomLeftOrigin: 		起点位置
*								true:  左上角  反转倒立显示
*								false: 左下角  正常显示
*********************************************************************/
//opencv 不识别汉字
//fontFace: 字体
enum HersheyFonts {FONT_HERSHEY_SIMPLEX        = 0, //!< normal size sans-serif font   //灯芯体FONT_HERSHEY_PLAIN          = 1, //!< small size sans-serif fontFONT_HERSHEY_DUPLEX         = 2, //!< normal size sans-serif font (more complex than FONT_HERSHEY_SIMPLEX)FONT_HERSHEY_COMPLEX        = 3, //!< normal size serif fontFONT_HERSHEY_TRIPLEX        = 4, //!< normal size serif font (more complex than FONT_HERSHEY_COMPLEX)FONT_HERSHEY_COMPLEX_SMALL  = 5, //!< smaller version of FONT_HERSHEY_COMPLEXFONT_HERSHEY_SCRIPT_SIMPLEX = 6, //!< hand-writing style fontFONT_HERSHEY_SCRIPT_COMPLEX = 7, //!< more complex variant of FONT_HERSHEY_SCRIPT_SIMPLEXFONT_ITALIC                 = 16 //!< flag for italic font
};

测试如下:

void testDrawText(const std::string& name) {cv::putText(m,name,cv::Point(10, 200),cv::HersheyFonts::FONT_HERSHEY_COMPLEX,1.0,cv::Scalar(50,50,255),2,cv::LineTypes::LINE_AA,false); //翻转}

在这里插入图片描述


其他绘制函数

绘制多边形线:

  • polylines

绘制填充多边形:

  • fillPoly

文本参考

百度百科_全球领先的中文百科全书

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

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

相关文章

macOS 源码编译 qpress

╰─➤ git clone https://github.com/PierreLvx/qpress.git ╰─➤ cd qpress ╰─➤ make g -O3 -o qpress -x c quicklz.c -x c qpress.cpp aio.cpp utilities.cpp -lpthread -Wall -Wextra -Werror ╰─➤ sudo make install …

怎么快速定位bug?怎么编写测试用例?

目录 01定位问题的重要性 02问题定位技巧 03初次怎么写用例 作为一名测试人员如果连常见的系统问题都不知道如何分析&#xff0c;频繁将前端人员问题指派给后端人员&#xff0c;后端人员问题指派给前端人员&#xff0c;那么在团队里你在开发中的地位显而易见 &#xff0c;口碑…

垃圾回收标记阶段算法

1.标记阶段的目的 主要是在GC在前&#xff0c;判断出哪些是有用的对象&#xff0c;哪些是需要回收的对象&#xff0c;只有被标记为垃圾对象&#xff0c;GC才会对其进行垃圾回收。判断对象是否为垃圾对象的两种方式&#xff1a;引用计数算法和可达性分析算法。 2.引用计数算法…

如何搭建使用dubbo-Admin?

dubbo-Admin介绍 一款用于dubbo可视化界面操作的管理平台 dubbo-Admin特点 dubbo-Admin是dubbo的管理界面平台&#xff0c;且是一个前后端分离的项目&#xff0c;前端使用vue&#xff0c;后端使用springboot。 软件下载 dubbo-admin-0.5.0.zip 软件使用

会议OA项目之会议审批(亮点功能:将审批人签名转换为电子手写签名图片)

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于OA项目的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.主要功能点介绍 二.效果展示 三.前端…

MongoDB 的日常使用

一、简介 1、 常见的数据库分类 RDBMS&#xff08;关系型数据库&#xff09;&#xff1a;常见的关系型数据库有 Oracle、DB2、Microsoft SQL Server、Microsoft Access、MySQL&#xff1b; NoSQL&#xff08;非关系型数据库&#xff09;&#xff1a;常见的非关系型数据库有 …

thinkphp实现无限分类(使用递归)

thinkphp实现无限分类&#xff08;使用递归&#xff09; 本文实例为大家分享了thinkphp实现无限分类的详细代码&#xff0c;希望对大家学习无限分类有所启发。 数据库&#xff1a;test 数据表&#xff1a;&#xff08;tp_category&#xff09;&#xff1a; Common/conf/conf…

在VSCode中实现Rust编程调试指南

在 VS Code 中调试 Rust&#xff1a;终极指南 在本教程中&#xff0c;您将学习如何使用 VS Code 调试 Rust。可用于使用 VS Code 调试 Rust 的操作。设置 VS Code 来调试 Rust Rust因其易用性、安全性和高性能而继续保持其作为最受欢迎的编程语言的地位。随着 Rust 的流行&…

elementui el-table折叠表格,点击主表数据展开从表明细

用element-ui 的el-table实现&#xff1a;主表table可实现展开行显示关联的明细表table的列表数据&#xff0c;效果图如下 <el-tableref"tableData"v-loading"listLoading":data"tableData"row-key"id"borderstripehighlight-curr…

自动驾驶感知系统-激光雷达

感知系统 现有的车载传感器主要包括超声波雷达、激光雷达、毫米波雷达、车载摄像头、红外探头等。主流的自动驾驶感知平台以雷达和车载摄像头为主&#xff0c;呈现多传感器融合发展趋势。基于测量能力和环境适应性&#xff0c;预计雷达和车载摄像头会保持其感知平台霸主地位&a…

在react中配置less

第一步&#xff1a;暴露出webpack配置文件 终端命令&#xff1a;npm run eject (此命令一旦运行不可逆) 第二步&#xff1a;安装less以及less-loader npm install less less-loader --save-dev 第三步&#xff1a;修改webpack的配置文件 运行完以上命令后&#xff0c;项目…

精通自动化,Pytest自动化测试框架-fixture用例的前后置(实现)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 测试用例实现前后…

crmeb部署

安装宝塔 教程 安装所需要的软件 php mysql5.7 redis fileinfo nginx 安装crmeb 重启mysql 前台http://192.168.216.128/ 后台http://192.168.216.128/admin admin admin888登录 访问前台

自动化运维工具--saltstack部署及使用

目录 一、saltstack简介 1、介绍 2、Salt的核心功能 3、saltstack通信机制 二、saltstack部署 1、部署环境 2、配置yum源 3、安装master与minion 4、连接认证master和minion 三、salt运行 1、执行格式 2、实操演示 一、saltstack简介 1、介绍 saltstack是一个配置管…

连锁反应开始了!Linux 发行版迎新变化!

任何企业都有合法权利捍卫其模型和产品。撇开大量不真正了解开源许可证如何工作的人不谈&#xff0c;我们的印象是&#xff0c;有很多人觉得仅仅因为这是Linux&#xff0c;他们就有某种权利免费获得它。但事实上&#xff0c;他们没有。这不是自由软件中的“自由”的意思&#x…

浮点型在内存中的存储

目录 1.浮点数是什么&#xff1f; 2. 浮点数存储规则 1.浮点数是什么&#xff1f; 就是数学中的小数。 常见的浮点数&#xff1a; 3.14159 1E10&#xff08;1*10^10&#xff09; 浮点数家族包括&#xff1a; float、double、long double 类型。 浮点数表示的范围&#x…

前端 | ( 十二)CSS3简介及基本语法(中)| 变换、过渡与动画 | 尚硅谷前端html+css零基础教程2023最新

学习来源&#xff1a;尚硅谷前端htmlcss零基础教程&#xff0c;2023最新前端开发html5css3视频 系列笔记&#xff1a; 【HTML4】&#xff08;一&#xff09;前端简介【HTML4】&#xff08;二&#xff09;各种各样的常用标签【HTML4】&#xff08;三&#xff09;表单及HTML4收尾…

【C++基础(六)】类和对象(中) --构造,析构函数

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C初阶之路⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; 类和对象-中 1. 前言2. 构造函数3. 构造函数的特性4…

分布式系统的应用程序性能监视工具-skywalking

分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。提供分布式链路日志追踪、剖析、服务网格遥测分析、度量聚合和可视化一体化解决方案。 在应用系统进行实时监控,实现对应用性能管理和故障定位的系统化解决方案中常用的…

爬虫小白-如何辨别是否有cookie反爬案例

目录 一、Cookie介绍二、cookie生成来源区分查找三、如何判断是否有cookie反爬四、来自服务器生成的cookie反爬解决方法五、来自js生成的cookie反爬解决方法 一、Cookie介绍 先推荐该篇文章简单了解Cookie、Session、Token、JWT1、cookie的类型&#xff1a;会话cookie和持久co…