c++版opencv长文指南

news2024/9/24 9:22:05

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_AUTOSIZE
	cv::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;
}

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

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

相关文章

轻松搞定小程序生成短链接/二维码,你学会了吗?

朋友们&#xff0c;大家有没有遇到过这样的困扰&#xff1a;小程序由于不是链接&#xff0c;在短信或者其他平台里根本没法推广&#xff0c;导致小程序的用户量很难涨起来。 那小程序转成链接真的就没办法实现吗&#xff1f;当然不是&#xff01; 现在有一款超实用的工具——…

zigbee笔记:十、ZStack(2.3.0-1.4.0)的OSAL使用分析

zigbee笔记&#xff1a;九中&#xff0c;我们已经学会了利用模板&#xff0c;定制自己的个性开发工程&#xff0c;本文为协议栈&#xff08;ZStack-CC2530-2.3.0-1.4.0&#xff09;代码使用分析笔记&#xff0c;来进一步掌握协议栈的使用。 一、协议栈使用知识点 1、协调器、路…

python从入门到精通:基础语法讲解

1、字面量 字面量&#xff1a;在代码中&#xff0c;被写下来的固定的值&#xff0c;称之为字面量。 python中常用的几种数据类型&#xff1a; 类型描述说明数字&#xff08;Number&#xff09; 整数&#xff08;int&#xff09; 浮点数&#xff08;float&#xff09; 复数&a…

Graph-Cot:图上迭代推理

Graph-Cot&#xff1a;图上迭代推理 提出背景GRAPH-COT 对比 MindMapGRAPH-COT 和 MindMap 多链推理方法结合案例一&#xff1a;复杂症状的诊断案例二&#xff1a;罕见病的诊断案例三&#xff1a;治疗方案的制定 解法拆解目的问题解法 GRAPH-COT 医学问诊 论文&#xff1a;http…

(BO)Bayes-CNN多变量时序预测 基于贝叶斯算法-卷积神经网络多变量时序预测(多输入单输出)Matlab代码

Bayes-CNN多变量时序预测 基于贝叶斯算法-卷积神经网络多变量时序预测&#xff08;多输入单输出&#xff09;Matlab代码 程序已经调试好&#xff0c;无需更改代码替换数据集即可运行&#xff01;&#xff01;&#xff01;数据格式为excel&#xff01;(如下) 需要其他的都可以…

CSS3下拉菜单实现

导航菜单&#xff1a; <nav class"multi_drop_menu"><!-- 一级开始 --><ul><li><a href"#">Power</a></li><li><a href"#">Money</a></li><li><a href"#"…

【数模修炼之旅】02 多目标规划 深度解析(教程+代码)

【数模修炼之旅】02 多目标规划 深度解析&#xff08;教程代码&#xff09; 接下来 C君将会用至少30个小节来为大家深度解析数模领域常用的算法&#xff0c;大家可以关注这个专栏&#xff0c;持续学习哦&#xff0c;对于大家的能力提高会有极大的帮助。 1 多目标规划介绍及应…

百度智能云发布3款轻量级+2款场景大模型

文心大模型ERNIE 3.5是目前百度智能云千帆大模型平台上最受欢迎的基础大模型之一。针对用户的常见通用的对话场景&#xff0c;ERNIE 3.5 在指令遵循、上下文学习和逻辑推理能力三方面分别进行了能力增强。 ERNIE Speed作为三款轻量级大模型中的“大个子”&#xff0c;推理场景…

解决连接不上Linux和服务器中的Nacos(Windows中能连接但是Linux中却不行)

