本文介紹MFC中圖像採集及圖像處理的多線程編方法。創建了三個線程,分別爲圖像採集、圖像處理及圖像顯示線程。線程之間的共享數據有保存的圖像鏈表和圖像處理結果存儲結構。
圖像鏈表:list<Hobject> imgList;
存儲結構體:
struct ResultContainer
{
Hobject result_img;
HTuple time_needed;
HTuple result_handle;
HTuple result_data;
};
創建4個事件保證線程同步性
HANDLE fgStopEvent;
HANDLE newImageEvent;
HANDLE newResultEvent;
HANDLE containerIsFreeEvent;
使用2個關鍵段保證共享數據使用的互斥性
CRITICAL_SECTION newImageMutex;
CRITICAL_SECTION resultDataMutex;
同時在頭文件中加入私有成員變量:
HANDLE dispThrHandle; //Win32線程句柄
unsigned int dispThreadId; //Win32線程標識符
HANDLE ipThrHandle; //Win32線程句柄
unsigned int ipThreadId; //Win32線程標識符
HANDLE fgThrHandle; //Win32線程句柄
unsigned int fgThreadId; //Win32線程標識符
- 在初始化中進行關鍵段的初始化,創建線程等其他數據初始化過程:
關鍵段初始化:
InitializeCriticalSection(&newImageMutex);
InitializeCriticalSection(&resultDataMutex);
設置事件句柄以同步線程:
fgStopEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
newImageEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
newResultEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
containerIsFreeEvent =CreateEvent(NULL,FALSE,TRUE,NULL);
初始化共享數據:
resultData.time_needed = NULL;
resultData.result_img = NULL;
resultData.result_handle = NULL;
resultData.result_data = NULL;
其他:
ResetEvent(fgStopEvent); //設置fgStopEvent爲無信號狀態
InitialGrabOfImage(); //圖像採集初始化
- 設置一個啓動按鈕,開啓線程,線程開啓函數如下:
void CMultiThreading::StartThreads()
{
//所有事件設置爲初始狀態
ResetEvent(fgStopEvent);
ResetEvent(newImageEvent);
ResetEvent(newResultEvent);
SetEvent(containerIsFreeEvent);
imgList.clear();
// 開啓線程
dispThrHandle = (HANDLE)_beginthreadex(NULL,0,
(unsigned (__stdcall *)(void*))&DISPRun,
this,
0,
&dispThreadId);
ipThrHandle = (HANDLE)_beginthreadex(NULL, 0,
(unsigned (__stdcall *)(void*))&IPRun,
this,
0,
&ipThreadId);
fgThrHandle = (HANDLE)_beginthreadex(NULL, 0,
(unsigned (__stdcall *)(void*))&ImgAcqRun,
this,
0,
&fgThreadId);
}
- 設置一個停止按鈕,停止所有線程,只需將停止事件設置爲有信號狀態:
SetEvent(fgStopEvent);
- 圖像採集線程:
void ImgAcqRun(void *pars)
{
HTuple sequenceName;
Hobject grabbedImage;
Hlong FGHandle;
CMultiThreadingDlg *MultiThrDlg = (CMultiThreadingDlg*) pars;
// --------------------- INIT ----------------------
sequenceName = "datacode/ecc200/ecc200.seq";
open_framegrabber("File",1,1,0,0,0,0,"default",-1,
"default",-1,"default",sequenceName,
"default",-1,-1,&FGHandle);
// ----------------- WAIT FOR EVENTS ---------------
while (WAIT_OBJECT_0 != WaitForSingleObject((MultiThrDlg->fgStopEvent),0)) //Stop按鈕沒有觸發
{
grab_image_async(&grabbedImage,FGHandle,-1);
EnterCriticalSection(&MultiThrDlg->newImageMutex); // CriticalSect關鍵段
if((MultiThrDlg->imgList).size()<MAX_BUFFERS)
{
(MultiThrDlg->imgList).push_back(grabbedImage);
}
LeaveCriticalSection(&MultiThrDlg->newImageMutex); // CriticalSect
SetEvent(MultiThrDlg->newImageEvent); //觸發事件
}
// ----------------- RESET/CLOSE ALL HANDLES -------
ResetEvent( MultiThrDlg->newImageEvent);
close_framegrabber(FGHandle);
return;
}
- 圖像處理線程:
void IPRun(void *pars)
{
HTuple T1,resultHandles,T2;
Hobject result_data, image;
CString sVal;
HANDLE eventHandle[2];
struct ResultContainer ResultDataIP;
CMultiThreadingDlg *MultiThrDlg = (CMultiThreadingDlg*) pars;
// -------------------- INIT ------------------------
//圖像初始化操作
// ----------------- WAIT FOR EVENTS ---------------
eventHandle[0] = (*MultiThrDlg).newImageEvent;
eventHandle[1] = (*MultiThrDlg).fgStopEvent;
while (WAIT_OBJECT_0 == WaitForMultipleObjects(2,eventHandle,
FALSE,INFINITE))
{
EnterCriticalSection(&MultiThrDlg->newImageMutex); // CriticalSect
image = (MultiThrDlg->imgList).front();
MultiThrDlg->imgList.pop_front();
LeaveCriticalSection(&MultiThrDlg->newImageMutex); // CriticalSect
count_seconds(&T1);
//圖像處理過程
count_seconds(&T2);
ResultDataIP.time_needed = 1000*(T2[0].D() - T1[0].D());
ResultDataIP.result_img = image;
ResultDataIP.result_handle = resultHandles;
ResultDataIP.result_data = result_data;
WaitForSingleObject(MultiThrDlg->containerIsFreeEvent,INFINITE);
EnterCriticalSection(&MultiThrDlg->resultDataMutex);
// CriticalSect
MultiThrDlg->resultData = ResultDataIP;
// CriticalSect
LeaveCriticalSection(&MultiThrDlg->resultDataMutex);
ResetEvent(MultiThrDlg->containerIsFreeEvent);
SetEvent( MultiThrDlg->newResultEvent);
}
// ----------------- RESET/CLOSE ALL HANDLES -------
ResetEvent(MultiThrDlg->newResultEvent);
return;
}
- 顯示線程:
void DISPRun(void *pars)
{
HTuple time,resultHandles,i;
Hobject result_data, image;
CString sVal;
Hlong wWindowID;
CRect rect;
HANDLE eventHandle[2];
struct ResultContainer rData;
CMultiThreadingDlg *MultiThrDlg = (CMultiThreadingDlg*) pars;
wWindowID = (Hlong)MultiThrDlg->ipWinStatic.m_hWnd;
MultiThrDlg->ipWinStatic.GetClientRect(&rect);
// -------------------- INIT -----------------------
set_check("~father");
open_window(0,0,rect.Width(),rect.Height(),wWindowID,
"visible","", &(MultiThrDlg->windowID));
set_check("father");
set_window_attr("border_width",0);
set_part(MultiThrDlg->windowID,0,0,MultiThrDlg->height-1,
MultiThrDlg->width-1);
set_color((MultiThrDlg->windowID),"green");
set_line_width(MultiThrDlg->windowID,3);
eventHandle[0] = ((*MultiThrDlg).newResultEvent);
eventHandle[1] = ((*MultiThrDlg)).fgStopEvent;
// ----------------- WAIT FOR EVENTS ---------------
while (WAIT_OBJECT_0 == WaitForMultipleObjects(2,eventHandle,
FALSE,INFINITE))
{
EnterCriticalSection(&MultiThrDlg->resultDataMutex); // CriticalSect
rData = MultiThrDlg->resultData; // CriticalSect
LeaveCriticalSection(&MultiThrDlg->resultDataMutex);
SetEvent(MultiThrDlg->containerIsFreeEvent);
time = rData.time_needed;
image = rData.result_img;
resultHandles = rData.result_handle;
result_data = rData.result_data;
disp_obj(image,HTuple(MultiThrDlg->windowID));
sVal.Format("%4.2f",time[0].D());
(MultiThrDlg->ipProcTime).SetWindowText(sVal + " ms");
disp_obj(symbolXLDs,HTuple(MultiThrDlg->windowID));
for (i=0; i<=(resultHandles.Num())-1; i+=1)
{
(MultiThrDlg->ipImgLabel).SetWindowText(decodedDataStrings[i]);
}
}
// ----------------- RESET/CLOSE ALL HANDLES ------
close_window(MultiThrDlg->windowID);
SetEvent(MultiThrDlg->containerIsFreeEvent);
MultiThrDlg->ipProcTime.SetWindowText("");
return;
}