opencv -- 播放gif和avi 的demo

前三篇,笼统的介绍了使用opencv实现gif和avi文件的播放。这篇把整个demo源码补齐。

首先demo是一个MFC应用,操作起来简单方便。源码路径,默认貌似要积分,无语

其实也没什么东西,这里把dlg类的实现贴出来。代码风格就不要吐槽了。


// COpenCVDlg.h : 头文件
//

#pragma once


// CCOpenCVDlg 对话框
class CCOpenCVDlg : public CDialogEx
{
// 构造
public:
	CCOpenCVDlg(CWnd* pParent = NULL);	// 标准构造函数

// 对话框数据
	enum { IDD = IDD_COPENCV_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnBnClickedOk();
	afx_msg void OnBnClickedCancel();
	afx_msg LRESULT OnDrawGif(WPARAM w, LPARAM lParam);
	afx_msg LRESULT OnExitGif(WPARAM w, LPARAM lParam);

private:
	int play();
	void playGif();
	void playGifEx();
	void playAVI();
	
public:
	afx_msg void OnClose();
};

 


// COpenCVDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "COpenCV.h"
#include "COpenCVDlg.h"
#include "afxdialogex.h"

//----------
#include "opencv2/opencv.hpp"
#include "opencv2/videoio.hpp"

#include "opencv/cv.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "cvvimage.h"
#include <thread>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

using namespace cv;

//----------------------
#include "FreeImage.h"
bool g_bExitLoading = false;

IplImage*  gif2ipl(const char* filename)
{
	FreeImage_Initialise();         //load the FreeImage function lib  
	FREE_IMAGE_FORMAT fif = FIF_GIF;
	FIBITMAP* fiBmp = FreeImage_Load(fif, filename, GIF_DEFAULT);
	FIMULTIBITMAP * pGIF = FreeImage_OpenMultiBitmap(fif, filename, 0, 1, 0, GIF_PLAYBACK);
	//  FIBITMAPINFO fiBmpInfo = getfiBmpInfo(fiBmp);  
	int gifImgCnt = FreeImage_GetPageCount(pGIF);
	FIBITMAP * pFrame;
	int width, height;
	width = FreeImage_GetWidth(fiBmp);
	height = FreeImage_GetHeight(fiBmp);
	IplImage * iplImg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
	iplImg->origin = 1;//should set to 1-top-left structure(Windows bitmap style)  
	RGBQUAD* ptrPalette = new RGBQUAD; // = FreeImage_GetPalette(fiBmp);  
	BYTE intens;
	BYTE* pIntensity = &intens;
	cvNamedWindow("gif", 0);
	printf("gifImgCnt %d \n", gifImgCnt);
	for (int curFrame = 0; curFrame < gifImgCnt; curFrame++)
	{
		pFrame = FreeImage_LockPage(pGIF, curFrame);
		//ptrPalette = FreeImage_GetPalette(pFrame);  
		char * ptrImgDataPerLine;
		for (int i = 0; i < height; i++)
		{
			ptrImgDataPerLine = iplImg->imageData + i*iplImg->widthStep;
			for (int j = 0; j < width; j++)
			{
				//get the pixel index   
				//FreeImage_GetPixelIndex(pFrame,j,i,pIntensity);    
				FreeImage_GetPixelColor(pFrame, j, i, ptrPalette);
				ptrImgDataPerLine[3 * j] = ptrPalette->rgbBlue;
				ptrImgDataPerLine[3 * j + 1] = ptrPalette->rgbGreen;
				ptrImgDataPerLine[3 * j + 2] = ptrPalette->rgbRed;
				//ptrImgDataPerLine[3*j] = ptrPalette[intens].rgbBlue;  
				//ptrImgDataPerLine[3*j+1] = ptrPalette[intens].rgbGreen;  
				//ptrImgDataPerLine[3*j+2] = ptrPalette[intens].rgbRed;  
			}
		}

		printf("convert curFrame end %d \n", curFrame);
		cvShowImage("gif", iplImg);
		cvWaitKey(30);
		FreeImage_UnlockPage(pGIF, pFrame, 1);
	}
	FreeImage_Unload(fiBmp);
	FreeImage_DeInitialise();
	return iplImg;
}
//----------------------
std::wstring GetDir()
{
	std::wstring strPath;//= GetModuleDir();
	HMODULE module = GetModuleHandle(0);
	TCHAR pFileName[MAX_PATH];
	GetModuleFileName(module, pFileName, MAX_PATH);

	std::wstring csFullPath(pFileName);
	int nPos = csFullPath.find_last_of(_T('\\'));
	if (nPos < 0)
		strPath = L"";
	else
		strPath = csFullPath.substr(0, nPos);

	return strPath;
}

std::wstring GetAbsolutePath(LPCTSTR lpPath)
{
	std::wstring str(lpPath);
	std::wstring strPath = GetDir();
	strPath = strPath + L"\\" + str;

	return strPath;
}

#define DRAW_GIF		WM_USER + 1
#define EXIT_DRAW_GIF   DRAW_GIF + 1

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CCOpenCVDlg 对话框



CCOpenCVDlg::CCOpenCVDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CCOpenCVDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CCOpenCVDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CCOpenCVDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDOK, &CCOpenCVDlg::OnBnClickedOk)
	ON_BN_CLICKED(IDCANCEL, &CCOpenCVDlg::OnBnClickedCancel)
	ON_MESSAGE(DRAW_GIF, &CCOpenCVDlg::OnDrawGif)
	ON_MESSAGE(EXIT_DRAW_GIF, &CCOpenCVDlg::OnExitGif)
	ON_WM_CLOSE()
