C++ opencv TrackBar的使用修改图像亮度、对比度
文章目录
TrackBar
本文头文件及命名空间:
#pragma once
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
TackBar即滑动条,可以按照需求动态调整图像,如调整图像的亮度、对比度、某一通道的像素值等。
在图像显示中添加滑动条,需要使用两个函数: 1. 创建滑动条 createTrackBar() 2. 回调函数 TrackbarCallback()
创建滑动条
trackbarname :滑动条的名称
winname : 显示图像的窗口名
value : 滑动条的初始值,int指针
count : 滑动条的最大值
onChange : 回调函数
userdata : 无类型的指针,一般为图像,Mat对象的指针
回调函数:
pos : 滑动条当前的取值
userdata : 创建滑动条传入的对象,即无类型的指针
使用滑动条,需要将两函数配合使用。
创建滑动条与回调函数类似信号与槽,滑动条创建后,改变滑动条位置,会自动调用回调函数。
滑动条默认从0开始,范围到输入的最大值
回调函数的对象是无类型的指针,使用时需要转为对应类型。
单个TrackBar
当只有单个TrackBar时,可以使用传参的方法。此时TrackBar需要传入Mat对象的指针,回调函数需要使用传入的指针参数,来对图像操作。
修改图像的对比度与亮度,可以使用convertTo完成。
回调函数中,新创建的Mat对象dst一定要是深拷贝,浅拷贝只复制矩阵头部,dst一旦修改,src也会被修改。
测试代码:
//回调函数1,使用主函数的局部变量,使用了传入的参数
void mytrackBarCallback(int pos, void* userdata) {
//将无类型指针转为Mat类型指针
Mat* user = (Mat*)userdata;
//创建新的Mat对象存放结果,在原始图像的直接操作会累积,产生意外结果
Mat dst ;
//调整对比度
(* user).convertTo(dst, -1, pos * 0.01);
imshow("image show", dst);
}
//trackBar测试
void trackbarTest() {
Mat src = imread(path, 1);
int start{10};
int Max{ 100 };
//创建窗口显示图像
namedWindow("image show", WINDOW_FREERATIO);
//创建trackBar,并设置起始值、回调函数
createTrackbar("改变对比度", "image show", &start, Max, mytrackBarCallback, &src);
//不调用一次回调函数,也不会影响结果
//mytrackBarCallback(100, &src);
//等待需要在主函数,在回调函数会无限等待,移动bar也没有效果
waitKey(0);
}
测试效果:
多个TrackBar
当需要分别修改图像的亮度与对比度时,要使用两个或多个TrackBar。也需要创建两个TrackBar。而TrackBar传参时,只能传入一个int指针类型参数,如果使用两个不同的回调函数分别传参,则会造成两个TrackBar互相无法联系,即修改亮度与对比度无法一起使用。
这里使用全局变量的方法,将需要传入的变量声明为全局变量,回调函数无需使用传入的参数。两个TrackBar使用同一个回调函数,实现对比度、亮度的同时修改。
测试代码:
//声明并定义全局变量
int colorStart{ 0 };
int contast{ 100 };
int colorMax{ 255 };
int contastMax{ 100 };
Mat srcBar = imread(path, 1);
//回调函数2,使用全局变量,不使用传入参数
void mytrackBarCallback2(int, void*) {
Mat dst;
srcBar.convertTo(dst, -1, contast * 0.01, colorStart);
imshow("image show", dst);
}
//trackBar测试
void trackbarTest() {
namedWindow("image show", WINDOW_FREERATIO);
//调整亮度的TrackBar
createTrackbar("亮度", "image show", &colorStart, colorMax, mytrackBarCallback2);
//调整对比度的TrackBar,他们使用同一个回调函数
createTrackbar("对比度", "image show", &contast, contastMax, mytrackBarCallback2);
waitKey(0);
}
测试结果:实现图像对比度和亮度的同时修改
网上也有使用传入参数和两个不同的回调函数实现图像对比度和亮度的同时调整,在回调函数中使用getTrackBarPos(),setTrackBar()来获取另一个TrackBar的pos值并修改。这种写法,需要事先声明回调函数,在主函数后在定义回调函数。
但测试后仍有问题,TrackBar的使用有先后,而TrackBar一旦使用便会调用自身的回调函数,自身的回调函数会去获取另一个还未使用的TrackBar的pos值,但由于第二个TrackBar还未使用,其本身还并不存在,会报错。即getTrackBarPos()报错,找不到对应TrackBar。
getTrackBarPos()只能获取已经使用的TrackBar的pos值。
测试代码:
//先声明
void mytrackBarCallback31(int pos, void* userdata);
void mytrackBarCallback32(int pos, void* userdata);
void trackbarTest() {
int bias{ 0 };
int alpha{ 100 };
int biasMax{ 255 };
int alphaMax{ 100 };
Mat mx = imread(path, 1);
namedWindow("image", WINDOW_FREERATIO);
//调整对比度的TrackBar
createTrackbar("alpha", "image", &alpha, alphaMax, mytrackBarCallback31 , &mx);
//调整亮度的TrackBar,他们使用不同回调函数
createTrackbar("bias", "image", &bias, biasMax, mytrackBarCallback32 , &mx);
waitKey(0);
}
void mytrackBarCallback31(int pos, void* userdata) {
Mat* user = (Mat*)userdata;
//创建新的Mat对象存放结果,在原始图像的直接操作会累积,产生意外结果
Mat dst;
//调整对比度
int bias = getTrackbarPos("bias", "image");
cout<<bias;
(*user).convertTo(dst, -1, pos * 0.01, bias);
imshow("image", dst);
}
void mytrackBarCallback32(int pos, void* userdata) {
Mat* user = (Mat*)userdata;
//创建新的Mat对象存放结果,在原始图像的直接操作会累积,产生意外结果
Mat dst;
//调整对比度
int alpha = getTrackbarPos("alpha", "image");
(*user).convertTo(dst, -1, alpha * 0.01,pos);
imshow("image", dst);
}
内容有误或可更改的部分,私信我,看到及时修改。