基于Cpp的OpenCV4.8入门学习笔记(一)


一、OpenCV在VS2019中项目配置步骤

  • 视图 -> 其他窗口 -> 属性管理器 -> Release|x64下添加Microsoft.Cpp.x64.user

  • 配置包含目录

​ 打开Microsoft.Cpp.x64.user下的属性页面 -> VC++目录下的包含目录,加入如下两个文件夹:

D:\CodeEnvironment\opencv\build\include

D:\CodeEnvironment\opencv\build\include\opencv2

  • 配置库目录

​ 属性页找到VC++目录下的库目录,加入如下文件夹:

D:\CodeEnvironment\opencv\build\x64\vc16\lib

  • 配置链接器

​ 属性页链接器下输入的附加依赖项,加入如下指令:opencv_world480.lib

  • 配置环境变量并重启VS

​ 将如下文件夹加入到系统的环境变量:

D:\CodeEnvironment\opencv\build\x64\vc16\lib

二、OpenCV图像的一些基本操作(day 01)

1. 图像读取操作函数

//第一个参数为图像所在磁盘位置,第二个参数图像读取的方式,默认彩色读取
bool imread( const String& filename, int flags = IMREAD_COLOR );
//例子
Mat image = imread("D:/Photo/神童2.png", IMREAD_COLOR);

2. 图像写入操作

//第一个参数为写入位置,第二个参数为Mat图像矩阵对象,第三个参数默认
bool imwrite( const String& filename, InputArray img,
              const std::vector<int>& params = std::vector<int>());
//例子
imwrite("D:/" + im_name, image);

3. 图像显示操作

//第一个参数为图像显示的窗口名字,第二个参数为Mat图像矩阵对象
void imshow(const String& winname, InputArray mat);
//例子
imshow("src",src);

4. 图像色彩空间转换,主要针对的是图像通道格式,比如从BGR转换到HSV,从BGR转换到GRAY

//第一个参数为Mat对象,表示原图,第二个参数为Mat对象,表示原图,第三个参数为色彩空间转换方式,第四个参数为输出图像的通道个数,一般会根据所转换的色彩空间自动推理
void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );
//例子
cvtColor(this->src, hsv, COLOR_BGR2HSV);	//H 0~180 S,V 0~255
cvtColor(this->src, gray, COLOR_BGR2GRAY);	//灰度图像为单通道

5. Mat图像矩阵对象的创建与赋值

//创建空白图像,第一个参数为图像大小,第二个参数为图像的通道类型,8UC3表示三通道,每个通道8位深度
Mat m3 = Mat::zeros(Size(512, 512), CV_8UC3);
//Mat对象赋值方式1:克隆,深拷贝
m1 = this->src.clone();

//Mat对象赋值方式2:拷贝,深拷贝 
this->src.copyTo(m2);

//Mat对象赋值方式3,等号,浅拷贝
Mat m3 = src;

6. 图像像素点(通道)访问的两种方式

//访问图像的每一个通道前,需要先获取图像的基本属性
Mat img;
int w = img.cols;
int h = img.rows;
int dims = img.channels();	//每个像素通道数

//方式一,数组方式遍历(不推荐,还得分通道数的情况)
for (int i = 0; i < h ++i) {
    for (int j = 0; j < w; ++j) {
        if (dims == 1) {	//灰度图像,单通道
            int pv = this->src.at<uchar>(i, j);		//获取8位通道值
            this->src.at<uchar>(i, j) = 255 - pv;	//对通道值进行反转
        }
        if (dims == 3) {	//彩色图像,多通道
            Vec3b bgr= this->src.at<Vec3b>(i, j);	//数组返回

            this->src.at<Vec3b>(i, j)[0] = 255 - bgr[0];
            this->src.at<Vec3b>(i, j)[1] = 255 - bgr[1];
            this->src.at<Vec3b>(i, j)[2] = 255 - bgr[2];
        }
    }
}


//方式二,数组指针遍历(推荐,代码简洁高效)
	for (int i = 0; i < h; ++i) {
		uchar* current_row = this->src.ptr<uchar>(i);	//获取当前行指针
		for (int j = 0; j < w * dims; ++j) {
			*current_row++ = 255 - *current_row;		
		}
	}

7. 图像像素点(通道)算术运算,主要是加减乘除

//方式一,通过Mat类提供的API计算,需要创建一个Mat图像矩阵,属于矩阵层面的运算
Mat m = Mat::zeros(this->src.size(), this->src.type());
m = Scalar(2, 2, 2);	//创建一个新的矩阵,并且对通道初始化

//第一个参数和第二个参数为操作数,第三个参数需要新的Mat对象接收运算结果
add(this->src, m, image1);
subtract(this->src, m, image2);
divide(this->src, m, image3);
multiply(this->src, m, image4);

