opencv c++编程基础

1、图片的本质

图像在 OpenCV 中的本质

在 OpenCV 中,图像被表示为一个多维数组,其中每个元素对应于图像中的单个像素。图像的维度取决于其通道数和像素数。

  • **通道数:**图像可以有多个通道,每个通道存储图像的不同信息。例如,彩色图像通常有 3 个通道(红色、绿色和蓝色),而灰度图像只有一个通道。
  • **像素数:**图像的像素数决定了其宽度和高度。

图像存储方式

OpenCV 中的图像通常以以下格式存储:

  • **Mat:**这是 OpenCV 中最常用的图像表示形式。Mat 是一个多维数组,可以存储不同类型的图像数据(例如,uint8、float32 等)。
  • **IplImage:**这是一个旧的图像表示形式,在 OpenCV 2.0 之前使用。它与 Mat 类似,但有一些限制。

Mat 中图像的存储

Mat 中的图像数据以行优先顺序存储。这意味着图像的第一个维度对应于行,而第二个维度对应于列。对于一个 3 通道的彩色图像,Mat 中的元素顺序如下:

[B00, G00, R00, B01, G01, R01, ..., Bmn, Gmn, Rmn]

其中:

  • BGR 表示蓝色、绿色和红色通道
  • mn 是图像的高度和宽度

通道的顺序

OpenCV 中图像的通道顺序通常为 BGR(蓝色、绿色、红色)。这与其他一些图像处理库(如 PIL)中使用的 RGB 顺序不同。

其他图像存储格式

除了 Mat 和 IplImage 之外,OpenCV 还支持其他图像存储格式,包括:

  • **UMat:**一种优化的 Mat,可利用 GPU 加速。
  • **cuda::GpuMat:**一种专用于 GPU 处理的 Mat。
  • **std::vector<uchar>:**一种使用标准 C++ 向量存储图像数据的格式。

2、Mat

从文件读取图片并显示

#include <iostream>
#include "opencv2/core.hpp"
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>

using namespace std;
using namespace cv;

int main(){
    Mat image;
    image = imread("firefox.png");      //imread()读取图片
    if(!image.empty()){
        imshow("1",image);              //imshow展示图片,前面为展示名,后面为图片。
        waitKey(0);
    }
    destroyAllWindows();

    return 0;
}

从文件读取图片并显示

waitKey(0) 是 OpenCV 中的一个函数,用于等待用户按下一个键。它有以下作用:

  • 暂停程序执行:waitKey(0) 会暂停程序执行,直到用户按下一个键。这通常用于在显示图像或视频时让用户有机会查看内容。
  • **获取按键:**当用户按下一个键时,waitKey(0) 会返回该键的 ASCII 码。这可用于检测用户输入并做出相应操作。
  • 无限等待:waitKey(0) 的参数为 0 表示无限等待。这意味着程序将一直暂停,直到用户按下一个键。

使用示例:

cv::Mat image = cv::imread("image.png");

cv::imshow("Image", image);

cv::waitKey(0);

在上面的示例中,程序将暂停执行,直到用户按下一个键。然后,程序将继续执行,关闭图像窗口并释放资源。

注意:

  • waitKey(0) 是一个阻塞函数,这意味着它会阻止程序执行,直到用户按下一个键。
  • 如果您不希望程序暂停执行,可以使用 waitKey(1),它将等待 1 毫秒的按键输入。如果在此期间没有按键输入,程序将继续执行。
  • waitKey(0) 通常用于交互式应用程序,例如图像查看器或视频播放器。

展示结果:

图片大小resize函数

resize后保存为新图片

#include <iostream>
#include "opencv2/core.hpp"
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core/mat.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

int main(){
    Mat image;
    image = imread("firefox.png");      //imread()读取图片
    if(!image.empty()){
        imshow("image",image);              //imshow展示图片,前面为展示名,后面为图片。
        waitKey(0);
    }
    // destroyAllWindows();

    Mat resize_image;
    resize(image, resize_image, Size(), 1, 0.5);     //resize()改变大小 前为高度 后为宽度

    if(!image.empty()){
        imshow("resize",resize_image);             
        waitKey(0);
    }
    imwrite("resize.png",resize_image);     //imwrite(文件名,图片)写入文件   需要指定扩展名,否则exception
    destroyAllWindows(); 
    return 0;
}

图片旋转

