MFC OpenCV:刷新图片以及防止窗口抖动的方法

  • 一、背景
  • 二、刷新方法
    • 2.1 先使PictrueContral控件不可见,后使其重新可见
    • 2.2 填充与MFC图像窗口背景相同的颜色
    • 2.3 填充图片
  • 三、参考文章

一、背景

  前置文章:MFC鼠标滚轮缩放OpenCV图片
  使用滚轮缩小图片,使其小于MFC的PictrueContral控件大小时,发现缩小前的图片依旧存在,缩小后的图片重叠在其上。具体错误图片如下所示:
  故缩放前应先刷新图片

二、刷新方法

2.1 先使PictrueContral控件不可见,后使其重新可见

实现方法:
  在显示图片之前添加如下代码刷新MFC的PictrueContral控件,其中IDC_STATIC为PictrueContral控件ID:

    GetDlgItem(IDC_STATIC)->ShowWindow(FALSE);GetDlgItem(IDC_STATIC)->ShowWindow(TRUE);

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;//原始图片#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,表示原图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<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 CMFCApplication1Dlg::OnQueryDragIcon()
{return static_cast<HCURSOR>(m_hIcon);
}BOOL CMFCApplication1Dlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{// TODO: 在此添加消息处理程序代码和/或调用默认值GetDlgItem(IDC_STATIC)->ShowWindow(FALSE);GetDlgItem(IDC_STATIC)->ShowWindow(TRUE);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);
}

运行结果:
  添加刷新代码后结果如下图所示。此方法虽然代码简单,最终结果也正确,但刷新图片时MFC图像窗口出现抖动,即刷新图片时间过长导致刷新时出现短暂空白。

2.2 填充与MFC图像窗口背景相同的颜色

实现方法:
  在显示图片前添加如下代码:

    CStatic* pStatic = (CStatic*)GetDlgItem(IDC_STATIC);CRect rect1;pStatic->GetClientRect(&rect1);//获取MFC图像窗口相对于窗口用户区左上角的坐标pStatic->GetDC()->FillSolidRect(rect1.left, rect1.top, rect1.Width(), rect1.Height(), RGB(255, 255, 255));//填充白色

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;//原始图片#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,表示原图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<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 CMFCApplication1Dlg::OnQueryDragIcon()
{return static_cast<HCURSOR>(m_hIcon);
}BOOL CMFCApplication1Dlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{// TODO: 在此添加消息处理程序代码和/或调用默认值CStatic* pStatic = (CStatic*)GetDlgItem(IDC_STATIC);CRect rect1;pStatic->GetClientRect(&rect1);//获取MFC图像窗口相对于窗口用户区左上角的坐标pStatic->GetDC()->FillSolidRect(rect1.left, rect1.top, rect1.Width(), rect1.Height(), RGB(255, 255, 255));//填充白色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);
}

运行结果:
  此方法同样能够刷新图片。针对小图片刷新、刷新操作速度慢、刷新频繁的情况,此方法基本可以避免窗口刷新造成抖动的情况。若快速且频繁刷新则会出现窗口抖动,图片闪烁的情况。

2.3 填充图片

实现方法:
  既然MFC刷新图片必然会出现图像窗口短暂空白的情况,若此段时间短到人眼无法识别,则无抖动闪烁情况。若时间过长则会出现窗口抖动、图片闪烁情况。
  那么可以新建一张与背景色相同的空白图片,然后在此空白图片上填充缩放后的图片。每次显示此图片时,其总能完整覆盖图片窗口而不再需要刷新图片。

实现步骤:
1、添加全局变量和函数声明

Mat g_matOriginal;//原始图片
Mat FileImage(Mat mat);

2、函数定义

Mat FileImage(Mat mat)
{Mat zero = Mat::Mat(g_szWin, CV_8UC3, Scalar(255, 255, 255));//定义一个与图片控件一样大,与背景色相同的空白图片Mat roi(zero, Rect(0, 0, mat.cols, mat.rows));//新建一个与mat相同大小的感兴趣区域mat.copyTo(roi);//将mat拷贝到感兴趣区域return zero;
}

3、显示图片判断

if (w*g_iZoom < g_szWin.width || h*g_iZoom < g_szWin.height)//图片小于MFC图片窗口时{imshow("ImageShow", FileImage(mat));//显示缩放后图片}else{imshow("ImageShow", mat);//显示缩放后图片}

4、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;//缩放步距
Size g_szWin = Size(0, 0);//图像窗口大小
Mat g_matOriginal;//原始图片
Mat FileImage(Mat mat);#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,表示原图g_matOriginal = imread("E:\\vs\\image\\11.png");//opencv读取图片imshow("ImageShow", g_matOriginal);//opencv显示图片waitKey(1);CRect rect;GetDlgItem(IDC_STATIC)->GetClientRect(&rect);//获取句柄g_szWin = Size(rect.right - rect.left - 2, rect.bottom - rect.top - 2);//获取图像窗口大小return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。void CMFCApplication1Dlg::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 CMFCApplication1Dlg::OnQueryDragIcon()
{return static_cast<HCURSOR>(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); //按比例缩小图片}if (w*g_iZoom < g_szWin.width || h*g_iZoom < g_szWin.height)//图片小于MFC图片窗口时{imshow("ImageShow", FileImage(mat));//显示缩放后图片}else{imshow("ImageShow", mat);//显示缩放后图片}waitKey(1);}return CDialogEx::OnMouseWheel(nFlags, zDelta, pt);
}Mat FileImage(Mat mat)
{Mat zero = Mat::Mat(g_szWin, CV_8UC3, Scalar(255, 255, 255));//定义一个与图片控件一样大,与背景色相同的空白图片Mat roi(zero, Rect(0, 0, mat.cols, mat.rows));//新建一个与mat相同大小的感兴趣区域mat.copyTo(roi);//将mat拷贝到感兴趣区域return zero;
}

