前置文章:MFC显示OpenCV图片的三种详细方法
在利用OpenCV嵌套MFC窗口显示图片后,希望通过鼠标滚轮函数缩放图片。
1、新建MFC应用程序。
2、配置OpenCV运行环境。
3、添加MFC的Pictrue Control控件
4、编写代码。只需修改MFCApplication1Dlg.cpp文件。
添加的代码:
//在MFCApplication1Dlg.cpp添加库文件
#include "opencv2/opencv.hpp"
using namespace cv;
//在MFCApplication1Dlg.cpp添加全局变量
double g_iZoom = 1;//初始缩放值
double g_iRadio = 0.1;//缩放步距
Mat g_matOriginal;//原始图片
//在MFCApplication1Dlg.cpp的CMFCApplication1Dlg::OnInitDialog()函数中添加如下代码:
namedWindow("ImageShow");//创建OpenCV窗口
HWND hWnd = (HWND)cvGetWindowHandle("ImageShow");//嵌套opencv窗口
HWND hParent = ::GetParent(hWnd);
::SetParent(hWnd, GetDlgItem(IDC_STATIC)->m_hWnd);
::ShowWindow(hParent, SW_HIDE);
g_iZoom = 1;//初始缩放值为1,表示原图
g_matOriginal = imread("E:\\vs\\image\\11.png");//opencv读取图片
imshow("ImageShow", g_matOriginal);//opencv显示图片
waitKey(1);
5、初步运行结果。到此可以简单显示图片。
6、右键MFC的Pictrue Control控件,添加MFC的鼠标滚轮函数。
BOOL CMFCApplication1Dlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CRect rect;
GetDlgItem(IDC_STATIC)->GetWindowRect(&rect);//获取MFC图像显示区域
Point p(pt.x, pt.y);//opencv鼠标坐标
Rect r(rect.left, rect.top, rect.right, rect.bottom);//opencv窗口显示区域
if (r.contains(p)) //鼠标放在图片窗口上
{
int w = g_matOriginal.cols, h =g_matOriginal.rows;//原图宽高
Mat mat;
if (zDelta > 0)//放大图片
{
double zoom = g_iZoom + g_iRadio;
if (w * zoom * h * zoom < 3000 * 3000)//图片宽高<3000*3000时缩放值才会变大
{
g_iZoom = zoom;
}
resize(g_matOriginal, mat, Size(), g_iZoom, g_iZoom, INTER_LINEAR); //按比例放大图片
}
else if (zDelta < 0)//缩小图片
{
double zoom = g_iZoom - g_iRadio;
if (w * zoom * h * zoom > 100 * 100)//图片宽高>100*100时缩放值才会变小
{
g_iZoom = zoom;
}
resize(g_matOriginal, mat, Size(), g_iZoom, g_iZoom, INTER_AREA); //按比例缩小图片
}
imshow("ImageShow", mat);//显示缩放后图片
waitKey(1);
}
return CDialogEx::OnMouseWheel(nFlags, zDelta, pt);
}
MFCApplication1Dlg.h
// MFCApplication1Dlg.h: 头文件
//
#pragma once
// CMFCApplication1Dlg 对话框
class CMFCApplication1Dlg : public CDialogEx
{
// 构造
public:
CMFCApplication1Dlg(CWnd* pParent = nullptr); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_MFCAPPLICATION1_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
};
MFCApplication1Dlg.cpp
// MFCApplication1Dlg.cpp: 实现文件
//
#include "stdafx.h"
#include "MFCApplication1.h"
#include "MFCApplication1Dlg.h"
#include "afxdialogex.h"
#include "opencv2/opencv.hpp"
using namespace cv;
double g_iZoom = 1;//初始缩放值
double g_iRadio = 0.1;//缩放步距
Mat g_matOriginal;//原始图片
//void OpenCVMouse(int event, int x, int y, int flags, void* param);
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CMFCApplication1Dlg 对话框
CMFCApplication1Dlg::CMFCApplication1Dlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_MFCAPPLICATION1_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_MOUSEWHEEL()
END_MESSAGE_MAP()
// CMFCApplication1Dlg 消息处理程序
BOOL CMFCApplication1Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
namedWindow("ImageShow");//创建OpenCV窗口
HWND hWnd = (HWND)cvGetWindowHandle("ImageShow");//嵌套opencv窗口
HWND hParent = ::GetParent(hWnd);
::SetParent(hWnd, GetDlgItem(IDC_STATIC)->m_hWnd);
::ShowWindow(hParent, SW_HIDE);
g_iZoom = 1;//初始缩放值为1,表示原图
//setMouseCallback("ImageShow", OpenCVMouse, NULL); // 鼠标事件
g_matOriginal = imread("E:\\vs\\image\\11.png");//opencv读取图片
imshow("ImageShow", g_matOriginal);//opencv显示图片
waitKey(1);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CMFCApplication1Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast(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 CMFCApplication1Dlg::OnQueryDragIcon()
{
return static_cast(m_hIcon);
}
BOOL CMFCApplication1Dlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CRect rect;
GetDlgItem(IDC_STATIC)->GetWindowRect(&rect);//获取MFC图像显示区域
Point p(pt.x, pt.y);//opencv鼠标坐标
Rect r(rect.left, rect.top, rect.right, rect.bottom);//opencv窗口显示区域
if (r.contains(p)) //鼠标放在图片窗口上
{
int w = g_matOriginal.cols, h =g_matOriginal.rows;//原图宽高
Mat mat;
if (zDelta > 0)//放大图片
{
double zoom = g_iZoom + g_iRadio;
if (w * zoom * h * zoom < 3000 * 3000)//图片宽高<3000*3000时缩放值才会变大
{
g_iZoom = zoom;
}
resize(g_matOriginal, mat, Size(), g_iZoom, g_iZoom, INTER_LINEAR); //按比例放大图片
}
else if (zDelta < 0)//缩小图片
{
double zoom = g_iZoom - g_iRadio;
if (w * zoom * h * zoom > 100 * 100)//图片宽高>100*100时缩放值才会变小
{
g_iZoom = zoom;
}
resize(g_matOriginal, mat, Size(), g_iZoom, g_iZoom, INTER_AREA); //按比例缩小图片
}
imshow("ImageShow", mat);//显示缩放后图片
waitKey(1);
}
return CDialogEx::OnMouseWheel(nFlags, zDelta, pt);
}
//void OpenCVMouse(int event, int x, int y, int flags, void* param)//opencv滚轮函数
//{
// if (event == EVENT_MOUSEWHEEL)//鼠标滚轮函数
// {
// TRACE("EVENT_MOUSEWHEEL\n");
// }
// if (event == EVENT_LBUTTONDOWN)
// {
// TRACE("EVENT_LBUTTONDOWN\n");//鼠标左键点击函数
// }
//}
Opencv窗口嵌套入MFC后,其鼠标按键函数有效,但其鼠标滚轮函数无效,只能使用MFC自身的鼠标滚轮函数。
如上图所示,当鼠标左键按下时输出栏显示如下内容:
atlTraceGeneral - EVENT_LBUTTONDOWN
atlTraceGeneral - EVENT_LBUTTONDOWN
atlTraceGeneral - EVENT_LBUTTONDOWN
而当鼠标滚轮前后滚动时并未出现:
atlTraceGeneral - EVENT_MOUSEWHEEL
如此说明opencv的鼠标滚轮函数无效。