W1-Trackbar

W1-Trackbar

createTrackbar简介

  • 大多数时候,图像处理的效果与其输入参数是密不可分的,当输入参数较多时,我们不可能通过一次次修改源代码来达到预期效果,所以OpenCV提供了一个很方便的函数createTrackbar。createTrackbar可以在图像显示窗口上创建一个滑块,通过改变滑块的位置来改变图像处理参数,进而直观调整图像处理效果。

createTrackbar函数应用分析

  • 函数定义如下
CV_EXPORTS int createTrackbar(const String& trackbarname, const String& winname,int* value, 
                              int count, TrackbarCallback onChange = 0, void* userdata = 0);
  • 参数说明如下

@param trackbarname Name of the created trackbar.
@param winname Name of the window that will be used as a parent of the created trackbar.
@param value Optional pointer to an integer variable whose value reflects the position of the slider. Upon creation, the slider position is defined by this variable.
@param count Maximal position of the slider. The minimal position is always 0.
@param onChange Pointer to the function to be called every time the slider changes position. This function should be prototyped as void Foo(int,void*); , where the first parameter is the trackbar position and the second parameter is the user data (see the next parameter). If the callback is the NULL pointer, no callbacks are called, but only value is updated.
@param userdata User data that is passed as is to the callback. It can be used to handle trackbar events without using global variables.

  • 从上面说明翻译过来就是
    • trackbarname:为创建的trackbar取个名字
    • winname :trackbar所要添加到窗口的名字
    • value : 这是一个整形指针,该指针的值和trackbar的位置是紧密联系的。当trackbar位置改变时,value的值也会作相应改变,同样当value的值改变时,trackbar的位置也会随之改变。
    • count :trackbar位置拉满时value对应的最大值,并且value的值始终在0-count之间。
    • onChange :这个参数是回调函数,当trackbar位置改变时,就会自动调用该回调函数,然后对图像做相应处理,该函数需要自己定义。参数的数据类型是TrackbarCallback 。其定义如下。
typedef void (*TrackbarCallback)(int pos, void* userdata);

所以该函数的输入参数pos就是接收value的值,userdata是接收图像数据,具体使用可以看下面的例子。

    • userdata:该参数其实就是接收原图像数据,虽然定义的是void*类型的参数,可以接收任何类型指针变量,但在OpenCV中,大多都是传入的图像数据。

  • 总结一下就是,要想利用trackbar来改变图像效果我们需要做的工作是:
  1. 给trackbar一个名字
  2. 创建好一个图像窗口,并给出图像窗口名
  3. 定义一个变量,用以时刻反映trackbar位置
  4. 指定3.反映trackbar位置的变量的最大值
  5. 定义一个回调函数,在tackbar位置改变时做相应处理
  6. 传入图像数据
  • 熟悉一下上面的这6步,在后面我们会按照这6步来编写程序。

应用示例

  • 以whiteFace函数为例,说明一下如何使用createTrackbar函数改变图像处理效果。源代码如下:
#include <iostream>
#include <opencv2\opencv.hpp>

using namespace cv;
using namespace std;

void whiteFace(Mat& matselfPhoto, int alpha, int beta)
{
    
    
	for (int y = 0; y < matselfPhoto.rows; y++)
	{
    
    
		for (int x = 0; x < matselfPhoto.cols; x++)
		{
    
    
			for (int c = 0; c < 3; c++)
			{
    
    
				matselfPhoto.at<Vec3b>(y, x)[c] = saturate_cast<uchar>(alpha*(matselfPhoto.at<Vec3b>(y, x)[c]) + beta);
			}
			
		}
	}
}

int main()
{
    
    
    Mat src = imread("F:/image/beautifulface.jpg", 1);//读取图像数据,储存在src中
	imshow("0", src);//显示图像
	whiteFace(src, 1.1, 68);  // 调整对比度与亮度,参数2为对比度,参数3为亮度
	imshow("0_c", src);
    keyWait(0);
 }
  • 上面的程序运行结果如下。
    在这里插入图片描述
  • 可以看出,处理后的人脸显示得比没处理的要白。那么如何利用createTrackbar函数动态改变图像处理效果呢?在此之前我们需要先来看看whiteFace函数,函数声明如下。
