OpenCV 遍历Mat,像素操作,使用TrackBar 调整图像的亮度和对比度 C++实现

文章目录

    • 1.使用C++遍历Mat,完成颜色反转
      • 1.1 常规遍历方式
      • 1.2 迭代器遍历方式
      • 1.3指针访问方式遍历(最快)
      • 1.4不同遍历方式的时间对比
    • 2.图像像素操作,提高图像的亮度
    • 3.TrackBar 进度条操作
      • 3.1使用TrackBar 调整图像的亮度
      • 3.2使用TrackBar 调整图像的对比度

1.使用C++遍历Mat,完成颜色反转

首先先看Mat 构成方式,以彩色图像三通道为例,在内存排布是顺序排布,因此可以很高效地遍历Mat的每一个像素点,遍历方式为先遍历行再遍历列

在这里插入图片描述

1.1 常规遍历方式

先遍历行再遍历列,取出的值是一个三通道 无符号整形8位的数据 值的范围代表0-255,OpenCV提供了Vec3b来存储,本质上可以理解为在同一块内存区域,连续存放方式。

for (int j = 0; j < h; ++j) {  // 正确的行(高度)索引for (int i = 0; i < w; ++i) {  // 正确的列(宽度)索引if (c == 1) {// 单通道,灰度图像uchar pv = image.at<uchar>(j, i);image.at<uchar>(j, i) = 255 - pv;} else if (c == 3) {// 三通道,BGR 数据 三个值Vec3b pv_rgb = image.at<Vec3b>(j, i);pv_rgb[0] = 255 - pv_rgb[0];pv_rgb[1] = 255 - pv_rgb[1];pv_rgb[2] = 255 - pv_rgb[2];image.at<Vec3b>(j, i) = pv_rgb;}}}

1.2 迭代器遍历方式

OpenCV 提供了Mat的迭代器,好处是比较安全。迭代器隐藏了内部的行跨距(step size),使得代码更易读。

 for (cv::MatIterator_<cv::Vec3b> it = image.begin<cv::Vec3b>(); it != image.end<cv::Vec3b>(); ++it) {cv::Vec3b& pixel = *it;  // 引用当前像素// 访问 B, G, R 通道uchar blue = pixel[0];uchar green = pixel[1];uchar red = pixel[2];pixel[0] = 255- blue;pixel[1] = 255- green;pixel[2] = 255- red;// 对像素值进行操作// pixel[0] = new_blue;// pixel[1] = new_green;// pixel[2] = new_red;}

1.3指针访问方式遍历(最快)

指针无需多言,快就完了

//基于指针的方式 最快start =  std::chrono::steady_clock::now();// 遍历所有行for (int i = 0; i < image.rows; i++) {// 获取行指针Vec3b* row = image.ptr<Vec3b>(i);for (int j = 0; j < image.cols; j++) {// 访问像素,row[j] 是 Vec3b 类型,表示一个BGR像素row[j][0] = 255 - row[j][0]; // Brow[j][1] = 255 - row[j][1]; // Grow[j][2] = 255 - row[j][2]; // R}}end = std::chrono::steady_clock::now();nanoseconds = calculateTimeDifferenceInNanoseconds(start, end);std::cout << "ptr during:" << nanoseconds << " us." << std::endl;

1.4不同遍历方式的时间对比

在同一张图片在每次遍历完成之后,计算开始时间与结束时间差异可以得到以下时间对比。可以看出指针方式遍历只需3ms左右,常规for循环需要8ms左右,而迭代器迭代的方式需要16ms 左右,最慢

在这里插入图片描述

2.图像像素操作,提高图像的亮度

这一块操作较为简单,OpenCV的Mat类,重载大多数的运算符,使得图像像素加减操作如同整数加减一样简单,简单代码示意

void pixel_operator(Mat &image){Mat dst;imshow("orig img",image);dst = image + Scalar (50,50,50);imshow("orig plus img",dst);dst = image - Scalar (100,100,100);imshow("orig minus img",dst);waitKey(0);destroyAllWindows();
}

Scalar可以提供RGB三通道数据。 当R G B 三种像素都增大的时候,图像的整体亮度就会得到增强,反之,图像的整体亮度就减弱。

效果示意,左上角为原始图像,右上角为图形亮度减弱的图像,中间的图像为图像亮度增强的效果

在这里插入图片描述

3.TrackBar 进度条操作

3.1使用TrackBar 调整图像的亮度

在OpenCV中,TrackBar是一种在窗口中添加交互式滑动条的工具,可以用来动态调整图像处理参数。使用TrackBar可以方便地调试和调整图像处理算法。

示例代码

#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;
//全局变量
Mat src, dst;
int lightness;// TrackBar回调函数
static void on_track(int, void*) {Mat m = Scalar(lightness, lightness, lightness);add(src, m, dst);  // 基于原始图像 src 进行亮度调整imshow("lightness adjust", dst);
}// TrackBar示例函数
void tracking_bar_demo(Mat& image) {namedWindow("lightness adjust", WINDOW_AUTOSIZE);  // 创建窗口int max_val = 100;lightness = 50;src = image.clone();  // 保留原始图像dst = Mat::zeros(image.size(), image.type());  // 初始化调整后的图像createTrackbar("Value Bar:", "lightness adjust", &lightness, max_val, on_track);on_track(lightness, 0);  // 初始化显示
}int main() {// 读取图像Mat image = imread("your_image_path.jpg", IMREAD_COLOR);if (image.empty()) {cout << "Could not open or find the image!" << endl;return -1;}// 调用TrackBar示例函数tracking_bar_demo(image);// 事件循环while (true) {int key = waitKey(30);if (key == 27) {  // 按下ESC键退出break;}}return 0;
}

代码解读

读取和转换图像

  • 使用imread读取图像,并检查图像是否成功加载。

创建窗口和TrackBar

  • 使用namedWindow创建一个窗口并显示初始的灰度图像。
  • 使用createTrackbar在窗口中创建一个TrackBar。参数包括TrackBar的名称、窗口名称、指向变量的指针、最大值和回调函数

回调函数 on_trackbar(int, void\*)

  • 当TrackBar的值发生变化时,OpenCV会调用这个函数。然后会把原图像加上新的变化的像素值,然后在窗口中显示变化的图像

代码改进:

分析TrackBar 的构造函数

CV_EXPORTS int createTrackbar(const String& trackbarname, const String& winname,int* value, int count,TrackbarCallback onChange = 0,void* userdata = 0);

在创建TrackBar的时候,还可以传入的void*的用户数据,回调函数也可以接受变化的值和用户数据

因此,可以直接通过指针传递的方式,不需要再创建全局变量

改进后:直接将图像数据传递进回调函数,无需再拷贝一份图像数据,无需其他变量,修改之后直接进行显示。

//track bar UI改动的回调函数
static void on_track(int val,void* userdata){imshow("lightness adjust", *(Mat*)userdata+Scalar (val,val,val));
}
void tracking_bar_demo(Mat &image){namedWindow("lightness adjust",WINDOW_AUTOSIZE);int max_val = 100;int lightness = 50;createTrackbar("Value Bar:","lightness adjust",&lightness,max_val,on_track,&image);on_track(lightness, &image);  // 初始化值
}

效果如图:

在这里插入图片描述

3.2使用TrackBar 调整图像的对比度

对比度是图像处理中一个非常重要的概念,它描述了图像中明暗区域之间的差异程度。具体来说,对比度反映了图像中最亮和最暗部分的亮度差异。对比度越高,图像中的明暗差异越明显;对比度越低,图像看起来越平淡、灰暗。通俗的讲,让亮的地方更亮,暗的地方更暗,使得差异更大。

在技术上,对比度可以定义为图像中像素值的范围。对于灰度图像,对比度可以用最大亮度和最小亮度之差来表示:

对比度=最大亮度−最小亮度

在彩色图像中,对比度通常是三个颜色通道(红、绿、蓝)的平均值。

对比度对于图像的视觉效果和信息传达有很大影响。适当的对比度可以使图像更加清晰、细节更加突出,增强视觉吸引力;而不合适的对比度可能会导致图像细节丢失或难以辨认。

对比度可以通过多种方法进行调整,常见的方法包括:

  1. 线性变换

    • 对图像中的每个像素值进行线性变换,使得亮度值范围变大或变小。

    • 公式:
      n e w p i x e l = c o n t r a s t × o r i g i n a l p i x e l + b r i g h t n e s s new pixel=contrast×original pixel+brightness newpixel=contrast×originalpixel+brightness

    其中,contrast 是对比度系数,brightness 是亮度偏移量。

  2. 直方图均衡化

    • 通过调整图像的灰度直方图,使得像素值分布更加均匀,从而增强对比度。
  3. 伽马校正

    • 伽马矫正(Gamma Correction)是用来针对影片或影像系统里对于光线的辉度(luminance)或是三色刺激值(tristimulus values)所进行非线性的运算或反运算。其公式一般为幂定律公式

这里使用最简单的方式 线性变换来实现调整对比度

示例代码:

Mat src, dst;
int contrast = 50;
int brightness = 50;// TrackBar回调函数
static void on_trackbar(int, void*) {double alpha = contrast / 50.0; // 对比度系数(范围:0.0 - 2.0)int beta = brightness - 50;     // 亮度偏移量(范围:-50 - 50)src.convertTo(dst, -1, alpha, beta); // 进行对比度和亮度调整imshow("Adjust Contrast and Brightness", dst);
}// TrackBar示例函数
void tracking_bar_demo(Mat &image) {namedWindow("Adjust Contrast and Brightness", WINDOW_AUTOSIZE);src = image.clone();dst = Mat::zeros(image.size(), image.type());// 创建对比度和亮度调节的TrackBarcreateTrackbar("Contrast", "Adjust Contrast and Brightness", &contrast, 100, on_trackbar);createTrackbar("Brightness", "Adjust Contrast and Brightness", &brightness, 100, on_trackbar);on_trackbar(0, 0); // 初始化显示
}
int main()
{string imagePath = "C:\\Users\\Marxist\\Pictures\\coco\\test.jpg";Mat image = imread(imagePath);if(image.empty()){cout<<"file not exist!"<<endl;return -1;}//pixel_operator(image);imshow("src image",image);tracking_bar_demo(image);// 事件循环while (true) {int key = waitKey(30);if (key == 27) {  // 按下ESC键退出break;}}return 0;
}

关键函数:convertTo ,用于将一个矩阵转换为另一个矩阵,支持不同的类型和缩放操作。它的主要用途是进行图像类型转换和数值转换,通常用于调整图像的对比度和亮度。

函数定义:

void convertTo(OutputArray m, int rtype, double alpha=1, double beta=0) const;

参数详解

  • OutputArray m: 输出矩阵或图像。可以是与输入矩阵类型相同或不同的类型。
  • int rtype: 输出矩阵的类型(例如 CV_8UCV_32F 等)。如果为 -1,表示输出矩阵类型与输入矩阵相同。
  • double alpha: 可选的缩放因子(乘法因子)。默认为 1。
  • double beta: 可选的偏移量(加法因子)。默认为 0。

该函数执行以下转换:
d s t ( x , y ) = s r c ( x , y ) × α + β dst(x,y)=src(x,y)×α+β dst(x,y)=src(x,y)×α+β

  • 缩放(alpha):对输入矩阵中的每个元素进行缩放。
  • 偏移(beta):对缩放后的每个元素加上一个偏移量。

效果如图:

在这里插入图片描述

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

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

相关文章

学术研讨 | 区块链网络体系结构研讨会顺利召开

添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 近日&#xff0c;国家区块链技术创新中心组织了“区块链网络体系结构研讨会”&#xff0c;会议面向跨域交互多、计算规模大、数据管理复杂、性能与扩展性要求高等特征的区块链网络的体系结构展开交流研讨&…

docker相关内容学习

一、docker的四部分 二、镜像相关命令 三、容器相关命令

视频生成【文章汇总】SVD, Sora, Latte, VideoCrafter12, DiT...

视频生成【文章汇总】SVD, Sora, Latte, VideoCrafter12, DiT... 数据集指标 【arXiv 2024】MiraData: A Large-Scale Video Dataset with Long Durations and Structured Captions【CVPR 2024】VBench : Comprehensive Benchmark Suite for Video Generative Models【arxiv 20…

学习记录——day15 数据结构 链表

链表的引入 顺序表的优缺点 1、优点:能够直接通过下标进行定位元素&#xff0c;访问效率高&#xff0c;对元素进行查找和修改比较快 2、不足:插入和删除元素需要移动大量的元素&#xff0c;效率较低 3、缺点:存储数据元素有上限&#xff0c;当达到MAX后&#xff0c;就不能再…

[python]数字与字符串

目录 Python 数字类型转换 Python 数字运算 Python字符串操作 修改 查询 Python 数字数据类型用于存储数值。 数据类型是不允许改变的&#xff0c;这就意味着如果改变数字数据类型的值&#xff0c;将重新分配内存空间。 Python 支持三种不同的数值类型&#xff1a; 整型…

javafx的ListView代入项目的使用

目录 1. 创建一个可观察的列表&#xff0c;用于存储ListView中的数据,这里的User是包装了用户的相关信息。 2.通过本人id获取friendid&#xff0c;及好友的id&#xff0c;然后用集合接送&#xff0c;更方便直观一点。 3.用for遍历集合&#xff0c;逐个添加。 4.渲染器&…

文件包涵条件竞争(ctfshow82)

Web82 利用 session.upload_progress 包含文件漏洞 <!DOCTYPE html> <html> <body> <form action"https://09558c1b-9569-4abd-bf78-86c4a6cb6608.challenge.ctf.show//" method"POST" enctype"multipart/form-data"> …

grafana对接zabbix数据展示

目录 1、初始化、安装grafana 2、浏览器访问 3、安装zabbix 4、zabbix数据对接grafana 5、如何导入模板&#xff1f; ① 设置键值 ② 在zabbix web端完成自定义监控项 ③ garafana里添加nginx上面的的三个监控项 6、如何自定义监控项&#xff1f; 以下实验沿用上一篇z…

【React学习打卡第三天】

Redux快速上手、三个核心概念、React组件使用、修改store的数据、提交action传参、异步操作、Redux调试 一、Redux快速上手1.概念2.快速体验(纯redux计数案例&#xff09; 3.三个核心概念 二、Redux与React-环境准备1.配套工具2.配置基础环境3.store目录结构设计![在这里插入图…

SpringMvc有几个上下文

你好&#xff0c;我是柳岸花明。 SpringMVC作为Spring框架的重要组成部分&#xff0c;其启动流程和父子容器机制是理解整个框架运行机制的关键。本文将通过一系列详细的流程图&#xff0c;深入剖析SpringMVC的启动原理与父子容器的源码结构。 SpringMVC 父子容器 父容器的创建 …

数据结构初阶(c语言)-双向链表

这里首先纠正上篇文章一个错误&#xff0c;链表的一个有效数据点应该称为结点而不是节点。 一&#xff0c;双向链表的概念与结构 1.1概念与结构示意图 我们所说的双向链表全称为带头双向循环链表&#xff0c;也就是说此链表带有哨兵位结点(不存放任何数据的结点&#xff0c;且…

【Git多人协作开发】知识点总结

目录 知识点总结 1.创建dev分支开发 1.1在本地创建 1.1在远程创建&#xff08;推荐&#xff09; 2.远程分支和本地分支建立连接☞pull和push操作 2.1情况1 2.2情况2 2.3情况3 3.本地仓库对远程仓库的拉取pull操作 3.1情况1 3.2情况2 4.将开发分支的内容合并到远程m…

【Week-G5】适用于图像翻译的pix2pix模型-Pytorch版本

文章目录 1、基础知识1.1 图像翻译1.2 CGAN1.3 U-Net1.4 Pix2Pix 2、运行代码 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 本次主要学习Pix2Pix网络&#xff0c;常用于图像翻译&#…

CVE-2020-7248 OpenWRT libubox标记二进制数据序列化漏洞(更新中)

提要 该文档会一直处于更新当中&#xff0c;当状态为完毕后&#xff0c;才是更新完成。由于网络上关于该漏洞原理的分析文档和资源实在是太少&#xff0c;而本人关于该方向也才是刚入门&#xff0c;能力有限&#xff0c;所以复现需要的时间较长&#xff0c;需要补充和学习的东西…

用Manim实现【多边形】类的实现——[上]

用Manim实现【多边形】类的实现——[上] Polygram内容是关于不同几何图形的分类&#xff0c;特别是涉及多边形&#xff08;Polygon&#xff09;及其扩展形式&#xff0c;比如多图形&#xff08;Polygram&#xff09;。在manim中有10中特征&#xff0c;接下来5种类及其特征的解…

搜维尔科技:Cyber​​glove通过其前所未有的柔性传感器技术,带来了多年的经验、专业知识和可靠性

Cyberglove 概述 新一代数据手套技术 MoCap 手套采用了原始 CyberGlove 产品 20 年经验所建立的技术&#xff0c;产生了改进的和新的特性、能力和设计&#xff0c;非常适合动作捕捉环境。 旧与新相遇&#xff0c; Cyberglove 通过其前所未有的柔性传感器技术&#xff0c;带来…

linux自动化构建工具--make/makefile

目录 1.make/makefile介绍 1.1基本认识 1.2依赖关系、依赖方法 1.3具体操作步骤 1.4进一步理解 1.5默认设置 1.6make二次使用的解释 1.7两个文件的时间问题 1.8总是被执行 1.9特殊符号介绍 1.make/makefile介绍 1.1基本认识 make是一个指令&#xff0c;makefile是一…

mysql面试(六)

前言 本章节详细讲解了一下mysql执行计划相关的属性释义&#xff0c;以及不同sql所出现的不同效果 执行计划 一条查询语句经过mysql查询优化器的各种基于成本和各种规则优化之后&#xff0c;会生成一个所谓的 执行计划&#xff0c;这个执行计划展示了这条查询语句具体查询方…

django 小型超市库存与销售管理系统-计算机毕业设计源码46608

摘 要 随着信息技术的快速发展&#xff0c;超市库存与销售管理面临着前所未有的挑战与机遇。为了提升超市的运营效率&#xff0c;优化库存管理&#xff0c;并增强销售数据的分析能力&#xff0c;我们基于Django框架设计并开发了一套小型超市库存与销售管理系统。该系统充分利用…

运算符的运算顺序

【单目算术位关系&#xff0c;逻辑三目后赋值】 ![在这里插入图片描述] (https://i-blog.csdnimg.cn/direct/e4c8f4e22b5044a48154bf7378e3b3b3.png)