实例工程包下载【OpenCV:基于MFC的视频播放器和图片读取器】
一、实现的功能
1、打开本地视频进行读取、播放、暂停、停止控制
2、图片打开功能分为两种:可使用“打开图片”按钮打开本地图片,或者点击comobox里面设定的图片列表选择并显示图片
二、编译环境
OS:Win8.1 x64
IDE: Visual Studio 2013
OpenCV: 2.4.8
三、主要思路
1、视频的滑动条控制:
①主窗体的OnHScroll()响应函数负责响应slider滑动条的变化,这样就轻松搞定slider控件与拖动滑动条动作与视频播放的联动。
②新建虚拟的slider实例和slider滑动位置的全局变量,通过数据交换函数予以关系绑定
③通过OpenCV的函数cvSetCaptureProperty()和slider滑动位置全局变量来确定指向视频的哪个帧位置,并进行加载显示到Picture控件中
2、combobox中图片的对应显示:①addstring()向列表中添加选项
②将图片名字改为列表中的选项名
③根据选项名通过cvloadImage()打开图片
四、核心代码
<span style="font-family:Microsoft YaHei;">// VideoPlayerDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "VideoPlayer.h"
#include "VideoPlayerDlg.h"
#include "CvvImage.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// 对话框数据
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
// CVideoPlayerDlg 对话框
CVideoPlayerDlg::CVideoPlayerDlg(CWnd* pParent /*=NULL*/)
: CDialog(CVideoPlayerDlg::IDD, pParent)
, IsPlaying(false)
, IsAviFile(false)
, g_VideoPath(_T(""))
, pDC(NULL)
, pwnd(NULL)
, b_flagProcess(false)
, g_m_int(0)
, g_pCapture(NULL)
, g_pFrame(NULL)
, g_m_run(0)
, TheImage(NULL)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CVideoPlayerDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_SLIDER1, m_slider);
DDX_Control(pDX, IDC_COMBO4, m_cbExample);
}
BEGIN_MESSAGE_MAP(CVideoPlayerDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_Open, &CVideoPlayerDlg::OnBnClickedOpen)
ON_BN_CLICKED(IDC_Stop, &CVideoPlayerDlg::OnBnClickedStop)
ON_WM_HSCROLL()
ON_BN_CLICKED(IDC_Play, &CVideoPlayerDlg::OnBnClickedPlay)
ON_BN_CLICKED(IDOK, &CVideoPlayerDlg::OnBnClickedOk)
ON_BN_CLICKED(IDCANCEL, &CVideoPlayerDlg::OnBnClickedCancel)
ON_BN_CLICKED(IDC_Pause, &CVideoPlayerDlg::OnBnClickedPause)
ON_STN_CLICKED(IDC_SHOWPIC, &CVideoPlayerDlg::OnStnClickedShowpic)
ON_BN_CLICKED(IDC_img_open, &CVideoPlayerDlg::OnBnClickedReadimg)
ON_EN_CHANGE(IDC_EDIT_FRAME_show, &CVideoPlayerDlg::OnEnChangeEditFrameshow)
ON_CBN_SELCHANGE(IDC_COMBO4, &CVideoPlayerDlg::OnCbnSelchangeCombo4)
END_MESSAGE_MAP()
// CVideoPlayerDlg 消息处理程序
BOOL CVideoPlayerDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
CvSize ImgSize;
ImgSize.height = IMAGE_HEIGHT;
ImgSize.width = IMAGE_WIDTH;
TheImage = cvCreateImage(ImgSize, IPL_DEPTH_8U, IMAGE_CHANNELS);
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: 在此添加额外的初始化代码
GetDlgItem( IDC_Play )->EnableWindow( FALSE );
GetDlgItem( IDC_Pause )->EnableWindow( FALSE );
GetDlgItem( IDC_Stop )->EnableWindow( FALSE );
GetDlgItem( IDC_SLIDER1 )->EnableWindow( FALSE );
m_cbExample.AddString("photos/1.bmp"); //combobox里面的图片保存在photos文件夹内
m_cbExample.AddString("photos/2.bmp");
m_cbExample.AddString("photos/3.bmp");
m_cbExample.AddString("photos/4.bmp");
m_cbExample.AddString("photos/5.bmp");
m_cbExample.AddString("photos/6.bmp");
m_cbExample.AddString("photos/7.bmp");
m_cbExample.AddString("photos/8.bmp");
m_cbExample.AddString("photos/9.bmp");
m_cbExample.AddString("photos/10.bmp");
pwnd = GetDlgItem(IDC_SHOWPIC);
pwnd->MoveWindow(40,40,352,288);
pDC =pwnd->GetDC();
hDC= pDC->GetSafeHdc();
pwnd->GetClientRect(&rect);
Invalidate();
m_slider.SetRange(0,100);
m_slider.SetTicFreq(10);
ImgSize.height = IMAGE_HEIGHT;
ImgSize.width = IMAGE_WIDTH;
g_pFrame = cvCreateImage( ImgSize, IPL_DEPTH_8U, IMAGE_CHANNELS );
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CVideoPlayerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CVideoPlayerDlg::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
{
CDialog::OnPaint();
CDialog::UpdateWindow(); // 更新windows窗口,如果无这步调用,图片显示还会出现问题
ShowImage(TheImage, IDC_ShowImg); // 重绘图片函数
}
if(!g_m_run)
{
CDC MemDC;
MemDC.CreateCompatibleDC(NULL);
pDC->StretchBlt(rect.left,rect.top,rect.Width(),rect.Height(),&MemDC,0,0,48,48,SRCCOPY);
MemDC.DeleteDC();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CVideoPlayerDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CVideoPlayerDlg::OnBnClickedOpen()
{
// TODO: 在此添加控件通知处理程序代码
CFileDialog dlg(
TRUE,
_T("*.avi"),
NULL,
OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
_T("*.avi|*.avi|*.rmvb|*.rmvb|*.mp4|*.mp4|*.wmv|*.wmv| All Files (*.*) |*.*||"),
NULL
);
dlg.m_ofn.lpstrTitle = _T("选取视频文件");
if( dlg.DoModal() != IDOK )
return;
g_VideoPath = dlg.GetPathName();
GetDlgItem( IDC_Play )->EnableWindow( TRUE );
GetDlgItem( IDC_Pause )->EnableWindow( TRUE );
GetDlgItem( IDC_Stop )->EnableWindow( TRUE );
GetDlgItem( IDC_SLIDER1 )->EnableWindow( TRUE );
}
void CVideoPlayerDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CSliderCtrl *pSlidCtrl=(CSliderCtrl*)GetDlgItem(IDC_SLIDER1);
g_m_int=pSlidCtrl->GetPos();
char chEdit[10];
itoa(g_m_int,chEdit,10);
SetDlgItemText(IDC_EDIT_FRAME_show,chEdit);
if(g_pCapture)
{
cvSetCaptureProperty(g_pCapture,CV_CAP_PROP_POS_FRAMES,g_m_int);
}
CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}
void CVideoPlayerDlg::OnBnClickedPlay()
{
// TODO: 在此添加控件通知处理程序代码
if( g_VideoPath == "" )
{
MessageBox("请先选择视频文件!");
return;
}
else
{
if(!(g_pCapture = cvCreateFileCapture( g_VideoPath )))
{
MessageBox("打开视频文件失败!");
return;
}
}
int frames = (int) cvGetCaptureProperty( g_pCapture, CV_CAP_PROP_FRAME_COUNT );
m_slider.SetRange(0,frames-1);
m_slider.SetTicFreq(1);
char chEdit[10];
itoa(frames,chEdit,10);
SetDlgItemText(IDC_EDIT_FRAME_count,chEdit);
GetDlgItem( IDC_Open )->EnableWindow( FALSE );
GetDlgItem( IDC_Play )->EnableWindow( FALSE );
GetDlgItem( IDC_Pause )->EnableWindow( TRUE );
GetDlgItem( IDC_Stop )->EnableWindow( TRUE );
IplImage *pFrame = NULL;
cvNamedWindow("video");
cvResizeWindow("video",1,1);
HWND hWnd = (HWND) cvGetWindowHandle("video");
HWND hParent = ::GetParent(hWnd);
HWND hwnd1=::FindWindow("CVideoPlayerDlg","VideoPlayer");
::SetParent(hWnd, hwnd1);
::ShowWindow(hParent, SW_HIDE);
if( g_pFrame )
cvZero( g_pFrame );
g_m_run = 1;
if(g_pCapture)
{
cvSetCaptureProperty(g_pCapture,CV_CAP_PROP_POS_FRAMES,g_m_int);
}
while( (g_m_int < frames) & (g_m_run == 1) )
{
pFrame = cvQueryFrame( g_pCapture );
IplImage* newframe = cvCloneImage(pFrame);
ResizeImage( newframe );
ShowImage( g_pFrame , IDC_SHOWPIC);
if (cvWaitKey(20) == 27)
break;
m_slider.SetPos(g_m_int);
char chEdit[10];
//g_m_int=numfrm;
itoa(g_m_int,chEdit,10);
SetDlgItemText(IDC_EDIT_FRAME_show,chEdit);
//numfrm++;
g_m_int++;
cvReleaseImage( &newframe );
}
if(g_m_int==frames)
{
g_m_int=0;
m_slider.SetPos(g_m_int);
g_m_run = 0;
if( g_pFrame )
{
cvZero( g_pFrame );
ShowImage( g_pFrame , IDC_SHOWPIC );
}
GetDlgItem( IDC_Open )->EnableWindow( TRUE );
GetDlgItem( IDC_Play )->EnableWindow( TRUE );
GetDlgItem( IDC_Pause )->EnableWindow( FALSE );
GetDlgItem( IDC_Stop )->EnableWindow( FALSE );
}
cvReleaseCapture(&g_pCapture);
cvDestroyWindow("video");
}
void CVideoPlayerDlg::OnBnClickedStop()
{
// TODO: 在此添加控件通知处理程序代码
CDC MemDC;
MemDC.CreateCompatibleDC(NULL);
pDC->StretchBlt(rect.left,rect.top,rect.Width(),rect.Height(),&MemDC,0,0,48,48,SRCCOPY);
MemDC.DeleteDC();
GetDlgItem( IDC_Open )->EnableWindow( TRUE );
GetDlgItem( IDC_Play )->EnableWindow( TRUE );
GetDlgItem( IDC_Pause )->EnableWindow( FALSE );
GetDlgItem( IDC_Stop )->EnableWindow( FALSE );
g_m_run=0;
g_m_int=0;
m_slider.SetPos(g_m_int);
char chEdit[10];
itoa(g_m_int,chEdit,10);
SetDlgItemText(IDC_EDIT_FRAME_show,chEdit);
return;
}
void CVideoPlayerDlg::ResizeImage(IplImage* img)
{
int w = img->width;
int h = img->height;
int max = (w > h)? w: h;
float scale = (float) ( (float) max / 256.0f );
int nw = (int)( w/scale );
int nh = (int)( h/scale );
int tlx = (nw > nh)? 0: (int)(256-nw)/2;
int tly = (nw > nh)? (int)(256-nh)/2: 0;
cvSetImageROI( g_pFrame, cvRect( tlx, tly, nw, nh) );
cvResize( img, g_pFrame );
cvResetImageROI( g_pFrame );
}
void CVideoPlayerDlg::ShowImage(IplImage* img, UINT ID)
{
CDC* pDC = GetDlgItem( ID ) ->GetDC();
HDC hDC = pDC ->GetSafeHdc();
CRect rect;
GetDlgItem(ID) ->GetClientRect( &rect );
int rw = rect.right - rect.left;
int rh = rect.bottom - rect.top;
int iw = img->width;
int ih = img->height;
int tx = (int)(rw - iw)/2;
int ty = (int)(rh - ih)/2;
SetRect( rect, tx, ty, tx+iw, ty+ih );
CvvImage cimg;
cimg.CopyOf( img );
cimg.DrawToHDC( hDC, &rect );
ReleaseDC( pDC );
}
void CVideoPlayerDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
g_m_run = 0;
cvReleaseImage( &g_pFrame );
cvDestroyAllWindows();
OnOK();
}
void CVideoPlayerDlg::OnBnClickedCancel()
{
// TODO: 在此添加控件通知处理程序代码
g_m_run = 0;
cvReleaseImage( &g_pFrame );
cvDestroyAllWindows();
OnCancel();
}
void CVideoPlayerDlg::OnBnClickedPause()
{
// TODO: 在此添加控件通知处理程序代码
g_m_run=0;
GetDlgItem( IDC_Open )->EnableWindow( FALSE );
GetDlgItem( IDC_Play )->EnableWindow( TRUE );
GetDlgItem( IDC_Pause )->EnableWindow( FALSE );
GetDlgItem( IDC_Stop )->EnableWindow( FALSE );
}
void CVideoPlayerDlg::OnStnClickedShowpic()
{
// TODO: 在此添加控件通知处理程序代码
}
void CVideoPlayerDlg::OnBnClickedReadimg()
{
// TODO: 在此添加控件通知处理程序代码
CFileDialog dlg(
TRUE, _T("*.bmp"), NULL,
OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
_T("image files (*.bmp; *.jpg) |*.bmp; *.jpg | All Files (*.*) |*.*||"), NULL
); // 选项图片的约定
dlg.m_ofn.lpstrTitle = _T("Open Image"); // 打开文件对话框的标题名
if (dlg.DoModal() != IDOK) // 判断是否获得图片
return;
CString mPath = dlg.GetPathName(); // 获取图片路径
IplImage* ipl = cvLoadImage(mPath, 1); // 读取图片、缓存到一个局部变量 ipl 中
if (!ipl) // 判断是否成功载入图片
return;
if (TheImage) // 对上一幅显示的图片数据清零
cvZero(TheImage);
resize_image(ipl); // 对读入的图片进行缩放,使其宽或高最大值者刚好等于 256,再复制到 TheImage 中
show_image(TheImage, IDC_ShowImg); // 调用显示图片函数
cvReleaseImage(&ipl); // 释放 ipl 占用的内存
}
void CVideoPlayerDlg::show_image(IplImage* img, UINT ID)
{
CDC* pDC = GetDlgItem(ID)->GetDC(); // 获得显示控件的 DC
HDC hDC = pDC->GetSafeHdc(); // 获取 HDC(设备句柄) 来进行绘图操作
CRect rect;
GetDlgItem(ID)->GetClientRect(&rect);
int rw = rect.right - rect.left; // 求出图片控件的宽和高
int rh = rect.bottom - rect.top;
int iw = img->width; // 读取图片的宽和高
int ih = img->height;
int tx = (int)(rw - iw) / 2; // 使图片的显示位置正好在控件的正中
int ty = (int)(rh - ih) / 2;
SetRect(rect, tx, ty, tx + iw, ty + ih);
CvvImage cimg;
cimg.CopyOf(img); // 复制图片
cimg.DrawToHDC(hDC, &rect); // 将图片绘制到显示控件的指定区域内
ReleaseDC(pDC);
}
void CVideoPlayerDlg::resize_image(IplImage* img)
{
// 读取图片的宽和高
int w = img->width;
int h = img->height;
// 找出宽和高中的较大值者
int max = (w > h) ? w : h;
// 计算将图片缩放到TheImage区域所需的比例因子
float scale = (float)((float)max / 256.0f);
// 缩放后图片的宽和高
int nw = (int)(w / scale);
int nh = (int)(h / scale);
// 为了将缩放后的图片存入 TheImage 的正中部位,需计算图片在 TheImage 左上角的期望坐标值
int tlx = (nw > nh) ? 0 : (int)(256 - nw) / 2;
int tly = (nw > nh) ? (int)(256 - nh) / 2 : 0;
// 设置 TheImage 的 ROI 区域,用来存入图片 img
cvSetImageROI(TheImage, cvRect(tlx, tly, nw, nh));
// 对图片 img 进行缩放,并存入到 TheImage 中
cvResize(img, TheImage);
// 重置 TheImage 的 ROI 准备读入下一幅图片
cvResetImageROI(TheImage);
}
void CVideoPlayerDlg::OnEnChangeEditFrameshow()
{
// TODO: 如果该控件是 RICHEDIT 控件,它将不
// 发送此通知,除非重写 CDialog::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
// TODO: 在此添加控件通知处理程序代码
}
void CVideoPlayerDlg::OnCbnSelchangeCombo4()
{
int nIndex = m_cbExample.GetCurSel();
CString strCBText;
m_cbExample.GetLBText(nIndex, strCBText);
IplImage* ipl = cvLoadImage(strCBText, 1); // 读取图片、缓存到一个局部变量 ipl 中
if (!ipl) // 判断是否成功载入图片
return;
if (TheImage) // 对上一幅显示的图片数据清零
cvZero(TheImage);
resize_image(ipl); // 对读入的图片进行缩放,使其宽或高最大值者刚好等于 256,再复制到 TheImage 中
show_image(TheImage, IDC_ShowImg); // 调用显示图片函数
cvReleaseImage(&ipl); // 释放 ipl 占用的内存
// TODO: 在此添加控件通知处理程序代码
}
</span>
五、相关问题的解决
1、OpenCV2.4.8找不到CImage(CvvImage)的解决办法:为了不和MFC中的CImage冲突,我们重新将CvvImage定义为CvImage。
在需要的地方引入 #include "CvvImage.h" 就可以用了。
<span style="font-family:Microsoft YaHei;">为了不和MFC中的CImage冲突,我们重新将CvvImage定义为CvImage。
在需要的地方引入 #include "CvvImage.h" 就可以用了。
//================================================================
// CvvImage.h
//================================================================
#pragma once
#ifndef CVVIMAGE_CLASS_DEF
#define CVVIMAGE_CLASS_DEF
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgproc/imgproc_c.h"
class CvvImage
{
public:
CvvImage();
virtual ~CvvImage();
virtual bool Create( int width, int height, int bits_per_pixel, int image_origin = 0 );
virtual bool Load( const char* filename, int desired_color = 1 );
virtual bool LoadRect( const char* filename,
int desired_color, CvRect r );
#if defined WIN32 || defined _WIN32
virtual bool LoadRect( const char* filename,
int desired_color, RECT r )
{
return LoadRect( filename, desired_color,
cvRect( r.left, r.top, r.right - r.left, r.bottom - r.top ));
}
#endif
virtual bool Save( const char* filename );
virtual void CopyOf( CvvImage& image, int desired_color = -1 );
virtual void CopyOf( IplImage* img, int desired_color = -1 );
IplImage* GetImage() { return m_img; };
virtual void Destroy(void);
int Width() { return !m_img ? 0 : !m_img->roi ? m_img->width : m_img->roi->width; };
int Height() { return !m_img ? 0 : !m_img->roi ? m_img->height : m_img->roi->height;};
int Bpp() { return m_img ? (m_img->depth & 255)*m_img->nChannels : 0; };
virtual void Fill( int color );
virtual void Show( const char* window );
#if defined WIN32 || defined _WIN32
virtual void Show( HDC dc, int x, int y, int width, int height,
int from_x = 0, int from_y = 0 );
virtual void DrawToHDC( HDC hDCDst, RECT* pDstRect );
#endif
protected:
IplImage* m_img;
};
typedef CvvImage CvImage;
#endif
//================================================================
// CvvImage.cpp
//================================================================
#include "StdAfx.h"
#include "CvvImage.h"
//
// Construction/Destruction
//
CV_INLINE RECT NormalizeRect( RECT r );
CV_INLINE RECT NormalizeRect( RECT r )
{
int t;
if( r.left > r.right )
{
t = r.left;
r.left = r.right;
r.right = t;
}
if( r.top > r.bottom )
{
t = r.top;
r.top = r.bottom;
r.bottom = t;
}
return r;
}
CV_INLINE CvRect RectToCvRect( RECT sr );
CV_INLINE CvRect RectToCvRect( RECT sr )
{
sr = NormalizeRect( sr );
return cvRect( sr.left, sr.top, sr.right - sr.left, sr.bottom - sr.top );
}
CV_INLINE RECT CvRectToRect( CvRect sr );
CV_INLINE RECT CvRectToRect( CvRect sr )
{
RECT dr;
dr.left = sr.x;
dr.top = sr.y;
dr.right = sr.x + sr.width;
dr.bottom = sr.y + sr.height;
return dr;
}
CV_INLINE IplROI RectToROI( RECT r );
CV_INLINE IplROI RectToROI( RECT r )
{
IplROI roi;
r = NormalizeRect( r );
roi.xOffset = r.left;
roi.yOffset = r.top;
roi.width = r.right - r.left;
roi.height = r.bottom - r.top;
roi.coi = 0;
return roi;
}
void FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int origin )
{
assert( bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));
BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);
memset( bmih, 0, sizeof(*bmih));
bmih->biSize = sizeof(BITMAPINFOHEADER);
bmih->biWidth = width;
bmih->biHeight = origin ? abs(height) : -abs(height);
bmih->biPlanes = 1;
bmih->biBitCount = (unsigned short)bpp;
bmih->biCompression = BI_RGB;
if( bpp == 8 )
{
RGBQUAD* palette = bmi->bmiColors;
int i;
for( i = 0; i < 256; i++ )
{
palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
palette[i].rgbReserved = 0;
}
}
}
CvvImage::CvvImage()
{
m_img = 0;
}
void CvvImage::Destroy()
{
cvReleaseImage( &m_img );
}
CvvImage::~CvvImage()
{
Destroy();
}
bool CvvImage::Create( int w, int h, int bpp, int origin )
{
const unsigned max_img_size = 10000;
if( (bpp != 8 && bpp != 24 && bpp != 32) ||
(unsigned)w >= max_img_size || (unsigned)h >= max_img_size ||
(origin != IPL_ORIGIN_TL && origin != IPL_ORIGIN_BL))
{
assert(0); // most probably, it is a programming error
return false;
}
if( !m_img || Bpp() != bpp || m_img->width != w || m_img->height != h )
{
if( m_img && m_img->nSize == sizeof(IplImage))
Destroy();
m_img = cvCreateImage( cvSize( w, h ), IPL_DEPTH_8U, bpp/8 );
}
if( m_img )
m_img->origin = origin == 0 ? IPL_ORIGIN_TL : IPL_ORIGIN_BL;
return m_img != 0;
}
void CvvImage::CopyOf( CvvImage& image, int desired_color )
{
IplImage* img = image.GetImage();
if( img )
{
CopyOf( img, desired_color );
}
}
#define HG_IS_IMAGE(img) \
((img) != 0 && ((const IplImage*)(img))->nSize == sizeof(IplImage) && \
((IplImage*)img)->imageData != 0)
void CvvImage::CopyOf( IplImage* img, int desired_color )
{
if( HG_IS_IMAGE(img) )
{
int color = desired_color;
CvSize size = cvGetSize( img );
if( color < 0 )
color = img->nChannels > 1;
if( Create( size.width, size.height,
(!color ? 1 : img->nChannels > 1 ? img->nChannels : 3)*8,
img->origin ))
{
cvConvertImage( img, m_img, 0 );
}
}
}
bool CvvImage::Load( const char* filename, int desired_color )
{
IplImage* img = cvLoadImage( filename, desired_color );
if( !img )
return false;
CopyOf( img, desired_color );
cvReleaseImage( &img );
return true;
}
bool CvvImage::LoadRect( const char* filename,
int desired_color, CvRect r )
{
if( r.width < 0 || r.height < 0 ) return false;
IplImage* img = cvLoadImage( filename, desired_color );
if( !img )
return false;
if( r.width == 0 || r.height == 0 )
{
r.width = img->width;
r.height = img->height;
r.x = r.y = 0;
}
if( r.x > img->width || r.y > img->height ||
r.x + r.width < 0 || r.y + r.height < 0 )
{
cvReleaseImage( &img );
return false;
}
if( r.x < 0 )
{
r.width += r.x;
r.x = 0;
}
if( r.y < 0 )
{
r.height += r.y;
r.y = 0;
}
if( r.x + r.width > img->width )
r.width = img->width - r.x;
if( r.y + r.height > img->height )
r.height = img->height - r.y;
cvSetImageROI( img, r );
CopyOf( img, desired_color );
cvReleaseImage( &img );
return true;
}
bool CvvImage::Save( const char* filename )
{
if( !m_img )
return false;
cvSaveImage( filename, m_img );
return true;
}
void CvvImage::Show( const char* window )
{
if( m_img )
cvShowImage( window, m_img );
}
void CvvImage::Show( HDC dc, int x, int y, int w, int h, int from_x, int from_y )
{
if( m_img && m_img->depth == IPL_DEPTH_8U )
{
uchar buffer[sizeof(BITMAPINFOHEADER) + 1024];
BITMAPINFO* bmi = (BITMAPINFO*)buffer;
int bmp_w = m_img->width, bmp_h = m_img->height;
FillBitmapInfo( bmi, bmp_w, bmp_h, Bpp(), m_img->origin );
from_x = MIN( MAX( from_x, 0 ), bmp_w - 1 );
from_y = MIN( MAX( from_y, 0 ), bmp_h - 1 );
int sw = MAX( MIN( bmp_w - from_x, w ), 0 );
int sh = MAX( MIN( bmp_h - from_y, h ), 0 );
SetDIBitsToDevice(
dc, x, y, sw, sh, from_x, from_y, from_y, sh,
m_img->imageData + from_y*m_img->widthStep,
bmi, DIB_RGB_COLORS );
}
}
void CvvImage::DrawToHDC( HDC hDCDst, RECT* pDstRect )
{
if( pDstRect && m_img && m_img->depth == IPL_DEPTH_8U && m_img->imageData )
{
uchar buffer[sizeof(BITMAPINFOHEADER) + 1024];
BITMAPINFO* bmi = (BITMAPINFO*)buffer;
int bmp_w = m_img->width, bmp_h = m_img->height;
CvRect roi = cvGetImageROI( m_img );
CvRect dst = RectToCvRect( *pDstRect );
if( roi.width == dst.width && roi.height == dst.height )
{
Show( hDCDst, dst.x, dst.y, dst.width, dst.height, roi.x, roi.y );
return;
}
if( roi.width > dst.width )
{
SetStretchBltMode(
hDCDst, // handle to device context
HALFTONE );
}
else
{
SetStretchBltMode(
hDCDst, // handle to device context
COLORONCOLOR );
}
FillBitmapInfo( bmi, bmp_w, bmp_h, Bpp(), m_img->origin );
::StretchDIBits(
hDCDst,
dst.x, dst.y, dst.width, dst.height,
roi.x, roi.y, roi.width, roi.height,
m_img->imageData, bmi, DIB_RGB_COLORS, SRCCOPY );
}
}
void CvvImage::Fill( int color )
{
cvSet( m_img, cvScalar(color&255,(color>>8)&255,(color>>16)&255,(color>>24)&255) );
}</span>