当前位置: 首页 > news >正文

c++版opencv长文指南

c++版opencv长文指南

  • 1、配置opencv库
    • 1.1 下载
    • 1.2 配置
      • 1.2.1 配置包含目录
      • 1.2.2 配置库含目录
      • 1.2.3 配置链接器
      • 1.2.4 配置系统环境变量
  • 2、学习路线
  • 3、入门知识
    • 3.1 图像读取与显示
    • 3.2 图像色彩空间转换
    • 3.2 图像对象的创建与赋值
      • 3.2.1 图像对象的创建
      • 3.2.2 图像对象的赋值
    • 3.3 图像像素的读写操作
    • 3.3 图像像素的算术操作
      • 3.3.1 通过运算符重载来实现
      • 3.3.2 通过数组遍历来实现
      • 3.3.3 通过api来实现
    • 3.4 滚动条操作
      • 3.4.1 调整图像亮度
      • 3.4.2 参数传递

1、配置opencv库

1.1 下载

OpenCV的安装实际上是将OpenCV的库路径添加到我们现有的项目路径中。通常有两种方法可以完成这一操作:
1、一种是自己下载OpenCV的源代码,并在此基础上编译生成库文件(如lib或dll);
2、另一种则是直接下载已经编译好的库文件。
我们可以选择第二种方式,直接使用预编译的库文件。最新版OpenCV Lib 下载链接为:

https://sourceforge.net/projects/opencvlibrary/files/latest/download

1.2 配置

下载并解压OpenCV后,将其解压到一个固定目录,比如:“D:\program\opencv”。稍后,我们需要将这个路径作为头文件的路径,加入到C++程序的项目中。

在Visual Studio (VS)中,由于每个项目都是独立编译的,所以每个项目都有自己的“属性设置”。换句话说,你可以通过右键点击项目名称并选择“属性”来配置该项目的编译规则。

接下来,我们将在属性窗口中配置OpenCV路径,具体步骤如下:

1.打开Visual Studio并加载你的项目。
2.通过右键点击项目名称并选择“属性”来配置该项目的编译规则。
在这里插入图片描述
在这里插入图片描述

1.2.1 配置包含目录

找到“VC++目录”。其中,紫色区域表示是要在什么环境下运行就在什么环境下配置。比如我要在Debug版下配置x64的。这里我选择为所有配置(既支持Release,同时支持Debug版)
在这里插入图片描述
“包含目录”中,添加OpenCV的include和opencv2文件夹路径。

1.2.2 配置库含目录

在这里插入图片描述
“库目录”中,添加OpenCV的lib文件夹路径。
在这里插入图片描述

1.2.3 配置链接器

切换到“链接器”选项卡,点击“输入”项,在“附加依赖项”中,添加相应的OpenCV库文件名称。
在这里插入图片描述
在这里插入图片描述
这个其实就在1.2.2节中库文件目录下,后缀d代表是debug版本。如果是不带后缀的,在vs中使用debug的版本就会报错。
在这里插入图片描述

1.2.4 配置系统环境变量

将:

D:\program\opencv\build\x64\vc15\bin

添加到电脑系统的环境变量中。

通过以上步骤,你就完成了OpenCV在VS项目中的路径配置。

2、学习路线

在这里插入图片描述

3、入门知识

3.1 图像读取与显示

#include<iostream>
#include<opencv2/opencv.hpp>using namespace std;
using namespace cv;
int main()
{ cv::Mat src = cv::imread("C:/Users/Desktop/02.jpg");// 以灰度显示//cv::Mat src = cv::imread("C:/Users/Desktop/02.jpg", cv::IMREAD_GRAYSCALE);if (src.empty()){cout << "不能够正确加载图片" << endl;return -1;}cv::namedWindow("my_window", cv::WINDOW_FREERATIO);cv::imshow("my_window", src);  // 默认是WINDOW_AUTOSIZEcv::waitKey(0);cv::destroyAllWindows();system("pause");return 0;
}

3.2 图像色彩空间转换

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;int main()
{ cv::Mat src = cv::imread("C:/Users/Desktop/02.jpg");if (src.empty()){cout << "不能够正确加载图片" << endl;return -1;}cv::Mat hsv, gray;cv::cvtColor(src, hsv, cv::COLOR_BGR2HSV);cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);cv::imshow("RGB", src);  cv::imshow("HSV", hsv);  cv::imshow("GRAY", gray);   // 保存cv::imwrite("C:/Users/Desktop/hsv.jpg", hsv);cv::imwrite("C:/Users/Desktop/gray.jpg", gray);cv::waitKey(0);cv::destroyAllWindows();system("pause");return 0;
}

