影像批量畸变纠正--双像三维建模小软件开发实例(三)

在(二)中,我们已经得到了相机的畸变参数,利用这参数纠正图像原理十分简单,不再赘述。本文主要介绍如何实现批量的畸变纠正,同时实时显示处理进度,程序运行界面如图1所示


图 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中,我们就可以把消息发送给这个指针,最终让对话框本身接收并处理消息。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值