对图像处理来说,很多时候需要与用户进行交互,最典型的应用有两种:
(1) 在算法设计时,要根据某一参数的不同取值来进行相应的计算;
(2) 交互式分割算法
其中,对第1种情况而言,OpenCV提供了滑动条,可以灵活地设置参数值来进行相应的处理。而对第2种情况而言,则提供了鼠标交互,首先我们介绍关于滑动条的知识点,下文将会给出鼠标的相关知识点。
- 为了更好地说明滑动条的应用,我采用Canny边缘检测算法来进行演示,其调用方式为:
void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize=3, bool L2gradient=false )
其中,image代表输入图像,这里为单通道图像;edges为单通道的边缘图;threshold1与threshold2是Canny边缘检测算法的两个阈值;apertureSize与L2gradient有默认值,因此在这篇文章里不进行解释,感兴趣的可以去官方网站查询。
- 对滑动条来说,其函数调用方式为:
int createTrackbar(const string& trackbarname, const string& winname, int* value, int count, TrackbarCallback onChange=0, void* userdata=0)
关于这几个参数的解释如下:
* trackbarname: 滚动条的名字,通常指滚动条前的一串字符
* winname:滚动条所在窗口的名字,这个其实是定义了滚动条所依赖的主窗口的名字
* value:滑块的位置,在创建时,此值即为初始值
* count:滑块的最大值,对滑块来说,最小值始终为0
* TrackbarCallback:这个是最核心的,指向回调函数的指针,当滑块位置改变时,就会调用指向的函数,从而达到交互的目的
* userdata:默认值为0。此值是用户传给回调函数的值,用来进行相应的处理。如果value的值设置为全局变量,则滑动块的值可以由value来进行控制,可以不设置userdata
- 测试用的完整代码如下:
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
Mat imgSrc;//输入图像,彩色
Mat imgEdge;//边缘图像
Mat imgGray;//输入图像,灰度图像
const int g_nMaxThresh = 255;
int g_nThresh_low;
int g_nThresh_high;
void on_Trackbar(int,void*);
int main()
{
imgSrc = imread("running.jpg",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
cvtColor(imgSrc, imgGray, CV_RGB2GRAY);//彩色图像转换为灰度图
g_nThresh_low = 0;//初始化低阈值值0
g_nThresh_high = 0;//初始化高阈值为0
namedWindow("Edge Detection", WINDOW_AUTOSIZE);//生成主窗口,用来容纳滚动条与图像
imshow("Edge Detection", imgGray);
//创建一个滑动条,名字为Low:255,主窗口为Edge Detection,最大值为255,value为g_nThresh_low,回调函数为on_trackbar
createTrackbar("Low: 255", "Edge Detection", &g_nThresh_low, 255, on_Trackbar);
//创建一个滑动条,名字为High: 255,主窗口为Edge Detection,最大值为255,value为g_nThresh_high,回调函数为on_trackbar
createTrackbar("High: 255", "Edge Detection", &g_nThresh_high, 255, on_Trackbar);
waitKey(0);
return 0;
}
//回调函数
void on_Trackbar(int, void*)
{
cout << "Threshold value: " <<endl;
cout << "High: " << g_nThresh_high << endl;
cout << "Low: " << g_nThresh_low << endl << endl;
//调用Canny边缘检测算法,imgGray为输入图像,imgEdge为边缘图像,g_nThresh_low与g_nThresh_high是两个阈值
Canny(imgGray, imgEdge, g_nThresh_low, g_nThresh_high);
imshow("Edge Detection", imgEdge);
}
程序运行结果
拖动滑动条的位置,在阈值改变时,程序可以实时地得到边缘检测的效果程序的初始窗口如下:
拖动滑动条,改变高低阈值,低阈值设置为16,高阈值设置为38,结果如下:
拖动滑动条,改变高低阈值,低阈值设置为194,高阈值设置为208,结果如下:
可以看出,不同的高低阈值可以得到不同的边缘检测效果。对我来说,现在在采用边缘检测结果时,基本不会用这些基本的边缘检测算法,我会用一些比较近代的边缘检测算法,比如Structured forest等算法,效果很不错。