void whiteFace(Mat& matselfPhoto, int alpha, int beta)
  • 可以看出,该函数有3个输入参数,第一个输入参数matselfPhoto,用以接收原图像数据,也就是上面代码中的src;第二个输入参数alpha用以改变图像对比度,这个参数会影响到图像效果;第三个输入参数beta用以改变图像亮度,这个参数同样会影响到图像效果。
  • 所以whiteFace中有两个参数会影响到图像效果,但是一个trackbar只能改变1个参数,所以我们就需要创建两个trackbar,按照前面所说的6个步骤,一步步编写代码。
  1. 先给这两个trackbar函数起一个名字,这里分别命名为“whiteFace_param1”和“whiteFace_param2”,如下所示。
int main()
{
    
    
	createTrackbar("whiteFace_param1",,,,,);
	createTrackbar("whiteFace_param2",,,,,);
}
  1. 创建一个窗口,并将该trackbar添加到图像窗口上。所以我们首先要读入图像数据,并显示出来,这里将窗口命名为“0”。然后将窗口名作为createTrackbar的第二个输入参数。代码如下。
int main()
{
    
    
	Mat src = imread("F:/image/beautifulface.jpg", 1);
	imshow("0", src);
	createTrackbar("whiteFace_param1","0",,,,);
	createTrackbar("whiteFace_param2","0",,,,);
}
  1. 定义一个变量,该变量可以反映trackbar的位置。为了增强代码的可读性,这里将两个变量作如下定义。
	int whiteFace_param1 = 1;
	int whiteFace_param2 = 68;
int main()
{
    
    
	int whiteFace_param1 = 1;
	int whiteFace_param2 = 68;
	Mat src = imread("F:/image/beautifulface.jpg", 1);
	imshow("0", src);
	createTrackbar("whiteFace_param1","0",&whiteFace_param1,,,);
	createTrackbar("whiteFace_param2","0",&whiteFace_param2,,,);
}
  • 这里将这两个函数的定义写到了main函数里,但是这样写其实是有问题的,在下面会提到,并做出修改。
  1. 指定两个trackbar对应的最大值。这里分别为10和100。代码如下
int main()
{
    
    
	int whiteFace_param1 = 1;
	int whiteFace_param2 = 68;
	Mat src = imread("F:/image/beautifulface.jpg", 1);
	imshow("0", src);
	createTrackbar("whiteFace_param1","0",&whiteFace_param1,10,,);
	createTrackbar("whiteFace_param2","0",&whiteFace_param2,100,,);
}
  1. 定义回调函数,trackbar位置变动时,上面的whiteFace_param1或whiteFace_param2会相应做更改,并调用该回调函数。为了显示出更改效果,那么回调函数中仅需要两个步骤,一是调用whiteFace()函数,二是调用imshow()函数显示图像更改效果。那么相应代码如下
void cb_whiteFace_param1(int pos,void* userdata)
{
    
    
	whiteFace(*(Mat *)userdata,pos, whiteFace_param2);
	imshow("0_c", *(Mat *)userdata);
}

上面代码其实存在两个问题,第一个就是我们上面提到的变量定义

	int whiteFace_param1 = 1;
	int whiteFace_param2 = 68;

我们将这两个变量定义到了main函数中,但是回调函数cb_whiteFace_param1并不在main函数中,所以在main函数定义的变量是没有办法在cb_whiteFace_param1中引用的,所以就需要将这两个函数定义为全局变量,修改后代码如下

int whiteFace_param1 = 1;
int whiteFace_param2 = 68;
void cb_whiteFace_param1(int pos,void* userdata)
{
    
    
	whiteFace(*(Mat *)userdata,pos, whiteFace_param2);
	imshow("0_c", *(Mat *)userdata);
}

int main()
{
    
    
	Mat src = imread("F:/image/beautifulface.jpg", 1);
	imshow("0", src);
	createTrackbar("whiteFace_param1","0",&whiteFace_param1,10,,);
	createTrackbar("whiteFace_param2","0",&whiteFace_param2,100,,);
}

但还存在另一个致命问题,就是在cb_whiteFace_param1()中,whiteFace输入参数是userdata的地址,也就是src的地址,这样相应地,当调用whiteFace()的时候,就会改变src的值,也就是改变原图像数据,这是我们非常不愿意看到的。所以就需要创建另一块存储空间来存放src的数据,避免直接更改src。所以修改后代码如下。

int whiteFace_param1 = 1;
int whiteFace_param2 = 68;