5、运行结果

三、参考文章

MFC里清除picture control上的图片,使他呈现原始控件的灰色

MFC OpenCV:刷新图片以及防止窗口抖动的方法相关推荐

  1. Android开发之刷新图片到相册 | 刷新视频到相册的方法区分发广播刷新方法

    我们很多app会有保存图片和保存视频,保存成功后一般在最近文件或者相册就能看到了,这个需要我们在保存文件后自行刷新到相册中,以前老版本方法通过广播刷新方法在API29中已经废弃了无法使用,咱们提供了新 ...

  2. MFC显示Mat图片

    Opencv在1.0时代,在MFC框架上显示图片可以通过Cvvimage类里的DrawPicToHDC( IplImage *img, UINT ID)方法方便的显示出来,当然当时使用的还是IpIIm ...

  3. 调用opencv3.x 库,在MFC中显示图片

    调用opencv3.x 库,在MFC中显示图片 使用opencv和MFC显示图片的方法大致分为以下几种: 1:将opencv的显示对话框嵌入到MFC窗口. 2:使用CvvImage类显示图片. 3:将 ...

  4. python opencv调节图片亮度与对比度

    python opencv调节图片亮度与对比度 亮度调整是将图像像素的强度整体变大/变小,对比度调整指的是图像暗处变得更暗,亮出变得更亮,从而拓宽某个区域内的显示精度. 创建两个滑动条分别调整对比度和 ...

  5. opencv 调整窗口大小_opencv改变imshow窗口大小,窗口位置的方法

    opencv改变imshow窗口大小,窗口位置的方法 如下所示: cv2.HoughLinesP cv2.namedWindow("enhanced",0); cv2.resize ...

  6. 2021-01-07 python opencv调节图片亮度与对比度

    python opencv调节图片亮度与对比度 度调整是将图像像素的强度整体变大/变小,对比度调整指的是图像暗处变得更暗,亮出变得更亮,从而拓宽某个区域内的显示精度. 创建两个滑动条分别调整对比度和亮 ...

  7. MFC+OPENCV实现角点检测

    MFC+OPENCV实现角点检测: // 角点检测 // 根据<基于OpenCV的计算机视觉技术实现>#define max_corners 200; // 限定的最大角点数IplImag ...

  8. ctf 改变图片高度_每天一分钟,python一点通(opencv的图片处理方法)

    有网友私信小编说,小编的文章很好,讲解的也很详细,但是有些知识点很深奥,对初学者不是很友好,回想小编的文章虽然几乎每条代码都有介绍,但是很多函数没有太详细,小编后期会重启 <每天一分钟,pyth ...

  9. MFC对话框动态刷新图片(仿照全屏屏保)

    最近做MFC对话框工程 用到全屏刷新图片的功能,由于功能实现比较简单,便使用CImage类配合定时器制作,下面贴上实现方式: 增加消息响应事件: //在对话框属性的消息中 添加WM_PAINT与WM_ ...

最新文章

  1. Java向数据库中插入Boolean类型的字段
  2. 动态数组的定义和声明(c++)
  3. java 2d 绘图教程_Java标准教程:Java 2D绘图--第2章 从绘图开始
  4. android 生成推广图片保存_flutter 如何生成图片并保存到手机相册?
  5. OJ1005: 整数幂
  6. 线程池很难么?带你从头到尾捋一遍,不信你听不懂!
  7. Try Catch C++ 异常捕获
  8. 如何造数据——分分钟变成造数据大师
  9. 噪声的频谱分析的重要意义_一文带你了解频谱仪和示波器究竟有何区别(涨知识了)...
  10. Mysql常见的引擎
  11. knx智能照明控制系统电路图_汇勒智能照明控制-KNX/EIB系统如何安装跟布线的
  12. 360杀毒软件安装在windows2003系统的解决方法
  13. 主机无法ping通虚拟机xp系统
  14. 诗词大全给力版_思维导图 | 6种高效记忆法,教你速背古诗词!
  15. win10网信政府版安装.NET Framework3.5
  16. 计算机会计信息系统中凭证日期应该是,《电算化会计》期中考试试题.doc
  17. 2sum,3sum,4sum问题总结
  18. Markdown编辑器如何配置图片大小
  19. 图标快速定位工具 ElementUI FontAwesome iView
  20. JavaScript(Ajax)和Cookie的同源策略

热门文章

  1. java swing qq_使用java swing实现qq登录界面示例分享
  2. php mysql prepare_php mysqli prepare使用实例介绍
  3. 【科普】什么是@[TOC]()?
  4. JsonPath完全介绍及详细使用教程
  5. Python2/3 字符串转16进制 16进制转字符串
  6. 点云压缩 GPCC属性编码 LOD划分方式介绍(G-PCC codec description v12)
  7. 90后陪酒女做亚马逊测评月入上百万!从陪酒女蜕变成白富美!她是如何做的?
  8. python 简单万年历
  9. discuz x3.4在https下实现首页去除 portal.php 尾巴
  10. 关键字static的作用