END_MESSAGE_MAP()


// CCOpenCVDlg 消息处理程序

BOOL CCOpenCVDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO:  在此添加额外的初始化代码
	CRect gtRt;
	GetDlgItem(IDC_STATIC)->GetWindowRect(&gtRt);
	GetDlgItem(IDC_STATIC)->SetWindowPos(NULL, 0, 0, gtRt.Width(), gtRt.Width(), SWP_NOZORDER);


	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CCOpenCVDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CCOpenCVDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CCOpenCVDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



void CCOpenCVDlg::OnBnClickedOk()
{
	GetDlgItem(IDC_STATIC)->ShowWindow(SW_SHOW);
	g_bExitLoading = false;

	//play();
	//playGif();

	/*playGifEx();

	return;*/

	playAVI();

	//CDialogEx::OnOK();
}


void CCOpenCVDlg::OnBnClickedCancel()
{
	g_bExitLoading = true;
	CDialogEx::OnCancel();
}

LRESULT CCOpenCVDlg::OnDrawGif( WPARAM w, LPARAM lParam)
{
	IplImage * p = (IplImage*)(w);
	if (p == nullptr)
	{
		return S_FALSE;
	}

	CDC *pDC = GetDlgItem(IDC_STATIC)->GetDC();//根据ID获得窗口指针再获取与该窗口关联的上下文指针
	HDC hdc = pDC->GetSafeHdc();                      // 获取设备上下文句柄
	CRect rect;
	GetDlgItem(IDC_STATIC)->GetClientRect(&rect); //获取box1客户区

	//cvShowImage("gif", iplImg);
	CvvImage cimg;
	cimg.CopyOf(p, p->nChannels);
	cimg.DrawToHDC(hdc, &rect);

	//delete p;
	//p = nullptr;
	cvReleaseImage(&p);
	ReleaseDC(pDC);

	return S_OK;
}

LRESULT CCOpenCVDlg::OnExitGif(WPARAM w, LPARAM lParam)
{
	GetDlgItem(IDC_STATIC)->ShowWindow(SW_HIDE);
	return S_OK;
}

int CCOpenCVDlg::play()
{
	// Create a VideoCapture object and open the input file
	// If the input is the web camera, pass 0 instead of the video file name
	VideoCapture cap("loading2.mov");

	// Check if camera opened successfully
	if (!cap.isOpened()){
		std::cout << "Error opening video stream or file" << std::endl;
		return -1;
	}

	while (1){

		Mat frame;
		// Capture frame-by-frame
		cap >> frame;

		// If the frame is empty, break immediately
		if (frame.empty())
			break;

		// Display the resulting frame
		imshow("Frame", frame);

		// Press  ESC on keyboard to exit
		char c = (char)waitKey(25);
		if (c == 27)
			break;
	}

	// When everything done, release the video capture object
	cap.release();

	// Closes all the frames
	destroyAllWindows();

	return 0;
}