3.2 图像对象的创建与赋值

c++中的Mat创建,其实和Python中的Numpy很像,都是表示矩阵。
Mat的基本结构如下:
头部存放了一些属性:图像的宽高、dtype类型、通道数等;
直接赋值创建1个新Mat对象,指针还是指向同一个Data Block;但克隆 / 拷贝则会创建1个新的内存空间。
在这里插入图片描述
使用c++版的opencv时,只要记住:
1、c++中的cv基本上和opencv-python中的语法类似,比如:

cv2.imread()
cv::imread();

2、c++中的cv中的Mat和python中的Numpy语法类似,比如:

np.zeros()
Mat::zeros();

Mat和cv两者不要打架,参考着python中的来记。

3.2.1 图像对象的创建

Mat类可以存储的数据类型包含double、float、uchar(unsigned char)以及自定义的模板等。
在这里插入图片描述

一切图像皆Mat,c++版opencv中但凡涉及到矩阵处理的都是Mat,其余很多都是通过cv::进行调用。

// 创建空白图像
// c++中Mat类似python中的Numpy
// CV_8UC1 8位无符号字符(unsigned char) 1:单通道, 3:3通道
//Mat m3 =  Mat::zeros(cv::Size(8, 8), CV_8UC1); 
//Mat m3 =  Mat::zeros(src.size(), src.type();
Mat m3 =  Mat::zeros(8, 8, CV_8UC3); 
// 宽度为:8 高度为:8 通道数:3
cout << "宽度为:" << m3.cols << " 高度为:" << m3.rows << " 通道数:" << m3.channels() << endl;
cout << m3 << endl;// 单通道没啥区别,3通道时,只在每个像素的第1个通道为1,其余两个通道像素值为0
m3 =  Mat::ones(cv::Size(8, 8), CV_8UC3); 
// 即使直接赋值,仍然会出现这样的现象
//m3 = 127;// Scalar可以解决  c++中的操作符重载全部可以运用在Mat中
m3 = cv::Scalar(127, 127, 127);
cout << m3 << endl;

3.2.2 图像对象的赋值

cv::Mat src = cv::imread("C:/Users/Desktop/02.jpg");
cv::Mat m1, m2;
// 克隆 、 拷贝则会创建1个新的内存空间。
m1 = src.clone();
src.copyTo(m2);
// 直接赋值创建1个新Mat对象,指针还是指向同一个Data Block;
// 所以这里的m3的像素值改变,而src也会随着一起改变。
cv::Mat m3 = src;
m3 = cv::Scalar(0, 0, 255);
cv::imshow("res", src)

3.3 图像像素的读写操作

