全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:5624
推到 Plurk!
推到 Facebook!

請問從擷圖到影像相減怎麼做比較快

答題得分者是:arisaka_matsuri
ciy
一般會員


發表:10
回覆:19
積分:5
註冊:2006-10-26

發送簡訊給我
#1 引用回覆 回覆 發表時間:2007-07-02 19:59:34 IP:140.121.xxx.xxx 訂閱
 以下是我的程式部分
麻煩各位大大看看
有沒有其他地方要改進或是有其他比較快的寫法
感恩~

<textarea class="cpp" rows="10" cols="60" name="code">//先抓一張背景圖------------------------------------------------------------- capFileSaveDIB(ghCapWnd1,"Picture\\pic.bmp"); Form1->Image2->Picture->LoadFromFile("Picture\\pic.bmp"); Graphics::TBitmap *Bitmap2=new Graphics::TBitmap; Byte *ptr2; Bitmap2= Image2->Picture->Bitmap; //以下寫在Timer裡---------------------------------------------------------- hDC = GetDC(Form1->Panel1->Handle); csBuf->Handle = hDC; Bitmap1->Width = Form1->Panel1->Width; Bitmap1->Height = Form1->Panel1->Height; Bitmap1->PixelFormat= pf24bit; Bitmap1->Canvas->CopyRect(Rect(0, 0, Bitmap1->Width, Bitmap1->Height), csBuf, Rect(0, 0, Form1->Panel1->Width, Form1->Panel1->Height)); Image1->Picture->Bitmap = Bitmap1 ; for ( y = Ymin; y < Ymax; y ) { ptr1 = (Byte *)Bitmap1->ScanLine[y]; ptr2 = (Byte *)Bitmap2->ScanLine[y]; for ( x = Xmin; x < Xmax; x ) { // 影像灰階化&影像相減 show1[x][y]=abs(0.299*(ptr1[x*3]-ptr2[x*3]) 0.587*(ptr1[x*3 1]-ptr2[x*3 1]) 0.114*(ptr1[x*3 2]-ptr2[x*3 2])); // 影像二值化閥值,用於過濾雜訊,將圖轉成白與黑------------------ if (show1[x][y] < TwoTh) //做第一張圖 { show1[x][y]=255; } else { show1[x][y]=0; } } </textarea><br /> ReleaseDC(0 , hDC); //最後少加了
編輯記錄
ciy 重新編輯於 2007-07-02 20:00:43, 註解 無‧
ciy 重新編輯於 2007-07-02 20:02:13, 註解 無‧
taishyang
站務副站長


發表:377
回覆:5490
積分:4563
註冊:2002-10-08

發送簡訊給我
#2 引用回覆 回覆 發表時間:2007-07-03 10:12:40 IP:122.124.xxx.xxx 未訂閱
capFileSaveDIB(ghCapWnd1,"Picture\\pic.bmp");
Form1->Image2->Picture->LoadFromFile("Picture\\pic.bmp");
不要藉由檔案應該可以更快一點
你可以查一下站上有利用CALLBACK取得source的範例
而這source可以暫存成TMemoryStream or Graphics::TBitmap做後續的處理
ciy
一般會員


發表:10
回覆:19
積分:5
註冊:2006-10-26

發送簡訊給我
#3 引用回覆 回覆 發表時間:2007-07-03 12:01:45 IP:140.121.xxx.xxx 訂閱
謝謝 taishyang 大大的回覆
可是我從檔案抓到 Image2 只抓了一次,就沒洗掉當背景圖
之後都由 hDC = GetDC(Form1->Panel1->Handle)....在抓圖相減
降會變慢嗎??
taishyang
站務副站長


發表:377
回覆:5490
積分:4563
註冊:2002-10-08

發送簡訊給我
#4 引用回覆 回覆 發表時間:2007-07-03 12:46:12 IP:122.124.xxx.xxx 未訂閱
抱歉沒仔細看你的註解
我想能改的地方應該有
1.因為Timer的interval有極限,可以改用Thread
2.相減前轉灰階的地方可以用下面的方式(減少乘法與除法的運算)可以快一些
for (int x=0; xWidth*3; x =3) //
{
BYTE grayVal = (Ptr[x] Ptr[x 1] Ptr[x 2])/3;
...
}