//方式二,利用指针遍历图像每一个通道,操作每一个通道,属于普通数据类型的运算
for (int i = 0; i < h; ++i) {
    uchar* current_row1 = image1.ptr<uchar>(i);
    uchar* current_row2 = image2.ptr<uchar>(i);
    uchar* current_row3 = image3.ptr<uchar>(i);
    uchar* current_row4 = image4.ptr<uchar>(i);
    for (int j = 0; j < w * channels; ++j) {
        //saturate_cast<uchar>()函数保证数据不会溢出uchar的表示范围,无符号八位0~255
        *current_row1++ = saturate_cast<uchar>(*current_row1 + 100);
        *current_row2++ = saturate_cast<uchar>(*current_row2 - 100);
        *current_row3++ = saturate_cast<uchar>(*current_row3 * 2);
        *current_row4++ = saturate_cast<uchar>(*current_row4 / 2);
    }
}

8. 利用OpenCV中GUI库提供的createTrackbar()创建滚动条,实现图像的对比度调整

/*
	第一个参数和第二个参数为字面意思,第二个参数为滚动条绑定的窗口名
	第三个参数定义滚动条位置
	第四个参数定义滚动条最大值
	第五个参数为滚动条绑定的函数事件指针
	第六个参数为用户数据,可以理解为滚动条需要操作的对象
*/
int createTrackbar(const String& trackbarname, const String& winname,
                              int* value, int count,
                              TrackbarCallback onChange = 0,
                              void* userdata = 0);

//例子
createTrackbar("light_value", "imageLight_contrast_operator", nullptr, 100, OnTrack1, (void *)(&this->src));
createTrackbar("contrast_value", "imageLight_contrast_operator", nullptr, 200, OnTrack2, (void*)(&this->src));

//其中,OnTrack1和OnTrack2为绑定在滚动条的函数事件,函数的定义需要满足TrackbarCallback所规定的形式

9. OpenCV中int waitKey(int delay = 0)函数对应的键盘事件解析

/*
	int waitKey(int delay = 0)函数解析:该函数的功能是,通过参数delay阻塞程序的运行,delay的单位为ms。
	当delay != 0时,这段时间内,等待用户按下一个键,当检测到用户按下的键,就会返回对应的ASCII码,若用户没有按下键,则等待delay毫秒后,返回-1。
	当delay = 0时,等待用户按下一个键,否则程序一直阻塞,和system("pause")函数功能雷同,不同的是,waitKey()响应的键盘事件是OpenCV库创建的窗口,而system("pause")响应的键盘事件是控制台。
*/

//例子,通过键盘事件改变图像的色彩空间
	Mat dst = this->src.clone();
	while (true) {
		//控制用户与图形界面的交互,返回值为按下键盘的ASCII码,如果在形参指定时间内没有按下键,返回-1
		int c = waitKey(100);	
		if (c == 27) {	//Esc的ASCII码
			break;
		}
		if (c == 49) {
			cout << "Entering key 1" << endl;
			cvtColor(QuickDemo::src, dst, COLOR_BGR2HSV);
		}
		if (c == 50) {
			cout << "Entering key 2" << endl;
			cvtColor(QuickDemo::src, dst, COLOR_BGR2GRAY);
		}
		if (c == 51) {
			cout << "Entering key 3" << endl;
			Mat tmp = Mat::zeros(QuickDemo::src.size(), QuickDemo::src.type());
			tmp = Scalar(50, 50, 50);
			add(QuickDemo::src, tmp, dst);		//图像矩阵做加法操作
		}
		imshow("Key Event Demo", dst);			//实时更新窗口里面的图像内容
	}

10. OpenCV中21种自带颜色转换的图像操作

//OpenCV库种存在枚举变量ColormapTypes,里面存放了21种颜色风格
enum ColormapTypes
{
    COLORMAP_AUTUMN = 0, 
    COLORMAP_BONE = 1, 
    COLORMAP_JET = 2, 
    COLORMAP_WINTER = 3,
    COLORMAP_RAINBOW = 4,
    COLORMAP_OCEAN = 5, 
    COLORMAP_SUMMER = 6, 
    COLORMAP_SPRING = 7, 
    COLORMAP_COOL = 8, 
    COLORMAP_HSV = 9, 
    COLORMAP_PINK = 10, 
    COLORMAP_HOT = 11, 
    COLORMAP_PARULA = 12, 
    COLORMAP_MAGMA = 13,
    COLORMAP_INFERNO = 14,
    COLORMAP_PLASMA = 15,
    COLORMAP_VIRIDIS = 16, 
    COLORMAP_CIVIDIS = 17,
    COLORMAP_TWILIGHT = 18, 
    COLORMAP_TWILIGHT_SHIFTED = 19,
    COLORMAP_TURBO = 20,
    COLORMAP_DEEPGREEN = 21
};
//OpenCV提供了applyColorMap()函数,转换图像的颜色风格,第三个参数为枚举类型ColormapTypes中颜色风格的编号
void applyColorMap(InputArray src, OutputArray dst, int colormap);