void cb_whiteFace_param1(int pos,void* userdata)
{
    
    
	Mat src = *(Mat *)(userdata);
	Mat src1 = src.clone();
	whiteFace(src1,pos, whiteFace_param2);
	imshow("0_c", src1);
}

int main()
{
    
    
	Mat src = imread("F:/image/beautifulface.jpg", 1);
	imshow("0", src);
	createTrackbar("whiteFace_param1","0",&whiteFace_param1,10,cb_whiteFace_param1,);
	createTrackbar("whiteFace_param2","0",&whiteFace_param2,100,cb_whiteFace_param2,);
}
  • 到这里回调函数就定义完了。
  1. 最后一步,将原图像数据传入createTrackbar()函数中。代码如下
int main()
{
    
    
	Mat src = imread("F:/image/beautifulface.jpg", 1);
	imshow("0", src);
	createTrackbar("whiteFace_param1","0",&whiteFace_param1,10,cb_whiteFace_param1,src);
	createTrackbar("whiteFace_param2","0",&whiteFace_param2,100,cb_whiteFace_param2,src);
}

  • 到这里,createtrackbar()函数的调用相关工作已经做完了。下面附上这部分完整代码。
#include <iostream>
#include <opencv2\opencv.hpp>

using namespace cv;
using namespace std;


void whiteFace(Mat& matselfPhoto, int alpha, int beta)
{
    
    
	for (int y = 0; y < matselfPhoto.rows; y++)
	{
    
    
		for (int x = 0; x < matselfPhoto.cols; x++)
		{
    
    
			for (int c = 0; c < 3; c++)
			{
    
    
				matselfPhoto.at<Vec3b>(y, x)[c] = saturate_cast<uchar>(alpha*(matselfPhoto.at<Vec3b>(y, x)[c]) + beta);
			}
			
		}
	}
}

int whiteFace_param1 = 1;
int whiteFace_param2 = 68;

void cb_whiteFace_param1(int pos,void* userdata)
{
    
    
	Mat src = *(Mat *)(userdata);
	Mat src1 = src.clone();
	whiteFace(src1,pos, whiteFace_param2);
	imshow("0_c", src1);
}

void cb_whiteFace_param2(int pos, void* userdata)
{
    
    
	Mat src = *(Mat *)(userdata);
	Mat src1 = src.clone();
	whiteFace(src1, whiteFace_param1, pos);
	imshow("0_c", src1);
}

int main()
{
    
    
	Mat src = imread("F:/image/beautifulface.jpg");
	imshow("0", src);
	createTrackbar("whiteFace_param1","0",&whiteFace_param1,10,cb_whiteFace_param1,&src);
	createTrackbar("whiteFace_param2", "0", &whiteFace_param2, 200, cb_whiteFace_param2, &src);
	waitKey(0);
	destroyAllWindows();
	return 0;
}
  • 运行结果如下
    在这里插入图片描述
  • 这样拖动两个trackbar就可以动态改变图像显示效果了。其余函数用trackbar函数动态显示就不一 一分析了,原理同上。下面附上全部代码。

完整源代码

#include <iostream>
#include <opencv2\opencv.hpp>

using namespace cv;
using namespace std;


void whiteFace(Mat& matselfPhoto, int alpha, int beta)
{
    
    
	for (int y = 0; y < matselfPhoto.rows; y++)
	{
    
    
		for (int x = 0; x < matselfPhoto.cols; x++)
		{
    
    
			for (int c = 0; c < 3; c++)
			{
    
    
				matselfPhoto.at<Vec3b>(y, x)[c] = saturate_cast<uchar>(alpha*(matselfPhoto.at<Vec3b>(y, x)[c]) + beta);
			}
			
		}
	}
}

int whiteFace_param1 = 1;
int whiteFace_param2 = 68;

void cb_whiteFace_param1(int pos,void* userdata)
{
    
    
	Mat src = *(Mat *)(userdata);
	Mat src1 = src.clone();
	whiteFace(src1,pos, whiteFace_param2);
	imshow("0_c", src1);
}

void cb_whiteFace_param2(int pos, void* userdata)
{
    
    
	Mat src = *(Mat *)(userdata);
	Mat src1 = src.clone();
	whiteFace(src1, whiteFace_param1, pos);
	imshow("0_c", src1);
}



int gaussiBlur_param1 = 0;
int gaussiBlur_param2 = 0;

