前三篇,笼统的介绍了使用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(>Rt);
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();
}