前言:opencv中没有matlab中能够在同一窗口中显示多幅图像的函数,需要我们去自实现。在这里我借鉴了github中一位大牛打代码,有兴趣的可以去看一下https://github.com/opencv/opencv/wiki/DisplayManyImages
一.实现需要的关键函数:VA_LIST
VA_LIST是在C语言中解决变参问题的一组宏,所在头文件:#include <stdarg.h>,用于获取不确定个数的参数。
使用方法:
(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;
(2)然后用VA_START宏初始化刚定义的VA_LIST变量;
(3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数);
(4)最后用VA_END宏结束可变参数的获取。
关于这个函数的原理介绍:
运动和行动 http://www.cnblogs.com/bettercoder/p/3488299.html
忧郁的废物_Addy https://blog.youkuaiyun.com/edonlii/article/details/8497704
aihao1984 https://blog.youkuaiyun.com/aihao1984/article/details/5953668
这几位大牛讲的非常好,有兴趣的可以去看一下这个函数是怎么实现的以及其内部原理到底是什么,我在这里就不进行赘述了。
二.代码
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include<iostream>
#include<stdarg.h>
void show_many_img(string title, int num, ...) {
int size;//定义缩放后图片的像素尺寸
int num_w;//横向要显示的图片个数
int num_h;//纵向要显示的图片个数
float scale;//对要显示的图片要进行resize以适应窗口;scale作为缩放的比例因子
//窗口最多能放下12张图片,需要一个判断
if (num <= 0) {
cout << "you need a coorect num" << endl;
return;
}
else if (num == 1) {
num_w = num_h = 1;
size = 300;
}
else if (num == 2) {
num_w = 2;
num_h = 1;
size = 300;
}
else if (num == 3 || num == 4) {
num_w = 2;
num_h = 2;
size = 300;
}
else if (num == 5 || num == 6) {
num_w = 3;
num_h = 2;
size = 200;
}
else if (num == 7 || num == 8) {
num_w = 4;
num_h = 2;
size = 200;
}
else if (num == 9 || num == 10|| num == 11||num == 12) {
num_w = 4;
num_h = 3;
size = 150;
}
else {
cout << "the num is too big" << endl;
return;
}
//创建一个新的图像,作为盛放要展示图像的容器,其中行比所有图像大100,列比所有图像
//大60,以便图像之间留出空白。而且一定要设置成Usigde的数据类型,否则imshow无法使用
Mat img_container = Mat::zeros(Size(100 + num_w*size, 60 + num_h*size), CV_8UC3);
va_list list;
va_start(list, num);
//m的作用,寻找要显示的图片在图像容器中左上角坐标的横坐标的位置,而且留下了20个像素的留白
//n的作用是寻找纵坐标的位置
int x, y, max,m,n;
for (int i = 0,m = n = 20; i < num; i++, m += (20 + size)) {
Mat img = va_arg(list, Mat);
if (img.empty()) {
cout << "img error" << endl;
return;
}
//寻找出要显示的图像长跟宽哪一个更大,让最大的边能够放入我们设计的size大小的窗口
x = img.cols;
y = img.rows;
max = (x > y) ? x : y;
//让被显示图像的最大一边能够放入我们设计的size大小的窗口,因此用最大边求缩放因子
scale = (float)((float)max / size);
//将要展示的图像,进行换行。
if (i % num_w == 0 && m != 20) {
m = 20;
n += 20 + size;
}
//设置被展示图像在图像容器中的ROI
Rect ROI(m,n,(int)(x/scale),(int)(y/scale));//其中的m,n是坐标值。两外两个是被缩放后的图像大小
Mat temp;
resize(img,temp,Size(ROI.width,ROI.height));
temp.copyTo(img_container(ROI));
}
namedWindow(title, 1);
imshow(title, img_container);
waitKey(0);
va_end(list);
}
int main(){
Mat img_1 = imread("pic.jpg");
show_many_img("显示六张", 6, img_1, img_1,img_1,img_1,img_1, img_1, img_1);
while(1);
return 0;
}
三.实验结果:我这里仅仅显示了6幅
四.总结
缺陷:这种做法将图像进行了resize,损坏了图片的原有信息。因此如果不必要,不太推荐用这种方法将多幅图像展现出来。