报错 com.alibaba.nacos.shaded.io.grpc.StatusRuntimeException: UNKNOWN: Uncaught exception in the SynchronizationContext. Re-thrown. at com.alibaba.nacos.shaded.io.grpc.Status.asRuntimeException(Status.jav 2024-08-13T10:21:52.93708:00 ERROR 27764 --- …

ArduPilot开源代码之FMU+IOMCU设计

ArduPilot开源代码之FMUIOMCU设计 1. 源由2. 设计概念3. FMU & IOMCU特点3.1 FMU&#xff08;Flight Management Unit&#xff09;的主要功能3.2 IOMCU&#xff08;Input/Output Microcontroller Unit&#xff09;的主要功能3.3 主要差异 4. 主/辅助(MAIN/AUX) PWM输出5. 软…

【北京仁爱堂】痉挛性斜颈的早期症状,你了解吗?

在日常生活中&#xff0c;您可能很少听到“痉挛性斜颈”这个名词&#xff0c;但它却是一种不容忽视的疾病。今天&#xff0c;就让我们一起来了解一下痉挛性斜颈的早期症状&#xff0c;以便能够及时发现并采取相应的措施。 痉挛性斜颈是一种局限性肌张力障碍疾病&#xff0c;主要…

Gitlab搭建服务器好做吗 Gitlab搭建服务器操作指南

GitLab是一个强大的开源代码托管和CI/CD工具&#xff0c;广泛用于软件开发的版本控制和自动化构建。对于许多公司和开发团队来说&#xff0c;自行搭建GitLab服务器是一个既具挑战性又有很多好处的选择。本文将详细讨论搭建GitLab服务器的难易程度&#xff0c;提供一份详尽的操作…

死信队列.

“死信”是指在RabbitMQ中那些因为某些原因无法被正常处理的消息。

OpenCV图像滤波(11)中值滤波medianBlur函数的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 功能描述 该函数使用中值滤波器对图像进行模糊处理。 该函数采用 ksizeksize 的窗口尺寸对图像进行平滑处理。对于多通道图像&#xff0c;每个通道将被独…

Linux发行版深度对比:Ubuntu、CentOS与Fedora

在Linux的广阔世界中&#xff0c;Ubuntu、CentOS和Fedora作为三大主流发行版&#xff0c;各自拥有独特的生态系统、用户基础和开发理念。它们不仅在技术架构上有着显著的差异&#xff0c;更在用户体验、社区支持、软件更新策略以及安全性能等方面展现出各自的特色。本文将对这三…

红黑树R-B Tree

文章目录 概述红黑树的特性红黑树的原理应用为什么设计红黑树红黑树左旋与右旋的区别 概述 红黑树&#xff08;Red Black Tree&#xff09;是一种自平衡的二叉查找树&#xff0c;在计算机科学中广泛使用&#xff0c;其典型的用途是实现关联数组。R-B Tree&#xff0c;全称是 R…

[C++][opencv]基于opencv实现photoshop算法亮度和对比度调整

【测试环境】 vs2019 opencv4.8.0 【效果演示】 【核心实现代码】 #include <iostream> #include "opencv2/core.hpp" #include "opencv2/imgproc.hpp" #include "opencv2/highgui.hpp"using namespace std; using namespace cv;#defi…

【区块链+食品安全】食药产业全流程可追溯平台 | FISCO BCOS应用案例

为响应国家强化食品安全追溯监管的号召&#xff0c;吉科软信息技术有限公司基于 FISCO BCOS 联盟链开源技术&#xff0c;推出了 食药产业全流程可追溯平台&#xff0c;并应用于吉林省白山市。该平台建立了从食药产品种养殖、生产加工、冷链运输、 流通到消费的全链条可追溯体系…

掌握Python eval()函数:解析动态代码执行的神奇之处

eval() 是 Python 提供的一个内置函数&#xff0c;用于动态执行字符串形式的表达式。 虽然它功能强大&#xff0c;但同时也伴随着一定的风险和局限性。在本文中&#xff0c;我们将详细介绍 eval() 的用法、注意事项以及一些常见的应用场景。 一、eval() 函数的基本用法 基本语…

SpringIOC和SpringAOC

lombok插件 XML<!-- 加载资源文件 --><context:property-placeholder location"classpath:jdbc.properties"></context:property-placeholder><!-- 注入数据源 --><bean id"dataSource" class"com.mchange.v2.c3p0.ComboP…