11. 图像像素的逻辑操作

Mat m1, m2, dst;
//逻辑操作针对通道数值的二进制表示,主要包括与或非,异或操作
bitwise_and(m1, m2, dst);
imshow("dst1", dst);

bitwise_or(m1, m2, dst);
imshow("dst2", dst);

//异或,相同为0,相异为1
bitwise_xor(m1, m2, dst);
imshow("dst3", dst);

//取反操作在二值图目标提取应用较多
bitwise_not(this->src, dst);	//取反操作写法一
dst = ~this->src;	//取反操作写法二

12. 图像的通道分离与合并

Mat src, dst;
vector<Mat>mv;	//Mat对象数组,接收通道分离后的图像

//对一个指定图像进行通道分离
split(src, mv);

//去除部分通道的值,然后合并
mv[2] = 0;
merge(mv, dst);

//可以输出通道分离与合并后的图像

13. 对纯色图像进行背景更换

Mat src, hsv, redBG, mask;

//第一步,图像色彩空间转换为hsv,更容易提取颜色
cvtColor(src, hsv, COLOR_BGR2HSV);

//第二步,通过通道颜色表示范围表,将指定背景颜色通道值赋值为255,其余赋值为0
inRange(hsv, Scalar(100, 43, 46), Scalar(124, 255, 255), mask);

//第三步,创建需要更换颜色的canvas,以纯红为例
Mat redBG = Mat::zeros(src.size(), src.type());
redBG = Scalar(0, 0, 180);

//第四步,将inRange()生成的二值图进行取反,将ROI区域通道值赋值为255,非ROI(背景)区域赋值为0
bitwise_not(mask, mask);

//第五步,利用copyTO()函数,将原图像根据二值图的ROI区域复制到纯色背景图中
src.copyTo(redBG, mask);

14. 像素统计学函数

//统计出每一个通道的最大值与最小值,并且输出其所在像素点位置
vector<Mat> mv;
Mat src;
split(src, mv);

double minValue, maxValue;	//存储通道的最大最小值
Point minLoc, maxLoc;		//存储最大最小通道值的像素点位置

//只能对单通道进行统计
for (int i = 0; i < mv.size(); ++i) {
    //
    minMaxLoc(mv[i], &minValue, &maxValue, &minLoc, &maxLoc, Mat());
    cout << "No." << i << " channels: " << endl;
    cout << "minValue: " << minValue << ", " << "maxValue: " << maxValue << endl;
    cout << "minLoc: " << minLoc << ", " << "maxLoc: " << maxLoc << endl;
}

//统计所有通道的均值与方差
Mat tmp = Mat::zeros(this->src.size(), this->src.type());
tmp = Scalar(255, 0, 0);

Mat mean, stddev; 
meanStdDev(tmp, mean, stddev);
cout << mean.at<double>(0, 0) << endl;	//输出mean图像矩阵(0, 0)位置的值
cout << "means: " << mean << endl;
cout<<"stddev: "<<stddev<<endl;		//Standard Deviation 标准差

15. OpenCV中常见几何图形的绘制

Mat src;

//矩形的绘制
Rect rect;
rect.x = 50;	//初始化矩阵的基本参数
rect.y = 50;
rect.width = 100;
rect.height = 100;
rectangle(src, rect, Scalar(255, 0, 0), 2, LINE_AA, 0);	//thickness小于0表示填充


//圆的绘制
Point p1(100,100);		//初始化矩形的圆心
circle(src, p1, 50, Scalar(0, 0, 255), 2, LINE_AA, 0);

//椭圆的绘制
Point p2(100,100);		//初始化椭圆的圆心
RotatedRect rotatedRect;
rotatedRect.center = p2;		
rotatedRect.size = Size(100, 50);	//分别表示椭圆2*a和2*b的值
ellipse(src, rotatedRect, Scalar(255, 255, 0), 2, LINE_AA);	//ellipse 椭圆

//线条的绘制
line(src, Point(50, 50), Point(150, 150), Scalar(0, 255, 255), 2, LINE_AA, 0);	//需要两个点

Mat tmp = Mat::zeros(this->src.size(), this->src.type());
Mat dst;
//图像带权重的加法操作,gamma参数是偏置值,直接加到每一个通道上
addWeighted(this->src, 0.8, tmp, 0.2, 50, dst);

三、总结

1. 一些图像基本常识

  一个像素点通常由通道组成,不同的色彩空间通道数不一样,例如常见的BGR(Blue, Green, Red)为三通道GRAY为单通道,每一个通道都有深度,例如显示器标识深度为8位,那么每个通道的取值范围为0~255,可以表示256种颜色

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值