void CCOpenCVDlg::playGif()
{
	CDC *pDC = GetDlgItem(IDC_STATIC)->GetDC();//根据ID获得窗口指针再获取与该窗口关联的上下文指针
	HDC hdc = pDC->GetSafeHdc();                      // 获取设备上下文句柄
	CRect rect;
	GetDlgItem(IDC_STATIC)->GetClientRect(&rect); //获取box1客户区

	CvvImage cimg;
	const char * filename = "D:\\WorkSpace\\COpenCV\\Debug\\loading.gif";

	FreeImage_Initialise();         //load the FreeImage function lib  
	FREE_IMAGE_FORMAT fif = FIF_GIF;
	FIBITMAP* fiBmp = FreeImage_Load(fif, filename, GIF_DEFAULT);
	FIMULTIBITMAP * pGIF = FreeImage_OpenMultiBitmap(fif, filename, 0, 1, 0, GIF_PLAYBACK);
	//  FIBITMAPINFO fiBmpInfo = getfiBmpInfo(fiBmp);  
	int gifImgCnt = FreeImage_GetPageCount(pGIF);
	FIBITMAP * pFrame;
	int width, height;
	width = FreeImage_GetWidth(fiBmp);
	height = FreeImage_GetHeight(fiBmp);
	IplImage * iplImg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
	iplImg->origin = 1;//should set to 1-top-left structure(Windows bitmap style)  
	RGBQUAD* ptrPalette = new RGBQUAD; // = FreeImage_GetPalette(fiBmp);  
	BYTE intens;
	BYTE* pIntensity = &intens;
	//cvNamedWindow("gif", 0);
	printf("gifImgCnt %d \n", gifImgCnt);

	while (1)
	{
		for (int curFrame = 0; curFrame < gifImgCnt/2; curFrame++)
		{
			pFrame = FreeImage_LockPage(pGIF, curFrame);
			//ptrPalette = FreeImage_GetPalette(pFrame);  
			char * ptrImgDataPerLine;
			for (int i = 0; i < height; i++)
			{
				ptrImgDataPerLine = iplImg->imageData + i*iplImg->widthStep;
				for (int j = 0; j < width; j++)
				{
					//get the pixel index   
					//FreeImage_GetPixelIndex(pFrame,j,i,pIntensity);    
					FreeImage_GetPixelColor(pFrame, j, i, ptrPalette);
					ptrImgDataPerLine[3 * j] = ptrPalette->rgbBlue;
					ptrImgDataPerLine[3 * j + 1] = ptrPalette->rgbGreen;
					ptrImgDataPerLine[3 * j + 2] = ptrPalette->rgbRed;
					//ptrImgDataPerLine[3*j] = ptrPalette[intens].rgbBlue;  
					//ptrImgDataPerLine[3*j+1] = ptrPalette[intens].rgbGreen;  
					//ptrImgDataPerLine[3*j+2] = ptrPalette[intens].rgbRed;  
				}
			}

			printf("convert curFrame end %d \n", curFrame);
			////cvShowImage("gif", iplImg);
			cimg.CopyOf(iplImg, iplImg->nChannels);
			cimg.DrawToHDC(hdc, &rect);

			cvWaitKey(10);
			FreeImage_UnlockPage(pGIF, pFrame, 1);
		}
	}
	
	FreeImage_Unload(fiBmp);
	FreeImage_DeInitialise();

	ReleaseDC(pDC);
}

