HIGHGUI页面初步学习
图像的输入显示和输出
imread函数
Mat imread(const string&filename ,int flags=1);
//第一个参数为文件名字
//flag默认是1
//flags>0返回3通道的彩色图像 BGR顺序
//flags=0返回灰度图像
//flags=2|4载入无损原图像
//flags<0反馈包含Alpha通道的加载图像
//下图为imread("",0);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w5zfpzqF-1658580159739)(C:\Users\正经人\AppData\Roaming\Typora\typora-user-images\image-20220606192802572.png)]
InputArray类型
可以简单当做Mat类型处理
nameWindow()函数
void nameWindow(const string&filename ,int flags=WINDOW_AUTOSIZE);
flags=WINDOW_AUTOSIZE
为自动适应窗口,自动调整以适应所显示的图像,不可以手动改变窗口的大小
flags另外的两个可选择的值为WINDOW_NORMAL
:可以手动设置窗口大小
WINDOW_OPENGL
窗口创建的时候支持OpenGL
|OpenGL是渲染2D、3D矢量图形硬件的一种软件接口。
输出图像到文件imwrite()函数
bool imwrite(const string& filename,InputArray img,const vector<int>& params=vector<int>());
filename “123.jpg”
InputArray img 填写mat类型的数据
const vector& params=vector() 默认的图像编码参数,可以修改图片质量,JPEG为0-100,PNG为0-9
合并显示
将长与宽小于等于image的logo与image重叠在一起
void cvAddWeighted( const CvArr* src1, double alpha,const CvArr* src2, double beta,double gamma, CvArr* dst );
参数1:src1,第一个原数组.
参数2:alpha,第一个数组元素权重参数3:src2第二个原数组
参数4:beta,第二个数组元素权重
参数5:gamma,图1与图2作和后添加的数值。不要太大,不然图片一片白。总和等于255以上就是纯白色了。参数6:dst,输出图片
//两张图片拼在一起
Mat image = imread("tu1.jpg");
Mat logo = imread("tu2.jpg");
//输入后显示
namedWindow("tupian1");
imshow("tupian1", image);
namedWindow("tupian2");
imshow("tupian2", logo);
//定义一个Mat类型,用于存放图像的ROI
Mat imageROI;
//方法一,利用Rect设置ROI位置
imageROI = image(Rect(0, 0, logo.cols, logo.rows));
//方法二
//imageROI=image(Range(350,350+logo.rows),Range(00,800+logo.cols));
//将logo加到原图上
addWeighted(imageROI, 0.5, logo, 0.3, 0., imageROI);
namedWindow("hunhe");
imshow("hunhe", image);
//imwrite("apicture.jpg", image);
waitKey();
destroyAllWindows();
return 0;
遇到的BUG
0x00007FF872444FD9 处(位于 Project1.exe 中)有未经处理的异常: Microsoft C++ 异常: cv::Exception,位于内存位置 0x000000F11317EFB8 处。
解决方法
- 将读取文件的路径改为双“ \"
Mat image = imread("D:\\opencv_learn\\Project1\\tu1.jpg");
Mat logo = imread("D:\\opencv_learn\\Project1\\tu2.jpg");
或将图片放置在工程文件下下方,并直接读取
- 查看链接器-输入-附加依赖,Debug x64应该为opencv_world***d.lib,查看一下是否填写错误
- 查看是否有重复的窗口名,检查下
imshow()
是不是写错了(经过实验,不同窗口读取相同图片不会产生bug)
//输入后显示
namedWindow("tupian1");
imshow("tupian1", image);
namedWindow("tupian2");
imshow("tupian2", logo);
- 图片颜色变换问题、图片通道数问题、图片尺寸问题,我的问题如下面代码所示,将image放在logo的左下角,但由于image的像素比logo大,大的图片不可能作为小的图片的一部分,所以产生了本次错误,再将image和logo切换位置后,可以成功运行。
大家在写OPENCV的代码时,也要注意Rect后面初始位置的两个参数,如果x+logo.cols
比image.cols
大,就有可能产生本错误。
//定义一个Mat类型,用于存放图像的ROI
Mat imageROI;
//方法一,利用Rect设置ROI位置
imageROI = logo(Rect(0, 0, image.cols, image.rows));
//方法二
//imageROI=image(Range(350,350+logo.rows),Range(00,800+logo.cols));
//将logo加到原图上
addWeighted(imageROI, 0.5, image, 0.3, 0., imageROI);
namedWindow("hunhe");
imshow("hunhe", image);
//imwrite("apicture.jpg", image);
waitKey();
destroyAllWindows();
return 0;
我们可以看到tupian1比tupian2大
滑动条的创建和使用
滑动条是OpenCV动态调节参数中比较好用的工具,依附于窗口存在
创建滑动条:createTrackbar()
createTrackbar()
往往会配合一个回调函数使用。
int creatTrackbar(conststring& trackbarname,conststring& winname,int* value,int count,TrackbarCallback onChange=0,void* userdata=0);
- conststring& trackbarname:轨迹条的名字
- conststring& winname:窗口的名字,表示轨迹条会依附到哪个窗口
- int* value:指向整型的指针,表示滑块位置
- int count:表示滑块可以达到的最大位置的值,滑块最小位置的值始终为0
- TrackbarCallback onChange=0:回调函数的指针,每次滑块位置改变时,这个函数会进行回调,。函数的原型为
void XXX(int,void*);
,第一个参数是轨迹条的位置,第二个参数是用户数据,当用户数据指针返回NULL时,证明没有回调函数调用,仅value有变化,即图像的混合程度不变,但是滑动块的位置却变化了。 - void* userdata=0:默认值为0,如value为实参、全局变量,则可不用填写。因为此参数代表用户输入的变量,当value为实参且为全局变量时,改变value,即可对回调函数值产生影响,不需要再输入userdata了
createTrackbar制定了一个回调函数,当轨迹条位置改变时,调用这个回调函数。回调函数就是一个通过函数指针调用的函数,当这个指针被用来调用所指向的函数时,称其为回调函数。
Example
#include<iostream>
using namespace cv;
using namespace std;
//createTrackbar()滑动条
const int g_nMaxAlpha = 100;//设置透明度最高为100
int g_nAlphaValueSlider;//创建滑动条对应的变量
double g_dAlphaValue;
double g_dBeteValue;
Mat srcimage1;
Mat srcimage2;
Mat dstimage;
Mat srcimage11, srcimage22;
void on_Trackbar(int, void*)
{
g_dAlphaValue = (double)g_nAlphaValueSlider / g_nMaxAlpha;//求出当前透明值的比例
g_dBeteValue = 1 - g_dAlphaValue;
//根据alpha和beta对两张图片进行线性混合
addWeighted(srcimage1, g_dAlphaValue, srcimage2, g_dBeteValue, 0.0, dstimage);
imshow("图片", dstimage);
}
int main()
{
//createTrackbar()滑动条
//设置图片为相同大小,如果不同,可以使用resize语句
srcimage1=imread("tu1.jpg");
srcimage2 = imread("tu2.jpg");
int down_width = 798;
int down_height = 1280;
resize(srcimage1, srcimage1, Size(down_width, down_height), INTER_LINEAR);
resize(srcimage2, srcimage2, Size(down_width, down_height), INTER_LINEAR);
if (!srcimage1.data)
{
printf("读取第一个照片有错误");
return -1;
}
if (!srcimage2.data)
{
printf("读取第二个照片有错误");
return -1;
}
g_nAlphaValueSlider = 70;//赋值为70
namedWindow("图片");
//创建滑动条
char TrackbarName[50];
sprintf_s(TrackbarName, "透明值 %d", g_nMaxAlpha);//sprintf_s为sprintf的安全升级版本
createTrackbar(TrackbarName, "图片", &g_nAlphaValueSlider, g_nMaxAlpha, on_Trackbar);
//结果在回调函数中显示
on_Trackbar(g_nAlphaValueSlider, 0);
//按任意键退出
waitKey(0);
return 0;
}
获取当前轨迹条的位置:getTrackbarPos()
int getTrackbarPos(conststring& trackbarname,conststring& winname);
- 第一个参数:轨迹条的名字
- 第二个参数:轨迹条窗口的名字
鼠标操作
OpenCV中的鼠标操作与滑动条的映射方式类似,均需要用到回调函数。
void setMouseCallback(conststring& winname,MouseCallback onMouse,void* userdata=0)
- 第一个参数,窗口的名字
- 第二个参数,当鼠标的位置移动(x、y坐标以图像坐标系为参考系)或鼠标左键按下、左键抬起时,被调用的函数指针
- 第三个参数,洪湖定义的传递到回调函数的参数,默认值为0
cv::Scalar的构造函数是cv::Scalar(v1, v2, v3, v4)
前面的三个参数是依次设置BGR的,和RGB相反,第四个参数设置图片的透明度。
cv::scalar::all(0)将四个值全部设为0.
image.copyTo(imageROI),作用是把image的内容粘贴到imageROI;
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace cv;
using namespace std;
#define WINDOW_NAME "【程序窗口】"
//全局函数说明
void on_MouseHandle(int event, int x, int y, int flags, void* param);
void DrawRectangle(cv::Mat& imag, cv::Rect box);
void ShowHelpText();
//全局变量说明
Rect g_rectangle;
bool g_bDrawingBox = false;//是否进行绘制
RNG g_rng(12345);
int main()
{
g_rectangle = Rect(-1, -1, 0, 0);
Mat srcImage(600, 800, CV_8UC3), tempImage;//CV_8UC3表示的是:8位深度的unsigned int型,C3表示channel 3,3个通道
srcImage.copyTo(tempImage);
srcImage = Scalar::all(0);
//设置回调函数
namedWindow(WINDOW_NAME);
setMouseCallback(WINDOW_NAME, on_MouseHandle, (void*)&srcImage);
while (1)
{
srcImage.copyTo(tempImage);//复制原图到临时变量
if (g_bDrawingBox)DrawRectangle(tempImage, g_rectangle);
imshow(WINDOW_NAME, tempImage);
if (waitKey(10) == 27)break;//按下ESC,程序退出
}
return 0;
}
void on_MouseHandle(int event, int x, int y, int flags, void* param)
{
//x与y代表鼠标现在的坐标位置
Mat& image = *(cv::Mat*)param;
switch (event)//event为鼠标移动or按下or抬起
{
//鼠标移动消息
case EVENT_MOUSEMOVE:
{
if (g_bDrawingBox)//判断是否进行绘制,并将长和宽存到RECT变量中
{
g_rectangle.width = x - g_rectangle.x;
g_rectangle.height = y - g_rectangle.y;
}
}
break;
//左键按下
case EVENT_LBUTTONDOWN:
{
g_bDrawingBox = true;//之后再拖动,即可改变rectangle的值
g_rectangle = Rect(x, y, 0, 0);
}
break;
//左键抬起
case EVENT_LBUTTONUP:
{
g_bDrawingBox = false;
if (g_rectangle.width < 0)
{
//将x加一个负值,向左移,并把width的正负反转,在向右画矩形时,实现效果
//若不操作,原意为在x,y点向左画矩形
g_rectangle.x += g_rectangle.width;
g_rectangle.width *= -1;
}
if (g_rectangle.height < 0)
{
g_rectangle.y += g_rectangle.height;
g_rectangle.height *= -1;
}
//调用函数进行绘制
DrawRectangle(image,g_rectangle);
}
break;
}
}
void DrawRectangle(cv::Mat& img, cv::Rect box)
{
rectangle(img, box.tl(), box.br(), Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255)));//随机颜色
}