getRotationMatrix2D()和warpAffine()函数

 Mat rotated_image;
  
    double angle = 90;                                               //旋转角度
  Point2f center(image.cols / 2.0, image.rows / 2.0);              //获取旋转中心
  Mat rotation_matix = getRotationMatrix2D(center, angle, 0.5);    //getRotationMatrix2D()计算旋转矩阵 参数:旋转中心、旋转角度、放大倍数
  warpAffine(image, rotated_image, rotation_matix, image.size());  //warpAffine旋转图片  参数:原图、目标图片、旋转矩阵、生成图片的大小


    if(!rotated_image.empty()){
        imshow("rotate",rotated_image);             
        waitKey(0);
    }
    imwrite("rotate.png",rotated_image);   
    destroyAllWindows(); 

Point2f 是 OpenCV 中的一个结构,用于表示二维点。它包含两个浮点成员:xy,分别表示点的横坐标和纵坐标。

声明:

struct Point2f {
  float x;
  float y;

};

构造函数:

  • **Point2f():**创建一个默认构造的 Point2f,其中 xy 都为 0。
  • **Point2f(float x, float y):**创建一个 Point2f,其中 xy 设置为指定的值。

图片平移

warpAffine()函数和平移矩阵

平移矩阵:

平移矩阵是一个 2x3 的仿射变换矩阵,

[ 1 0 tx ]

[ 0 1 ty ]

其中:

  • tx 是水平平移量。
  • ty 是垂直平移量。

为tx提供正值将使图像向右移动,而负值将使图像向左移动。

同样,ty值为正值时,图像会向下平移,而ty值为负值时,图像会向上平移。

warpAffine()本质是仿射变换。

3、这里可以看到调整了大小或者平移过后窗口大小存在一些问题,:

可以使用 OpenCV 的 namedWindow() 函数来设置 imshow() 窗口的大小。

示例:

cv::namedWindow("Image", cv::WINDOW_NORMAL); // 创建一个可调整大小的窗口

cv::imshow("Image", image);

// 设置窗口大小

cv::resizeWindow("Image", 640, 480);

参数:

  • **window_name:**窗口的名称。
  • **flag:**一个标志,指定窗口的类型。WINDOW_NORMAL 创建一个可调整大小的窗口。

其他标志:

  • **WINDOW_AUTOSIZE:**窗口大小自动调整为图像大小。
  • **WINDOW_FREERATIO:**窗口可以自由调整大小,而无需保持图像的宽高比。
  • **WINDOW_FULLSCREEN:**窗口以全屏模式显示。

注意:

  • namedWindow() 函数必须在 imshow() 函数之前调用。
  • 窗口大小只能在创建窗口后设置。
  • 窗口大小设置仅适用于可调整大小的窗口(即使用 WINDOW_NORMAL 标志创建的窗口)。

图片拼接

在 OpenCV 中,可以使用 hconcat()vconcat() 函数水平和垂直拼接图像。

水平拼接(并排):

cv::Mat image1 = cv::imread("image1.png");

cv::Mat image2 = cv::imread("image2.png");

cv::Mat拼接图像;

cv::hconcat(std::vector[cv::Mat](cv::Mat){image1, image2},拼接图像);

垂直拼接(上下):

cv::Mat image1 = cv::imread("image1.png");

cv::Mat image2 = cv::imread("image2.png");

cv::Mat拼接图像;

cv::vconcat(std::vector[cv::Mat](cv::Mat){image1, image2},拼接图像);

参数:

  • **images:**要拼接的图像的向量。
  • **拼接图像:**用于存储拼接图像的 Mat 对象。

注意:

  • 要拼接的图像必须具有相同的通道数和深度。
  • hconcat()vconcat() 函数将自动调整图像大小以匹配。
  • 拼接图像的尺寸取决于要拼接的图像的尺寸和拼接的方向。

图片翻转

在 OpenCV 中,可以使用 flip() 函数水平或垂直翻转图像。

水平翻转:

cv::Mat image = cv::imread("image.png");

cv::Mat flipped_image;

// 水平翻转

cv::flip(image, flipped_image, 1);

垂直翻转:

cv::Mat image = cv::imread("image.png");

cv::Mat flipped_image;

// 垂直翻转

cv::flip(image, flipped_image, 0);

参数:

  • **image:**要翻转的图像。
  • **flipped_image:**用于存储翻转后图像的 Mat 对象。
  • **flipCode:**指定翻转方向的标志。

flipCode 标志:

  • **0:**垂直翻转
  • **1:**水平翻转
  • **-1:**水平和垂直翻转

注意:

  • 翻转图像不会修改原始图像。
  • 翻转图像可能会导致图像质量下降,尤其是在翻转包含文本或其他非对称特征的图像时。