===================引 用 ciy 文 章===================
謝謝 taishyang 大大的回覆
可是我從檔案抓到 Image2 只抓了一次,就沒洗掉當背景圖
之後都由 hDC = GetDC(Form1->Panel1->Handle)....在抓圖相減
降會變慢嗎??
編輯記錄
taishyang 重新編輯於 2007-07-03 12:51:04, 註解 無‧
ciy
一般會員


發表:10
回覆:19
積分:5
註冊:2006-10-26

發送簡訊給我
#5 引用回覆 回覆 發表時間:2007-07-03 13:41:52 IP:140.121.xxx.xxx 訂閱
謝謝 taishyang 大大的方法
我用了那個灰階化的方式似乎沒什麼變
速度依然維持在0.051秒
而關於Timer,我是用下方這種MMTimer的方式
不太懂 taishyang 大大說的thread...抱歉~
因為我目前是要做即時處理
所以速度起碼要0.03秒才夠
經測試發現在影像擷取及相減這部分佔用最多時間
故希望能從此地方改進
<textarea class="cpp" rows="10" cols="60" name="code">int a = 0; HANDLE hEvent = CreateEvent(NULL, false, false, NULL); int TimerID = timeSetEvent(1, 0, (LPTIMECALLBACK)hEvent, 0, TIME_PERIODIC | TIME_CALLBACK_EVENT_SET); do { WaitForSingleObject(hEvent, INFINITE); Application->ProcessMessages(); Canvas->TextOut(400, 300, a); ////////////////////// // 放置主要程式碼 // a ; ////////////////////// } while (a <= 10000); timeKillEvent(TimerID); CloseHandle(hEvent);

</body></html></textarea><br />
arisaka_matsuri
高階會員


發表:25
回覆:205
積分:231
註冊:2003-10-19

發送簡訊給我
#6 引用回覆 回覆 發表時間:2007-07-05 15:28:04 IP:140.113.xxx.xxx 訂閱
要改善速度其實大有空間
影像擷取的部分可以參考taishyang版主的建議
用另外一個thread的方式運作
避免目前的thread都在等待影像資料從裝置進入記憶體的時間(我認為這應該是瓶頸)

另外就是影像相減部分的改善方式
以下是我的一點心得

測試環境:WinXP SP2 BCB 6.0 SP4 @ CPU 2.0G / dual core
測試影像:兩張640*480 24bpp RGB 影像相減取絕對值並取臨界值後,存成另一張640*480 24bpp RGB
計算執行時間方法:利用WinAPI QueryPerformanceFrequency() 與 QueryPerformanceCounter()
測試結果:
Project Options / Compiler : Full Debug
ciy's code:16~19 ms
For-loop:6~7 ms
While-loop : 6~7 ms

Project Options / Compiler : Release
ciy's code:13~14 ms
For-loop:~3.1 ms
While-loop : ~2.6 ms

以上結果可歸納成兩點結論
1. 善用compiler最佳化code的功能,同時關閉debug模式,會節省不少時間
2. 避免浮點數運算,簡化乘除法,或將乘除法改以bit shift達成


還可不可以更快?我想無庸置疑的是可以的
利用OpenMP(VC 8.0支援)或是多thread處理,有希望再省下30%時間
使用Intel IPP套件(MMX, SSE, SSE2指令),上述的處理不用花到1ms
還想再快?那就去找GPU來幫你吧!

測試程式碼
僅供參考,不代表可以在任何情況下執行
特別是While-loop的寫法需要對影像在記憶體中的排列方式很清楚,否則不建議使用

For-loop
<textarea name="code" class="cpp" rows="10" cols="60"> Graphics::TBitmap *IMG1 = Image1->Picture->Bitmap; Graphics::TBitmap *IMG2 = Image2->Picture->Bitmap; Graphics::TBitmap *BMP = Image3->Picture->Bitmap; BYTE *ptr1; BYTE *ptr2; BYTE *ptr3; int value, lgray; for (int r = 0; r < 480; r) { ptr1 = (BYTE *)IMG1->ScanLine[r]; ptr2 = (BYTE *)IMG2->ScanLine[r]; ptr3 = (BYTE *)BMP->ScanLine[r]; for (int c = 0; c < 640; c) { lgray = abs((ptr1[c*3]-ptr2[c*3]) * 29 (ptr1[c*3 1]-ptr2[c*3 1]) * 150 (ptr1[c*3 2]-ptr2[c*3 2]) * 77); value = lgray >> 8; if (value < 64) { ptr3[c*3 0] = 0; ptr3[c*3 1] = 0; ptr3[c*3 2] = 0; } else { ptr3[c*3 0] = 255; ptr3[c*3 0] = 255; ptr3[c*3 0] = 255; } } } </textarea>

While-loop
<textarea cols="60" rows="10" class="cpp" name="code"> BYTE *EOM; ptr1 = (BYTE *)IMG1->ScanLine[479]; ptr2 = (BYTE *)IMG2->ScanLine[479]; ptr3 = (BYTE *)BMP->ScanLine[479]; EOM = (BYTE *)BMP->ScanLine[0] 640 * 3; while (ptr3 < EOM) { lgray = abs((*(ptr1)-*(ptr2)) * 29 (*(ptr1 1)-*(ptr2 1)) * 150 (*(ptr1 2)-*(ptr2 2)) * 77); value = lgray >> 8; if (value < 64) { *(ptr3 ) = 0; *(ptr3 ) = 0; *(ptr3 ) = 0; } else { *(ptr3 ) = 255; *(ptr3 ) = 255; *(ptr3 ) = 255; } ptr1 = 3; ptr2 = 3; } </textarea>
編輯記錄
arisaka_matsuri 重新編輯於 2007-07-05 15:56:48, 註解 無‧
arisaka_matsuri 重新編輯於 2007-07-05 15:58:16, 註解 無‧
arisaka_matsuri 重新編輯於 2007-07-05 16:01:13, 註解 無‧
ciy
一般會員


發表:10
回覆:19
積分:5
註冊:2006-10-26

發送簡訊給我
#7 引用回覆 回覆 發表時間:2007-07-06 12:36:40 IP:140.121.xxx.xxx 訂閱
哇~~感謝 arisaka_matsuri 大大的回覆,
你說的那些數據
讓我又重新燃起希望!

試了For-loop程式碼和Full Debug和Release模式
真的有變快
不過只快了1~3 ms
可能跟我的硬體有關吧?
以下為我的測試環境:WinXP SP2 BCB 6.0 SP4 CPU 2.8G / Celeron(R)
測試影像:兩張320*240 RGB 影像相減取絕對值並取臨界值後算差異像素形心

另外關於你兩點結論底下提供的方法有點看不懂?可以發mail問你嗎?

也感謝taishyang 大大先前的回答~
編輯記錄
ciy 重新編輯於 2007-07-06 12:39:55, 註解 無‧
pwipwi
版主


發表:68
回覆:629
積分:349
註冊:2004-04-08

發送簡訊給我
#8 引用回覆 回覆 發表時間:2007-07-08 01:54:17 IP:61.62.xxx.xxx 訂閱
您好:
程式碼中有一些可以再加快的地方:
1.

x的indexing用x =3,之後ptr1[x*3]改為ptr1[x],ptr1[x*3 1]改為ptr1[x 1

2.

去除不必要的浮點數運算,
abs(0.299*(ptr1[x*3]-ptr2[x*3]) 0.587*(ptr1[x*3 1]-ptr2[x*3 1]) 0.114*(ptr1[x*3 2]-ptr2[x*3 2]));
改成
int r = ptr1[x]-ptr2[x];
r *= 299;
int g = ptr1[x 1]-ptr2[x 1];
g *= 587;
int b = ptr1[x 2]-ptr2[x 2];
b *= 114;
以上的程式碼等於是用1000倍的整數運算

3.用一維陣列來存結果,可以使每一次indexing時少一個乘法運算

4.你抓圖的程式碼是抓取Panel上顯示的圖,速度會慢很多,
要是你是用Camera的我記得站上有標準的影像擷取程式碼



ciy
一般會員


發表:10
回覆:19
積分:5
註冊:2006-10-26

發送簡訊給我
#9 引用回覆 回覆 發表時間:2007-07-09 23:31:41 IP:140.121.xxx.xxx 訂閱
謝謝板主的回覆
不曉得降問算不算另一個問題,是的話我再另外問~
所謂更快的擷取程式碼是指用CALLBACK嗎?
系統時間:2024-03-29 15:51:27
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!