void CCOpenCVDlg::playGifEx()
{
	std::thread t([](LPVOID pWnd){

		CCOpenCVDlg* pThis = (CCOpenCVDlg*)pWnd;
		if (pThis == nullptr)
		{
			return;
		}
	
		const char * filename = "D:\\WorkSpace\\COpenCV\\Debug\\loading.gif";

		FreeImage_Initialise();         //load the FreeImage function lib  
		FREE_IMAGE_FORMAT fif = FIF_GIF;
		FIBITMAP* fiBmp = FreeImage_Load(fif, filename, GIF_DEFAULT);
		FIMULTIBITMAP * pGIF = FreeImage_OpenMultiBitmap(fif, filename, 0, 1, 0, GIF_PLAYBACK);
		//  FIBITMAPINFO fiBmpInfo = getfiBmpInfo(fiBmp);  
		int gifImgCnt = FreeImage_GetPageCount(pGIF);
		FIBITMAP * pFrame;
		int width, height;
		width = FreeImage_GetWidth(fiBmp);
		height = FreeImage_GetHeight(fiBmp);
		IplImage * iplImg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
		iplImg->origin = 1;//should set to 1-top-left structure(Windows bitmap style)  
		RGBQUAD* ptrPalette = new RGBQUAD; // = FreeImage_GetPalette(fiBmp);  
		BYTE intens;
		BYTE* pIntensity = &intens;
		//cvNamedWindow("gif", 0);
		printf("gifImgCnt %d \n", gifImgCnt);

		while (!g_bExitLoading)
		{
			for (int curFrame = 0; curFrame < 16; curFrame++)
			{
				pFrame = FreeImage_LockPage(pGIF, curFrame);
				//ptrPalette = FreeImage_GetPalette(pFrame);  
				char * ptrImgDataPerLine;
				for (int i = 0; i < height; i++)
				{
					
					if (g_bExitLoading == true)
					{
						break;
					}

					ptrImgDataPerLine = iplImg->imageData + i*iplImg->widthStep;
					for (int j = 0; j < width; j++)
					{
						if (g_bExitLoading == true)
						{
							break;
						}
						//get the pixel index   
						//FreeImage_GetPixelIndex(pFrame,j,i,pIntensity);    
						FreeImage_GetPixelColor(pFrame, j, i, ptrPalette);
						ptrImgDataPerLine[3 * j] = ptrPalette->rgbBlue;
						ptrImgDataPerLine[3 * j + 1] = ptrPalette->rgbGreen;
						ptrImgDataPerLine[3 * j + 2] = ptrPalette->rgbRed;
						//ptrImgDataPerLine[3*j] = ptrPalette[intens].rgbBlue;  
						//ptrImgDataPerLine[3*j+1] = ptrPalette[intens].rgbGreen;  
						//ptrImgDataPerLine[3*j+2] = ptrPalette[intens].rgbRed;  
					}
				}

				if (g_bExitLoading == true)
				{
					::PostMessage(pThis->m_hWnd, EXIT_DRAW_GIF, NULL, NULL);
					FreeImage_UnlockPage(pGIF, pFrame, 1);
					break;
				}

				printf("convert curFrame end %d \n", curFrame);
				////cvShowImage("gif", iplImg);

				IplImage* pImg = cvCloneImage(iplImg);;
				//memcpy(pImg, iplImg, width * height);

				::PostMessage(pThis->m_hWnd, DRAW_GIF, (WPARAM)(LPVOID)pImg, NULL);
				/*cimg.CopyOf(iplImg, iplImg->nChannels);
				cimg.DrawToHDC(hdc, &rect);
				*/
				cvWaitKey(10);
				FreeImage_UnlockPage(pGIF, pFrame, 1);
			}
		}
		FreeImage_Unload(fiBmp);
		FreeImage_DeInitialise();
	}, this);
	t.detach();
}

void CCOpenCVDlg::playAVI()
{
	// TODO:  在此添加控件通知处理程序代码
	CDC *pDC = GetDlgItem(IDC_STATIC)->GetDC();//根据ID获得窗口指针再获取与该窗口关联的上下文指针
	HDC hdc = pDC->GetSafeHdc();                      // 获取设备上下文句柄
	CRect rect;
	// 矩形类
	GetDlgItem(IDC_STATIC)->GetClientRect(&rect); //获取box1客户区

	//std::wstring path = GetAbsolutePath(L"loading.avi");
	CvCapture *capture = cvCreateFileCapture("D:\\WorkSpace\\COpenCV\\Debug\\loading.avi");  //读取视频
	if (capture == NULL) {
		printf("NO capture");    //读取不成功,则标识
		//return 1;
	};
	double fps = cvGetCaptureProperty(capture, CV_CAP_PROP_FPS);   //读取视频的帧率
	int vfps = 1000 / fps;                                        //计算每帧播放的时间
	printf("%5.1f\t%5d\n", fps, vfps);
	double frames = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_COUNT);//读取视频中有多少帧
	printf("frames is %f\n", frames);
	//cvNamedWindow("example",CV_WINDOW_AUTOSIZE);                  //定义窗口
	IplImage *frame;

	CvvImage cimg;

	while (1){
		frame = cvQueryFrame(capture);                          //抓取帧
		if (frame == nullptr)
		{
			break;
		}

		cimg.CopyOf(frame, frame->nChannels);
		cimg.DrawToHDC(hdc, &rect);
		float ratio = cvGetCaptureProperty(capture, CV_CAP_PROP_POS_AVI_RATIO);     //读取该帧在视频中的相对位置
		printf("%f\n", ratio);
		//if (!frame)break;
		//cvShowImage("IDC_STATIC",frame);                          //显示

		char c = cvWaitKey(vfps);
		if (c == 27)break;
	}
	ReleaseDC(pDC);
	cvReleaseCapture(&capture);
	cvDestroyWindow("example");
}


void CCOpenCVDlg::OnClose()
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值

	CDialogEx::OnClose();
}

猜你喜欢

转载自blog.csdn.net/moyebaobei1/article/details/81745532