高斯模糊

在 OpenCV 中,可以使用 GaussianBlur() 函数对图像应用高斯模糊。

示例

cv::Mat image = cv::imread("image.png");
cv::Mat blurred_image;

// 高斯模糊
cv::GaussianBlur(image, blurred_image, cv::Size(5, 5), 0);

参数

**image:**要模糊的图像。

**blurred_image:**用于存储模糊后图像的 Mat 对象。

**kernel_size:**模糊核的大小。它必须是一个奇数。

**sigmaX:**高斯核在 x 方向的标准偏差。如果为 0,则从 kernel_size 计算。

注意

高斯模糊是一种线性滤波器,它使用高斯核来平滑图像。

高斯核是一个钟形曲线,其中心权重最大,边缘权重逐渐减小。

kernel_size 越大,模糊效果越强。

sigmaX 越大,模糊效果越明显。

高斯模糊可能会导致图像质量下降,尤其是边缘和细节丢失。

4、完整代码:

#include <iostream>
#include "opencv2/core.hpp"
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core/mat.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

int main(){
    Mat image;
    image = imread("firefox.png");      //imread()读取图片
    if(!image.empty()){
        namedWindow("image", cv::WINDOW_NORMAL);
        imshow("image",image);              //imshow展示图片,前面为展示名,后面为图片。
        resizeWindow("image", 640, 480);
        waitKey(0);
    }
    // destroyAllWindows();

    Mat resize_image;
    resize(image, resize_image, Size(), 1, 0.5);     //resize()改变大小 前为高度 后为宽度

    if(!resize_image.empty()){
        namedWindow("resize", cv::WINDOW_NORMAL);
        imshow("resize",resize_image);             
        resizeWindow("resize", 640, 480);
        waitKey(0);
    }
    imwrite("resize.png",resize_image);     //imwrite(文件名,图片)写入文件   需要指定扩展名,否则exception
    // destroyAllWindows(); 

    Mat rotated_image;
	
    double angle = 90;                                               //旋转角度
	Point2f center(image.cols / 2.0, image.rows / 2.0);              //获取旋转中心
	Mat rotation_matix = getRotationMatrix2D(center, angle, 0.5);    //getRotationMatrix2D()计算旋转矩阵 参数:旋转中心、旋转角度、放大倍数
	warpAffine(image, rotated_image, rotation_matix, image.size());  //warpAffine旋转图片  参数:原图、目标图片、旋转矩阵、生成图片的大小


    if(!rotated_image.empty()){
        namedWindow("rotate", cv::WINDOW_NORMAL);
        imshow("rotate",rotated_image);    
        resizeWindow("rotate", 640, 480);         
        waitKey(0);
    }
    imwrite("rotate.png",rotated_image);   
    // destroyAllWindows(); 


    Mat translated_image;                    
    float tx = float(image.rows) / 4;                           //平移距离 1/4 
    float ty = float(image.cols) / 4;                           //平移距离 1/4 
    float warp_values[] = { 1.0, 0.0, tx, 0.0, 1.0, ty };       //构建平移矩阵
    Mat translation_matrix = Mat(2, 3, CV_32F, warp_values);    //构建平移矩阵
    warpAffine(image, translated_image, translation_matrix, image.size());   //warpAffine平移图片


    if(!translated_image.empty()){
        namedWindow("translated", cv::WINDOW_NORMAL);
        imshow("translated",translated_image); 
        resizeWindow("translated", 640, 480);               
        waitKey(0);
    }
    imwrite("translated.png",translated_image);   
    destroyAllWindows(); 

    Mat flipped_image_row;
    Mat flipped_image_col;
    
    flip(image, flipped_image_row, 1); //水平翻转
    flip(image, flipped_image_col, 0); //垂直翻转
    
    imshow("row",flipped_image_row);
    imshow("col",flipped_image_col);
    imshow("image",image);
    waitKey(0);
    destroyAllWindows(); 

    Mat blurred_image;
    GaussianBlur(image, blurred_image, cv::Size(99,99), 0);
    imshow("blurred_image",blurred_image);
    waitKey(0);
    destroyAllWindows(); 
    return 0;
}

简单四宫格:

#include <opencv2/core/mat.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

using namespace cv;