void cb_gaussiBlur_param1(int pos, void* userdata)
{
    
    
	Mat src = *(Mat *)(userdata);
	Mat src1 = src.clone();
	GaussianBlur(src1, src1, Size(9, 9), pos, gaussiBlur_param2);
	imshow("1_c", src1);
}

void cb_gaussiBlur_param2(int pos, void* userdata)
{
    
    
	Mat src = *(Mat *)(userdata);
	Mat src1 = src.clone();
	GaussianBlur(src1, src1, Size(9, 9), gaussiBlur_param1, pos);
	imshow("1_c", src1);
}


int bilateraFilter_parma1 = 30;
int bilateraFilter_parma2 = 60;
int bilateraFilter_parma3 = 15;
Mat b_result;

void cb_bilateraFilter_param1(int pos, void* userdata)
{
    
    
	Mat result;
	bilateralFilter(*(Mat*)userdata, result, pos, bilateraFilter_parma2, bilateraFilter_parma3);
	imshow("2_c", result);
	b_result = result;
}

void cb_bilateraFilter_param2(int pos, void* userdata)
{
    
    
	Mat result;
	bilateralFilter(*(Mat*)userdata, result, bilateraFilter_parma1, pos, bilateraFilter_parma3);
	imshow("2_c", result);
	b_result = result;
}

void cb_bilateraFilter_param3(int pos, void* userdata)
{
    
    
	Mat result;
	bilateralFilter(*(Mat*)userdata, result, bilateraFilter_parma1, bilateraFilter_parma2, pos);
	imshow("2_c", result);
	b_result = result;
}

int synthesize_param1 = 9;
int synthesize_param2 = 15;
int synthesize_param3 = 5;

void cb_synthesize_param1(int pos, void* userdata)
{
    
    
	Mat matFinla;
	cv::GaussianBlur(b_result, matFinla, Size(0, 0), pos);
	addWeighted(b_result, (double)synthesize_param2/10, matFinla, (double)(0- synthesize_param3)/10, 0, matFinla);
	imshow("3_c",matFinla);
}

void cb_synthesize_param2(int pos, void* userdata)
{
    
    
	Mat matFinla;
	cv::GaussianBlur(b_result, matFinla, Size(0, 0), synthesize_param1);
	addWeighted(b_result, (double)pos / 10, matFinla, (double)(0 - synthesize_param3) / 10, 0, matFinla);
	imshow("3_c", matFinla);
}

void cb_synthesize_param3(int pos, void* userdata)
{
    
    
	Mat matFinla;
	cv::GaussianBlur(b_result, matFinla, Size(0, 0), synthesize_param1);
	addWeighted(b_result, (double)synthesize_param2 / 10, matFinla, (double)(0 - pos) / 10, 0, matFinla);
	imshow("3_c", matFinla);
}



int main()
{
    
    
	Mat src = imread("F:/image/beautifulface.jpg");
	bilateralFilter(src, b_result, 30, 60, 15);

	imshow("0", src);
	createTrackbar("whiteFace_param1","0",&whiteFace_param1,10,cb_whiteFace_param1,&src);
	createTrackbar("whiteFace_param2", "0", &whiteFace_param2, 200, cb_whiteFace_param2, &src);
	
	
	
	imshow("1", src);
	createTrackbar("gaussiBlur1", "1", &gaussiBlur_param1, 100, cb_gaussiBlur_param1, &src);
	createTrackbar("gaussiBlur2", "1", &gaussiBlur_param2, 100, cb_gaussiBlur_param2, &src);
	
	imshow("2", src);
	createTrackbar("bilateraFilter_param1", "2", &bilateraFilter_parma1, 100, cb_bilateraFilter_param1, &src);
	createTrackbar("bilateraFilter_param2", "2", &bilateraFilter_parma2, 100, cb_bilateraFilter_param2, &src);
	createTrackbar("bilateraFilter_param3", "2", &bilateraFilter_parma3, 100, cb_bilateraFilter_param3, &src);

	imshow("3", src);
	createTrackbar("synthesize_param1", "3", &synthesize_param1, 100, cb_synthesize_param1, &src);
	createTrackbar("synthesize_param2", "3", &synthesize_param2, 100, cb_synthesize_param2, &src);
	createTrackbar("synthesize_param3", "3", &synthesize_param3, 100, cb_synthesize_param3, &src);
	
	waitKey(0);
	destroyAllWindows();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dhejsb/article/details/120576062