影像批量畸变纠正--双像三维建模小软件开发实例(三)
2014-01-11 14:22
162 查看
在(二)中,我们已经得到了相机的畸变参数,利用这参数纠正图像原理十分简单,不再赘述。本文主要介绍如何实现批量的畸变纠正,同时实时显示处理进度,程序运行界面如图1所示
图 1. 图像畸变纠正程序运行界面
在ImageRectifier中,我们需要输入畸变参数和相机参数,然后把同一相机拍摄的多幅图像一次性输入,即可批量进行处理。程序附带了处理进度条,运行情况一目了然。
本程序的实现,最关键的是多线程的运用。我们可以在前端实时观看程序处理进度,同时程序后台不断地处理图像。前端的处理进度显示和后台的处理结果通过消息传递关联起来。下面我们首先简要介绍工作线程的原理,然后介绍本程序具体实现思路。
进程(process)是应用程序的一个运行实例,即一个运行中的应用程序,线程(thread)是隶属于进程的独立执行体,一个进程有且只有一个主线程,而同时可以拥有其他多个线程。线程分为工作线程(worker thread)和用户界面线程(user interface thread)两种,前者没有窗口,没有消息泵,不需要处理消息,后者有窗口,有消息泵可以处理界面消息。一般地,利用AfxBeginThread(ThreadProc,this)函数创建一个工作线程,ThreadProc是线程入口函数,this是传入线程的参数。在一个程序的主函数中利用AfxBeginThread函数启动线程后,线程会独立执行,当然,AfxBeginThread有其他一些缺省参数可以控制线程函数的执行时机,优先级等,在此我们不做研究。
1、消息和消息响应函数的关联(黑体显示):
BEGIN_MESSAGE_MAP(CImageRectifierDlg, CDialog)
//{{AFX_MSG_MAP(CImageRectifierDlg)
ON_MESSAGE(WM_USERMSG,OnMyMessage)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
2、WM_USERMSG的定义
#define WM_USERMSG WM_USER+100
这样做的目的是为了避免和其他消息数值冲突
3、OnMyMessage()是对话框类CImageRectifierDlg的成员函数,在该函数中完成进度条的更新
另外非常重要的一点,我们的线程函数是全局函数,而消息响应函数却是对话框类CImageRectifier的成员函数,他们如何关联的呢?是通过线程函数的参数LPVOID型的pParam来实现的。具体地,我们在CImageRectifier::OnOK()中启动线程时是这样启动的:thread = AfxBeginThread(MyWorkThread,(LPVOID)this),这就把对话框对象本身的指针作为参数传给了线程函数MyWorkThread,于是在MyWorkThread中,我们就可以把消息发送给这个指针,最终让对话框本身接收并处理消息。
图 1. 图像畸变纠正程序运行界面
在ImageRectifier中,我们需要输入畸变参数和相机参数,然后把同一相机拍摄的多幅图像一次性输入,即可批量进行处理。程序附带了处理进度条,运行情况一目了然。
本程序的实现,最关键的是多线程的运用。我们可以在前端实时观看程序处理进度,同时程序后台不断地处理图像。前端的处理进度显示和后台的处理结果通过消息传递关联起来。下面我们首先简要介绍工作线程的原理,然后介绍本程序具体实现思路。
一、工作线程原理介绍
参考《Visual C++面向对象编程教程(第二版)》(清华大学出版社)进程(process)是应用程序的一个运行实例,即一个运行中的应用程序,线程(thread)是隶属于进程的独立执行体,一个进程有且只有一个主线程,而同时可以拥有其他多个线程。线程分为工作线程(worker thread)和用户界面线程(user interface thread)两种,前者没有窗口,没有消息泵,不需要处理消息,后者有窗口,有消息泵可以处理界面消息。一般地,利用AfxBeginThread(ThreadProc,this)函数创建一个工作线程,ThreadProc是线程入口函数,this是传入线程的参数。在一个程序的主函数中利用AfxBeginThread函数启动线程后,线程会独立执行,当然,AfxBeginThread有其他一些缺省参数可以控制线程函数的执行时机,优先级等,在此我们不做研究。
二、利用工作线程实现进度显示和后台处理的关联
我们的思路是这样的,用户启动任务后,我们在主程序中启动一个线程函数,并把图像处理的任务交给这个线程函数,由它在后台执行,执行过程中不断发送消息给前端的主线程,前端的主线程一旦接收到消息则更新当前执行进度条。1、消息和消息响应函数的关联(黑体显示):
BEGIN_MESSAGE_MAP(CImageRectifierDlg, CDialog)
//{{AFX_MSG_MAP(CImageRectifierDlg)
ON_MESSAGE(WM_USERMSG,OnMyMessage)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
2、WM_USERMSG的定义
#define WM_USERMSG WM_USER+100
这样做的目的是为了避免和其他消息数值冲突
3、OnMyMessage()是对话框类CImageRectifierDlg的成员函数,在该函数中完成进度条的更新
LRESULT CImageRectifierDlg::OnMyMessage(WPARAM wParam, LPARAM lParam) { CString str; str.Format("%d",lParam); str += "%"; this->m_path_imgfile.SetItemText(wParam,1,str); this->m_path_imgfile.Update(wParam); return 1; }4、后台的线程函数处理任务和发送消息的方法
UINT MyWorkThread(LPVOID pParam) { CImageRectifierDlg* dlg = (CImageRectifierDlg*) pParam; CvMat *intrinsic_matrix = cvCreateMat(3,3,CV_32FC1); CvMat *distortion_coeffs = cvCreateMat(4,1,CV_32FC1); CV_MAT_ELEM(*intrinsic_matrix,float,0,0) = dlg->f1; CV_MAT_ELEM(*intrinsic_matrix,float,0,1) = 0; CV_MAT_ELEM(*intrinsic_matrix,float,0,2) = dlg->x0; CV_MAT_ELEM(*intrinsic_matrix,float,1,0) = 0; CV_MAT_ELEM(*intrinsic_matrix,float,1,1) = dlg->f2; CV_MAT_ELEM(*intrinsic_matrix,float,1,2) = dlg->y0; CV_MAT_ELEM(*intrinsic_matrix,float,2,0) = 0; CV_MAT_ELEM(*intrinsic_matrix,float,2,1) = 0; CV_MAT_ELEM(*intrinsic_matrix,float,2,2) = 1; CV_MAT_ELEM(*distortion_coeffs,float,0,0) = dlg->k1; CV_MAT_ELEM(*distortion_coeffs,float,1,0) = dlg->k2; CV_MAT_ELEM(*distortion_coeffs,float,2,0) = dlg->p1; CV_MAT_ELEM(*distortion_coeffs,float,3,0) = dlg->p2; IplImage *image = cvLoadImage(dlg->filepaths.at(0)); IplImage *mapx = cvCreateImage(cvGetSize(image),IPL_DEPTH_32F,1); IplImage *mapy = cvCreateImage(cvGetSize(image),IPL_DEPTH_32F,1); cvInitUndistortMap(intrinsic_matrix,distortion_coeffs,mapx,mapy); int i=0; CString str; for (i=0;i<dlg->filepaths.size();i++) { PostMessage(dlg->m_hWnd,WM_USERMSG,i,1); str = dlg->filepaths.at(i); image = cvLoadImage(str); IplImage *t = cvCloneImage(image); cvRemap(t,image,mapx,mapy); cvSaveImage(str+"Rectify.tif",image); cvReleaseImage(&t); PostMessage(dlg->m_hWnd,WM_USERMSG,i,100); } PostMessage(dlg->m_hWnd,WM_USERMSG,0,100); return 1; }稍微解释一下发送消息的函数PostMessage的参数,第一个参数是接收消息的窗口对象,这里就是对话框本身,第二个参数是消息标识,第三和第四个参数是传给消息响应函数(在这里即为OnMyMessage)的参数。
另外非常重要的一点,我们的线程函数是全局函数,而消息响应函数却是对话框类CImageRectifier的成员函数,他们如何关联的呢?是通过线程函数的参数LPVOID型的pParam来实现的。具体地,我们在CImageRectifier::OnOK()中启动线程时是这样启动的:thread = AfxBeginThread(MyWorkThread,(LPVOID)this),这就把对话框对象本身的指针作为参数传给了线程函数MyWorkThread,于是在MyWorkThread中,我们就可以把消息发送给这个指针,最终让对话框本身接收并处理消息。
相关文章推荐
- 核线影像制作--双像三维建模小软件开发实例(六)
- 人机交互量测同名点程序--双像三维建模小软件开发实例(四)
- 相对定向--双像三维建模小软件开发实例(五)
- 相机标定--双像三维建模小软件开发实例(二)
- 双像三维建模小软件开发实例(一)
- C#软件开发实例.私人订制自己的屏幕截图工具(四)基本截图功能实现
- C#软件开发实例.私人订制自己的屏幕截图工具(七)添加放大镜的功能
- 基于框架开发的办公软件实例
- 软件开发流程实例之一 :项目概述
- 第10章 开发实例-安全通信软件
- C#软件开发实例.私人订制自己的屏幕截图工具(五)针对拖拽时闪烁卡顿现象的优化
- 实例敏捷软件开发一: 会议助手APP之用户场景(User Scenarios)的构想和分析
- C#软件开发实例.私人订制自己的屏幕截图工具(六)添加配置管理功能
- C#软件开发实例.私人订制自己的屏幕截图工具(十一)编辑工具栏的实现
- 【分享】大量android/iphone软件开发资料和实例代码
- 账号批量注册软件开发启示录
- C#软件开发实例.私人订制自己的屏幕截图工具(五)针对拖拽时闪烁卡顿现象的优化
- ExtJS与.NET结合开发实例(Grid之批量删除篇)
- C#软件开发实例.私人订制自己的屏幕截图工具(七)添加放大镜的功能
- VARCHART XGantt应用实例:法国Volume Software的软件开发