int main(){
    Mat image = imread("firefox.png");
    // Mat image_45;
    Mat image_90;
    Mat image_180;
    Mat image_270;

    // double angle_45 = 45;
    double angle_90 = 90;   
    double angle_180 = 180;
    double angle_270 = 270;                                            
	
    Point2f center(image.cols / 2.0, image.rows / 2.0);              
	// Mat rotation_matix_45 = getRotationMatrix2D(center, angle_45, 1.0);    
	// warpAffine(image, image_45, rotation_matix_45, image.size()); 

	Mat rotation_matix_90 = getRotationMatrix2D(center, angle_90, 1.0);    
	warpAffine(image, image_90, rotation_matix_90, image.size()); 

    Mat rotation_matix_180 = getRotationMatrix2D(center, angle_180, 1.0);    
	warpAffine(image, image_180, rotation_matix_180, image.size()); 

    Mat rotation_matix_270 = getRotationMatrix2D(center, angle_270, 1.0);    
	warpAffine(image, image_270, rotation_matix_270, image.size()); 

    Mat row_1;
    Mat row_2;
    Mat image_4x4;
    hconcat(std::vector<cv::Mat>{image, image_90},row_1);                 //横向拼接
    hconcat(std::vector<cv::Mat>{image_270, image_180},row_2);            //纵向拼接
    vconcat(std::vector<cv::Mat>{row_1, row_2},image_4x4);
    imshow("4x4",image_4x4);
    waitKey(0);
    destroyAllWindows();

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大学生选择算法向还是嵌入式向?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「嵌入式的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 由于嵌入式的薪资待遇和…

【oracle】Oracle RAC中的GNS到底是什么?

本文为云贝教育 刘峰 原创&#xff0c;请尊重知识产权&#xff0c;转发请注明出处&#xff0c;不接受任何抄袭、演绎和未经注明出处的转载 一、概述 Oracle Grid Naming Service (GNS) 是Oracle Grid Infrastructure的一个重要组件&#xff0c;它提供了一种集中式的命名服务&…

33 mid 55. 跳跃游戏

贪心算法&#xff1a; class Solution {public boolean canJump(int[] nums) {int leftBorder 0;for (int i 0; i <nums.length; i) {if(i<leftBorder){leftBorderMath.max(leftBorder,inums[i]);}if(leftBorder>nums.length-1){return true;}}return false;} }

元宇宙vr科普馆场景制作引领行业潮流

在这个数字化高速发展的时代&#xff0c;北京3D元宇宙场景在线制作以其独特的优势&#xff0c;成为了行业内的创新引领者。它能够快速完成空间设计&#xff0c;根据您的个性化需求&#xff0c;轻松设置布局、灯光、音效以及互动元素等&#xff0c;为您打造出一个更加真实、丰富…

TCP—三次握手和四次挥手

目录 一、三次握手和四次挥手的目的 二、TCP可靠的方面 三、什么是三次握手 四、第三次握手的目的 五、什么是四次挥手 六、超时时间的目的 七、SYN包、ACK包、FIN包 八、解决丢包和乱序 九、参考资料 一、三次握手和四次挥手的目的 TCP三次握手的目的主要是为了确保两…

谷歌地图 | Google I/O ‘24 重磅发布助力企业拓展海外市场的新功能!

编者按&#xff1a;本文是 Google I/O 2024 系列的一部分&#xff0c;该系列分享了Google 年度开发者大会上最新的 Google Maps Platform 新闻。 距全球首个 Google Maps API 问世已近 20 年。它引领了网络和移动端地理空间体验的革命。从那时起&#xff0c;Google Maps Platf…

Common Lisp笔记

在计划学习函数式编程的时候&#xff0c;我一开始打算学习的是 F#。因为我朋友就是在 DTU 上的学&#xff0c;F# 就是 DTU&#xff08;丹麦理工&#xff09;开发的。但是由于 F# 和微软的 .NET 绑定&#xff0c;而在 macOS 上&#xff0c;目前版本的 .NET 的是有些问题的&#…

2023年平均工资公布!你是什么段位?

来源国家统计局&#xff08;下同&#xff09; 01 城镇非私营单位就业人员年平均工资情况 2023年&#xff0c;全国城镇非私营单位就业人员年平均工资为120698元&#xff0c;比上年增加6669元&#xff0c;名义增长5.8%&#xff0c;扣除价格因素实际增长5.5%。 2014-2023年城镇非私…

基于FPGA实现LED的闪烁——HLS

基于FPGA实现LED的闪烁——HLS 引言&#xff1a; ​ 随着电子技术的飞速发展&#xff0c;硬件设计和开发的速度与效率成为了衡量一个项目成功与否的关键因素。在传统的硬件开发流程中&#xff0c;工程师通常需要使用VHDL或Verilog等硬件描述语言来编写底层的硬件逻辑&#xff0…

Pytorch深度学习实践笔记12(b站刘二大人)

&#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;pytorch深度学习 &#x1f380;CSDN主页 发狂的小花 &#x1f304;人生秘诀&#xff1a;学习的本质就是极致重复! 《PyTorch深度学习实践》完结合集_哔哩哔哩_bilibi…

锐捷网络与您相约第七届数字中国建设峰会 共话数字未来

第七届数字中国建设峰会将于5月24日至25日在福建福州举办,本届峰会是国家数据工作体系优化调整后首次举办的数字中国建设峰会,主题是“释放数据要素价值,发展新质生产力”。作为行业领先的ICT基础设施及解决方案提供商,锐捷网络与福建省电子信息集团、星网锐捷,围绕“发展新质生…

newinit.sh挖矿攻击处理与规避方案

目录 攻击分析 恢复措施&#xff1a; 问题排查 攻击入口分析 预防 临时处理方案&#xff1a; 攻击分析 攻击者&#xff1a;职业黑客&#xff08;99%&#xff09; 攻击方式&#xff1a;挖矿病毒newinit.sh和蠕虫病毒pnscan 中毒现象: 服务器负载异常&#xff0c;具体表…

06_知识点总结(JS高级)

一、进程与线程 1. 进程(process)&#xff1a;程序的一次执行, 它占有一片独有的内存空间 2. 线程(thread)&#xff1a; 是进程内的一个独立执行单元&#xff0c;CPU的基本调度单元, 是程序执行的一个完整流程 3. 进程与线程 * 应用程序必须运行在某个进程的某个线程上 * 一个…

反射、类加载、静态代理,jdk动态代理,cglib代理

一、 反射 反射是在程序运行状态下&#xff0c;动态获取类的结构&#xff08;属性&#xff0c;构造器&#xff0c;方法&#xff0c;注解&#xff09;&#xff0c;动态的创建类对象然后调用类中的属性方法。反射的起源Class&#xff0c;Class中包含类反射要使用的API 获取Class的…

【LeetCode】【2】两数相加(1411字)

文章目录 [toc]题目描述样例输入输出与解释样例1样例2样例3 提示Python实现模拟 个人主页&#xff1a;丷从心 系列专栏&#xff1a;LeetCode 刷题指南&#xff1a;LeetCode刷题指南 题目描述 给两个非空的链表&#xff0c;表示两个非负的整数&#xff0c;它们每位数字都是按…

大模型的发展方向:让大模型感知人类所处的物理世界,文字、听、看、闻、触摸、动手操作等信息接收和输出能力,向物理世界学习 大模型开发者方向

大模型的发展方向非常广泛&#xff0c;除了让大模型感知人类所处的物理世界&#xff0c;通过文字、听觉、视觉、嗅觉、触觉和动手操作等信息接收能力&#xff0c;还包括以下几个重要的方向&#xff1a; 多模态学习与融合&#xff1a; 多模态感知&#xff1a;整合来自不同感知渠…

neo4j详细安装教程

前言 最近开始学习知识图谱&#xff0c;现整理Neo4j的详细安装教程&#xff0c;Neo4j是一个高性能的,NOSQL图形数据库&#xff0c;它将结构化数据存储在网络上而不是表中。由于知识图谱中存在大量的关系型信息&#xff08;实体—关系—实体&#xff09;, 使用结构化数据库进行存…

SpringBoot + Redis实现对接口的限流

目录 前言 什么是限流&#xff1f; 实现限流 创建一个注解类 接着创建一个切面类 前言 在项目中&#xff0c;对于接口的限流&#xff0c;是任何项目都必不可少的一部分&#xff0c;主要是为了防止用户频繁的发送请求&#xff0c;对服务器造成压力。 另外一点就是防止外来攻…

Android USB调试模式下自动上下滑动(Go实现)

简介 有的时候要对手机UI界面进行滑动测试&#xff0c; 手动或许太消耗时间&#xff0c; 理由Android USB调试模式对UI进行上下滑动测试。 adb指令 使用adb --help 可以查看所有的adb支持指令, 但这里我们只需要上下, 使用到的指令&#xff1a; adb devices #列举所有设备 ad…

AI Agent教育行业落地案例

【AI赋能教育】揭秘Duolingo背后的AI Agent&#xff0c;让学习更高效、更有趣&#xff01; ©作者|Blaze 来源|神州问学 引言 随着科技的迅猛发展&#xff0c;人工智能技术已经逐步渗透到我们生活的各个方面。而随着AI技术的广泛应用&#xff0c;教育培训正引领着一场新的…