c++中的像素遍历和访问方式:
1、数组遍历

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;int main()
{ cv::Mat src = cv::imread("C:/Users/Desktop/02.jpg");int w = src.cols;int h = src.rows;int dims = src.channels();for (int y = 0; y < h; y++){for (int x = 0; x < w; x++){if (dims == 1){// 灰度图像// at方法是Mat里面的1个函数模板,所以要指定模板的数据类型int pv = src.at<uchar>(y, x);src.at<uchar>(y, x) = 255 - pv;}else if (dims == 3){// RGB图像// 是一个模板类 cv::Vec 的特化版本,专门用于存储 3 个 uchar(无符号字符)值,通常表示 BGR 通道。// 是一个用于表示固定大小的三维向量的类型,专门用于图像处理中的颜色数据cv::Vec3b bgr = src.at<cv::Vec3b>(y, x);src.at<cv::Vec3b>(y, x)[0] = 255 - bgr[0];src.at<cv::Vec3b>(y, x)[1] = 255 - bgr[1];src.at<cv::Vec3b>(y, x)[2] = 255 - bgr[2];}}}cv::imshow("img", src);cv::waitKey(0);cv::destroyAllWindows();system("pause");return 0;
}

2、指针方式遍历

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;int main()
{ cv::Mat src = cv::imread("C:/Users/Desktop/02.jpg");int w = src.cols;int h = src.rows;int dims = src.channels();for (int y = 0; y < h; y++){// 使用 src.ptr<uchar>(y) 获取当前行的指针;// current_y 是指向图像第 y 行第一个像素的指针。uchar* current_y = src.ptr<uchar>(y);for (int x = 0; x < w; x++){if (dims == 1){// 灰度图像int pv = *current_y;*current_y++ = 255 - pv;}else if (dims == 3){// RGB图像*current_y++ = 255 - *current_y;*current_y++ = 255 - *current_y;*current_y++ = 255 - *current_y;}}}cv::imshow("img", src);cv::waitKey(0);cv::destroyAllWindows();system("pause");return 0;
}

3.3 图像像素的算术操作

1、可以和标量Scalar进行加减乘除;
2、可以和创建的图像本身(全0、全1后进行赋初始值)的算术操作

3.3.1 通过运算符重载来实现

int main()
{ cv::Mat src = cv::imread("C:/Users/Desktop/02.jpg");cv::Mat dst;dst = src + cv::Scalar(50, 50, 50);    // 加法//dst = src - cv::Scalar(50, 50, 50);  // 减法//dst = src / cv::Scalar(2, 2, 2);      // 除法// 两个图形相乘,是不可以用标量进行操作的// penCV 并不支持直接用 * 操作符对 cv::Mat 和 cv::Scalar 进行运算//dst = src * cv::Scalar(2, 2, 2);// 使用 cv::multiply 函数cv::Mat m = cv::Mat::zeros(src.size(), src.type());m = cv::Scalar(2, 2, 2);cv::multiply(src, m, dst);cv::imshow("加法操作", dst);cv::waitKey(0);cv::destroyAllWindows();system("pause");return 0;
}

3.3.2 通过数组遍历来实现

实际上,opencv底层实现了优化,优先调用api

int main()
{ cv::Mat src = cv::imread("C:/Users/Desktop/02.jpg");cv::Mat m = cv::Mat::zeros(src.size(), src.type());m = cv::Scalar(50, 50, 50);cv::Mat dst = cv::Mat::zeros(src.size(), src.type());// 加法// 从上到下,从左到右,先遍历行(图像的高)for (int y = 0; y < src.rows; y++){for (int x = 0; x < src.cols; x++){// 获取原始图像的每个像素值cv::Vec3b p1 = src.at<cv::Vec3b>(y, x);// 获取m图像的每个像素值cv::Vec3b p2 = m.at<cv::Vec3b>(y, x);// saturate_cast方法在cv中常用, 将像素值约束在0-255之间dst.at<cv::Vec3b>(y, x)[0] = cv::saturate_cast<uchar>(p1[0] + p2[0]);dst.at<cv::Vec3b>(y, x)[1] = cv::saturate_cast<uchar>(p1[1] + p2[1]);dst.at<cv::Vec3b>(y, x)[2] = cv::saturate_cast<uchar>(p1[2] + p2[2]);}}cv::imshow("加法操作", dst);cv::waitKey(0);cv::destroyAllWindows();system("pause");return 0;
}

3.3.3 通过api来实现

int main()
{ cv::Mat src = cv::imread("C:/Users/Desktop/02.jpg");cv::Mat m = cv::Mat::zeros(src.size(), src.type());m = cv::Scalar(50, 50, 50);cv::Mat dst = cv::Mat::zeros(src.size(), src.type());cv::add(src, m, dst);// 减法cv::subtract(src, m, dst);// 除法cv::divide(src, m, dst);cv::imshow("加法操作", dst);cv::waitKey(0);cv::destroyAllWindows();system("pause");return 0;
}

3.4 滚动条操作

3.4.1 调整图像亮度

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;// 全局变量
cv::Mat src, dst, m;
int max_value = 100;  // 滑块的最大值
int lightness = 50;   // 初始亮度值void on_track(int, void*)
{m = cv::Scalar(lightness, lightness, lightness);cv::add(src, m, dst);// 显示结果cv::imshow("调节亮度", dst);cv::waitKey(0);
}int main()
{ src = cv::imread("C:/Users/Desktop/02.jpg");m = cv::Mat::zeros(src.size(), src.type());dst = cv::Mat::zeros(src.size(), src.type());cv::namedWindow("调节亮度", cv::WINDOW_FREERATIO);cv::createTrackbar("Value Bar:", "调节亮度", &lightness, max_value, on_track);// 手动调用回调函数以初始化显示on_track(lightness, 0);system("pause");return 0;
}

3.4.2 参数传递

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;void on_lightness(int lightness, void* userdata)
{cv::Mat src = *((cv::Mat*)userdata);cv::Mat m = cv::Mat::zeros(src.size(), src.type());m = cv::Scalar(lightness, lightness, lightness);cv::Mat dst = cv::Mat::zeros(src.size(), src.type());// dst = alpha * src + beta * m + gamma// alpha = 1, beta = 0, gamma =0, dst = alpha + gamma 就是调整亮度了cv::addWeighted(src, 1.0, m, 0, lightness, dst);// 显示结果cv::imshow("亮度和对比度调整", dst);cv::waitKey(0);
}void on_contrast(int lightness, void* userdata)
{cv::Mat src = *((cv::Mat*)userdata);cv::Mat m = cv::Mat::zeros(src.size(), src.type());m = cv::Scalar(lightness, lightness, lightness);cv::Mat dst = cv::Mat::zeros(src.size(), src.type());double contrast = lightness / 100.0;// alpha = contrast, beta = 0, gamma = 0, dst = src * alpha 就是调整亮度了cv::addWeighted(src, contrast, m, 0.0, 0, dst);// 显示结果cv::imshow("亮度和对比度调整", dst);cv::waitKey(0);
}int main()
{ cv::Mat src = cv::imread("C:/Users/15198/Desktop/微信图片_20240625171102.jpg");int max_value = 100;  // 滑块的最大值int lightness = 50;   // 初始亮度值int contrast_value = 100;  // 默认对比度cv::namedWindow("亮度和对比度调整", cv::WINDOW_FREERATIO);cv::createTrackbar("Value Bar:", "亮度和对比度调整", &lightness, max_value, on_lightness, (void*)&src);cv::createTrackbar("Contrast Bar:", "亮度和对比度调整", &contrast_value, max_value, on_contrast, (void*)&src);// 手动调用回调函数以初始化显示on_lightness(lightness, &src);system("pause");return 0;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Java进阶篇之深入理解多态的概念与应用
  • PHP项目任务系统小程序源码
  • 【网络基础一】几乎不讲任何网络协议细节,搭建网络基本结构
  • 【vue】在页面右下角添加悬浮按钮组件
  • 循环神经网络六-Pytorch中的序列化器
  • DreamFusion 论文学习
  • HTTP 和 HTTPS 协议的全面介绍
  • springboot多数据源配置
  • 安装AURIX™ Development Studio软件,新建工程,基于英飞凌TC375
  • 使用 Elasticsearch RestHighLevelClient 进行查询
  • 【如何使用Python绘制条形图】
  • 超详解Haproxy七层代理及配置
  • 力扣45:跳跃游戏2题解
  • 小白零基础学数学建模系列-Day4-线性规划基础与案例分析
  • 漏洞复现-Cacti命令执行漏洞 (CVE-2022-46169)
  • 【Linux系统编程】快速查找errno错误码信息
  • 【腾讯Bugly干货分享】从0到1打造直播 App
  • Angular数据绑定机制
  • exif信息对照
  • input的行数自动增减
  • Java 11 发布计划来了,已确定 3个 新特性!!
  • MySQL主从复制读写分离及奇怪的问题
  • swift基础之_对象 实例方法 对象方法。
  • vue中实现单选
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 机器学习学习笔记一
  • 马上搞懂 GeoJSON
  • 前言-如何学习区块链
  • 使用权重正则化较少模型过拟合
  • ionic入门之数据绑定显示-1
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • ###C语言程序设计-----C语言学习(3)#
  • #android不同版本废弃api,新api。
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • (1)Hilt的基本概念和使用
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (11)MATLAB PCA+SVM 人脸识别
  • (13)Latex:基于ΤΕΧ的自动排版系统——写论文必备
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (day 2)JavaScript学习笔记(基础之变量、常量和注释)
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (done) 两个矩阵 “相似” 是什么意思?
  • (HAL库版)freeRTOS移植STMF103
  • (leetcode学习)236. 二叉树的最近公共祖先
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (六)软件测试分工
  • (论文阅读11/100)Fast R-CNN
  • (全注解开发)学习Spring-MVC的第三天
  • (转)ABI是什么
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .bat批处理(七):PC端从手机内复制文件到本地