实现了在一个窗口显示多个视频子窗口,能够读入单个的视频或摄像头数据,然后在一个窗口中分别显示原始帧图像、反色图像、灰度图像以及Canny边缘检测图像。并在每个子窗口左上角显示系统时间,函数cvShowManyImages是改写的。
代码如下:
#include "stdafx.h"
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
// 隐藏 console 窗口
#pragma comment( linker, "/subsystem:/"windows/" /entry:/"mainCRTStartup/"" )
// 单窗口显示多幅图像的函数
void cvShowMultiImages(char* title, int nArgs, ...)
{
// img - Used for getting the arguments
IplImage* img;
// DispImage - the image in which all the input images are to be copied
IplImage* DispImage;
int size; // size - the size of the images in the window
int ind; // ind - the index of the image shown in the window
int x, y; // x,y - the coordinate of top left coner of input images
int w, h; // w,h - the width and height of the image
// r - Maximum number of images in a column
// c - Maximum number of images in a row
int r, c;
// scale - How much we have to resize the image
float scale;
// max - Max value of the width and height of the image
int max;
// space - the spacing between images
int space;
// If the number of arguments is lesser than 0 or greater than 12
// return without displaying
if(nArgs <= 0) {
printf("Number of arguments too small..../n");
return;
}
else if(nArgs > 12) {
printf("Number of arguments too large..../n");
return;
}
// Determine the size of the image,
// and the number of rows/cols
// from number of arguments
else if (nArgs == 1) {
r = c = 1;
size = 300;
}
else if (nArgs == 2) {
r = 2; c = 1;
size = 300;
}
else if (nArgs == 3 || nArgs == 4) {
r = 2; c = 2;
size = 300;
}
else if (nArgs == 5 || nArgs == 6) {
r = 3; c = 2;
size = 200;
}
else if (nArgs == 7 || nArgs == 8) {
r = 4; c = 2;
size = 200;
}
else {
r = 4; c = 3;
size = 150;
}
// Create a new 3 channel image to show all the input images
DispImage = cvCreateImage( cvSize(60 + size*r, 20 + size*c), IPL_DEPTH_8U, 3 );
// Used to get the arguments passed
va_list args;
va_start(args, nArgs);
// Loop for nArgs number of arguments
space = 20;
for (ind = 0, x = space, y = space; ind < nArgs; ind++, x += (space + size)) {
// Get the Pointer to the IplImage
img = va_arg(args, IplImage*);
// Check whether it is NULL or not
// If it is NULL, release the image, and return
if(img == 0) {
printf("Invalid arguments");
cvReleaseImage(&DispImage);
return;
}
// Find the width and height of the image
w = img->width;
h = img->height;
// Find whether height or width is greater in order to resize the image
max = (w > h)? w: h;
// Find the scaling factor to resize the image
scale = (float) ( (float) max / size );
// Used to Align the images
// i.e. Align the image to next row
if( ind % r == 0 && x!= space) {
x = space;
y += space + size;
}
// Set the image ROI to display the current image
cvSetImageROI(DispImage, cvRect(x, y, (int)( w/scale ), (int)( h/scale )));
// Resize the input image and copy the it to the Single Big Image
cvResize(img, DispImage);
// Reset the ROI in order to display the next image
cvResetImageROI(DispImage);
}
// Create a new window, and show the Single Big Image
//cvNamedWindow( title, 1 );
cvShowImage( title, DispImage);
// End the number of arguments
va_end(args);
// Release the Image Memory
cvReleaseImage(&DispImage);
}
int main( int argc, char** argv ) //见博文int main(int argc,char* argv[])详解与main函数带参在VS中调试方法
{
CvCapture* capture;
if (argc == 1)
{
capture = cvCreateCameraCapture( 0 );
}
else
{
capture = cvCreateFileCapture( argv[1] );
}
IplImage* frame;
cvNamedWindow("video",1);
cvResizeWindow("video",750,750);
CvFont timeFont,timeFont1;
cvInitFont(&timeFont, CV_FONT_HERSHEY_COMPLEX, 1.0f,1.0f,0,1,8);
cvInitFont(&timeFont1, CV_FONT_HERSHEY_COMPLEX, 1.0f,1.0f,0,1,8);
// Initialize new applied memory of 'time1'
char timestr[25];
memset(timestr, 0, 25 * sizeof(char));
while (1)
{
frame = cvQueryFrame( capture );
if (!frame) break;
// Get the systme local time info
time_t rawtime;
struct tm* timeinfo;
//time( &rawtime );
rawtime = time( NULL );
timeinfo = localtime( &rawtime );
char* p = asctime( timeinfo );
// the 25th character of array 'p' is '/n'
// but it can not be display correctly in the image
// so we just read out the first 24 character of 'p'
for (int i = 0; i < 24; i++)
{
timestr[i] = *p;
p++;
}
p = NULL;
// Bitwise inversion of every element of the current frame
IplImage* frame_not = cvCreateImage(cvGetSize(frame),frame->depth,frame->nChannels);
cvNot(frame,frame_not);
// Get the gray scale image of the current frmae
// and transform the gray image from single channel to three channels
IplImage* frame_gray=cvCreateImage(cvGetSize(frame),frame->depth,1);
IplImage* frame1=cvCreateImage(cvGetSize(frame),frame->depth,frame->nChannels);
cvCvtColor(frame,frame_gray,CV_RGB2GRAY);
cvCvtColor(frame_gray,frame1,CV_GRAY2BGR);
// Do Canny edge detection
// and transform the result image from single channel to three channels
IplImage* frame_canny=cvCreateImage(cvGetSize(frame),frame->depth,1);
IplImage* frame2=cvCreateImage(cvGetSize(frame),frame->depth,frame->nChannels);
cvCanny(frame_gray,frame_canny,20,75,3);
cvCvtColor(frame_canny,frame2,CV_GRAY2BGR);
// Display the local time information in each image
cvPutText( frame, timestr, cvPoint(5,25), &timeFont, CV_RGB(255,0,0) );
cvPutText( frame1, timestr, cvPoint(5,25), &timeFont, CV_RGB(255,0,0) );
cvPutText( frame2, timestr, cvPoint(5,25), &timeFont1, CV_RGB(255,0,0) );
cvPutText( frame_not, timestr, cvPoint(5,25), &timeFont1, CV_RGB(255,0,0) );
cvShowMultiImages("video",4,frame,frame_not,frame1,frame2);
//cvWaitKey(33);
int key = cvWaitKey(33);
if( key == 27 ) break;
cvReleaseImage(&frame_not);
cvReleaseImage(&frame1);
cvReleaseImage(&frame_gray);
cvReleaseImage(&frame2);
cvReleaseImage(&frame_canny);
}
cvDestroyWindow("video");
cvReleaseCapture(&capture);
return 0;
}
有几点需要注意:
1、在 while 循环中,处理完的图像应及时释放所占用的内存(cvReleaseImage),否则会不断占用内存空间以致系统当机。
2、图像数据的指针若是由 cvCreateImage 返回的,则应由 cvReleaseImage 来释放内存;如果是读取自视频或摄像头的帧图像,则应用 cvReleaseCapture 来释放内存,不必再用 cvReleaseImage() ,在 while 循环中使用 cvReleaseImage( &frame ) 会导致生成的程序在执行时出错。
3,有关va_list、va_start、va_arg、va_end有详述见博客相关博文