1、OpenCV 用户界面介绍
#include <iostream>
#include <string>
#include <sstream>
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
//CV_GUI_NORMAL标志使用原生界面和更基本的界面
const int CV_GUI_NORMAL = 0x10;
int main()
{
//imread是读取图像的主函数,此函数打开图像并以矩阵格式存储它
//imread(”图像路径字符串“,用于指定要加载的图像类型<默认为彩色图像;可选的>)
Mat lena = imread("lena.jpg");
Mat photo = imread("photo.jpg");
if (!lena.data)
{
cout << "Lena image missing!" << endl;
return -1;
}
if (!photo.data)
{
cout << "Lena image missing!" << endl;
return -1;
}
//namedWindow函数创建窗口
//namedWindow(”带有窗口名称的常量字符串“,需要的标志<可选的>)
namedWindow("Lena", WINDOW_NORMAL);
namedWindow("Photo", WINDOW_AUTOSIZE);
//当创建多个窗口时,它们是叠加的,moveWindow函数将窗口移动到桌面的任何位置
//Lena窗口向左移动了10个像素,向上移动了10个像素
moveWindow("Lena", 10, 10);
moveWindow("Photo", 700, 10);
//显示图像
imshow("Lena", lena);
imshow("Photo", photo);
//resizeWindow函数将Lena窗口的大小调整为512像素
//resizeWindow("window name", width, height)
resizeWindow("Lena", 512, 512);
waitKey(0);
//destroyWindow函数删除窗口,窗口名称是唯一需要的参数
destroyWindow("Lena");
destroyWindow("Photo");
//创建10个窗口
for (int i=0; i < 10; i++)
{
ostringstream ss;
ss << "Photo" << i;
namedWindow(ss.str());
moveWindow(ss.str(), 20*i, 20*i);
imshow(ss.str(), photo);
}
waitKey(0);
//destroyAllWindows函数可以一次删除所创建的所有窗口
//在任何情况下,OpenCV都会在应用程序中终止时自动销毁所有的窗口,因此在应用程序结束时不必调用此函数
destroyAllWindows();
return 0;
}
知识补充
结果
2、将滑块和鼠标事件添加到界面
#include <iostream>
#include <string>
#include <sstream>
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
// 创建一个变量保存滑块位置
int blurAmount=15;
//为滑块和鼠标事件定义回调函数
static void onChange(int pos, void* userInput);
static void onMouse( int event, int x, int y, int, void* userInput );
int main( int argc, const char** argv )
{
Mat lena = imread("lena.jpg");
namedWindow("Lena");
//createTrackbar函数用于生成滑块
//为Lena窗口添加了tracebar,然后调用Lena跟踪条对图像进行模糊处理。跟踪条的值存储在将会作为指针传递的blurAmount整数中,并将跟踪条的最大值设置为30,把onChange设置为回调函数,将lena mat图像作为用户数据发送
createTrackbar("Lena", "Lena", &blurAmount, 30, onChange, &lena);
//可以向Lena窗口添加鼠标回调,并将onMouse设置为回调函数,从而将lena mat图像作为用户数据进行传递
setMouseCallback("Lena", onMouse, &lena);
//为了完成主函数,需要使用与滑块相同的参数来初始化图像,要执行初始化,只需调用onChange回调函数
onChange(blurAmount, &lena);
waitKey(0);
destroyWindow("Lena");
return 0;
}
//滑块回调函数使用滑块值作为模糊量,将基本的模糊滤镜应用于图像
static void onChange(int pos, void* userInput)
{
//使用pos来检查滑块值是否为0
//在这种情况下,我们不使用过滤器,因为它会生产执行错误,也不能用0像素模糊
if(pos <= 0)
return;
//创建一个名为imgBlur的空矩阵来存储模糊结果
Mat imgBlur;
// Get the pointer input image
Mat* img= (Mat*)userInput;
// Apply a blur filter
blur(*img, imgBlur, Size(pos, pos));
// Show the result
imshow("Lena", imgBlur);
}
//Mouse callback
static void onMouse( int event, int x, int y, int, void* userInput )
{
if( event != EVENT_LBUTTONDOWN )
return;
// Get the pointer input image
Mat* img= (Mat*)userInput;
// Draw circle
circle(*img, Point(x, y), 10, Scalar(0,255,0), 3);
// Call on change to get blurred image
onChange(blurAmount, img);
}
知识补充
结果
3、Qt图形用户界面
简单操作
#include <iostream>
#include <string>
#include <sstream>
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
const int CV_GUI_NORMAL= 0x10;
int main( int argc, const char** argv )
{
//imread是读取图像的主函数,此函数打开图像并以矩阵格式存储它
//imread(”图像路径字符串“,用于指定要加载的图像类型<默认为彩色图像;可选的>)
Mat lena= imread("lena.jpg");
//namedWindow函数创建窗口
//namedWindow(”带有窗口名称的常量字符串“,需要的标志<可选的>)
namedWindow("Lena");
//显示图像
imshow("Lena", lena);
//displayOverlay函数在图像区域顶部显示叠加消息
//displayOverlay(”窗口名称“, “要显示的文本”, 显示叠加文本的时间<以毫秒为单位,如果设置为0,则文本永远不会消失>)
displayOverlay("Lena", "Overlay 5secs", 0);
//displayStatusBar函数在状态栏显示叠加消息
//displayStatusBar(”窗口名称“, “要显示的文本”, 显示叠加文本的时间<以毫秒为单位,如果设置为0,则文本永远不会消失>)
displayStatusBar("Lena", "Status bar 5secs", 5000);
// 保存窗口参数
saveWindowParameters("Lena");
// 下载窗口参数
loadWindowParameters("Lena");
//waitKey函数参数为要等待按键的毫秒数,如果参数为0,则这个函数会一直等待下去,直到用户按下某个键
waitKey(0);
///destroyWindow函数删除窗口,窗口名称是唯一需要的参数
destroyWindow("Lena");
return 0;
}
结果
将按钮添加到用户界面
#include <iostream>
#include <string>
#include <sstream>
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
Mat img;
//应用三种类型的滤镜:将颜色转化为灰色、模糊和Sobel过滤器
//都是可选的,用户可以使用要创建的按钮选择每一种滤镜
//为了获得每个过滤器的状态,创建了三个全局的布尔变量
bool applyGray=false;
bool applyBlur=false;
bool applySobel=false;
//applyFilters函数检查每个过滤器的状态变量
void applyFilters(){
Mat result;
img.copyTo(result);
if(applyGray)
{
cvtColor(result, result, COLOR_BGR2GRAY);
}
if(applyBlur)
{
blur(result, result, Size(5,5));
}
if(applySobel)
{
//sobel滤波器是使用sobel算子获得的图像导数,通常用于检测图像边缘
Sobel(result, result, CV_8U, 1, 1);
}
imshow("Lena", result);
}
//每个回调函数都会更改其状态变量以调用另一个名为applyFilters的函数,以便将激活的过滤器添加到输入图像
void grayCallback(int state, void* userData)
{
applyGray = true;
applyFilters();
}
void bgrCallback(int state, void* userData)
{
applyGray = false;
applyFilters();
}
void blurCallback(int state, void* userData)
{
applyBlur = (bool)state;
applyFilters();
}
void sobelCallback(int state, void* userData)
{
applySobel = !applySobel;
applyFilters();
}
int main( int argc, const char** argv )
{
img = imread("lena.jpg");
namedWindow("Lena");
//createButton函数创建按钮
//OpenCV中定义了三种按钮类型:QT_CHECKBOX,QT_RADIOBOX,QT_PUSH_BUTTON
//每个按钮有五个参数,按顺序如下所示:
//1、按钮名称;2、回调函数;3、传递给回调函数的用户变量数据的指针;4、按钮类型;5、用于复选框和单选框按钮类型的默认初始状态
createButton("Blur", blurCallback, NULL, QT_CHECKBOX, 0); createButton("Gay",grayCallback,NULL,QT_RADIOBOX, 0);
//图片的默认状态为彩色
createButton("RGB",bgrCallback,NULL,QT_RADIOBOX, 1); createButton("Sobel",sobelCallback,NULL,QT_PUSH_BUTTON, 0);
waitKey(0);
destroyWindow("Lena");
return 0;
}
知识补充
结果
4、OpenGL 支持
OpenCV 包括对OpenGL的支持。OpenGL 是一个作为标准而集成在几乎所有图形卡中的图形库。OpenGL 能够把2D图像绘制成复杂的3D场景。要在OpenGL中允许支持窗口,必须在调用namedWindow创建窗口时设置WINDOW_OPENGL 标志。
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
// OpenGL includes
#ifdef __APPLE__
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif
// OpenCV includes
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
//创建所需的全局变量,用来存储捕获的视频帧并保存帧,然后控制动画角度平面和OpenGL纹理
Mat frame;
GLfloat angle= 0.0;
GLuint texture;
VideoCapture camera;
//loadTexture函数将Mat帧转换为OpenGL纹理图像,可以在每个回调绘图中加载和使用
int loadTexture()
{
//在将图像作为纹理加载之前,必须确保在帧矩阵中有数据,即检查数据变量对象是否为空
if (frame.data==NULL) return -1;
//如果每帧矩阵中矩阵中有数据,则可以创建OpenGL纹理绑定,并将OpenGL纹理参数设置为线性插值
glBindTexture( GL_TEXTURE_2D, texture );
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
//定义像素存储在矩阵中
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//glTexImage2D函数生成像素
//OpenGL默认使用RGB格式,而OpenCV默认使用BGR格式,必须在函数中设置正确的格式
glTexImage2D2(GL_TEXTURE_2D, 0, GL_RGB, frame.cols, frame.rows,0, GL_BGR, GL_UNSIGNED_BYTE, frame.data);
return 0;
}
void on_opengl(void* param)
{
//使用常见的OpenGL函数,然后加载标识OpenGL矩阵以重置之前所有的更改
glLoadIdentity();
// 加载帧纹理
glBindTexture( GL_TEXTURE_2D, texture );
// 在1,1,1轴上旋转平面
glRotatef( angle, 1.0f, 1.0f, 1.0f );
// glBegin绘制四边形平面
glBegin (GL_QUADS);
//绘制一个以(0,0)为中心的平面,其大小为2单位
//glTexCoord2d和glVertex2d函数定义要使用的纹理坐标和顶点位置
glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0);
glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0);
glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0);
glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0);
glEnd();
}
int main( int argc, const char** argv )
{
// 打开网络摄像头(WebCam),检索拍摄的帧
camera.open(0);
if(!camera.isOpened())
{
camera.open("Recording3.webm");
if(!camera.isOpened())
return -1;
}
//如果摄相机正确打开,使用WINDOW_OPENGL标志创建支持OpenGL的窗口
namedWindow("OpenGL Camera", WINDOW_OPENGL);
// 想在平面中绘制来自摄像头的图像,需要启用OpenGL纹理
glEnable( GL_TEXTURE_2D );
glGenTextures(1, &texture);
//setOpenGlDrawCallback函数设置绘制OpenGL回调
//setOpenGlDrawCallback("窗口名称", 回调函数)
setOpenGlDrawCallback("OpenGL Camera", on_opengl);
//创建一个循环来加载纹理,并更新调用OpenGL绘图回调的窗口内容,最后更新角度的位置
while(waitKey(30)!='q')
{
camera >> frame;
// Create first texture
loadTexture();
updateWindow("OpenGL Camera");
angle =angle+4;
}
destroyWindow("OpenGL Camera");
return 0;
}
结果
问题
/usr/bin/ld: /tmp/ccx2qdzO.o: undefined reference to symbol 'glEnable'
/usr/bin/ld: /lib/x86_64-linux-gnu/libGL.so.1: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
解决方法
g++ sample5.cpp -lGL -lGLU -lGLEW -lglut -o main `pkg-config opencv4 --cflags --libs`
5、VTK 例子
#include <opencv2/viz.hpp>
#include <opencv2/calib3d.hpp>
#include <iostream>
using namespace cv;
using namespace std;
/*
* @function main
*/
int main()
{
/// Create a window
viz::Viz3d myWindow("Coordinate Frame");
/// Add coordinate axes
myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem());
/// Add line to represent (1,1,1) axis
viz::WLine axis(Point3f(-1.0f,-1.0f,-1.0f), Point3f(1.0f,1.0f,1.0f));
axis.setRenderingProperty(viz::LINE_WIDTH, 4.0);
myWindow.showWidget("Line Widget", axis);
/// Construct a cube widget
viz::WCube cube_widget(Point3f(0.5,0.5,0.0), Point3f(0.0,0.0,-0.5), true, viz::Color::blue());
cube_widget.setRenderingProperty(viz::LINE_WIDTH, 4.0);
/// Display widget (update if already displayed)
myWindow.showWidget("Cube Widget", cube_widget);
/// Rodrigues vector
Mat rot_vec = Mat::zeros(1,3,CV_32F);
float translation_phase = 0.0, translation = 0.0;
while(!myWindow.wasStopped())
{
/* Rotation using rodrigues */
/// Rotate around (1,1,1)
rot_vec.at<float>(0,0) += CV_PI * 0.01f;
rot_vec.at<float>(0,1) += CV_PI * 0.01f;
rot_vec.at<float>(0,2) += CV_PI * 0.01f;
/// Shift on (1,1,1)
translation_phase += CV_PI * 0.01f;
translation = sin(translation_phase);
Mat rot_mat;
Rodrigues(rot_vec, rot_mat);
/// Construct pose
Affine3f pose(rot_mat, Vec3f(translation, translation, translation));
myWindow.setWidgetPose("Cube Widget", pose);
myWindow.spinOnce(1, true);
}
return 0;
}