請問比對圖片想使用多執行緒的方式,但還是單線程問題 |
答題得分者是:aftcast
|
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
請問一下各位,我要做圖形比對的程式,但是因為會跑在多核的機器上,所以想用multithread的方式來執行,增加效能,目前作法如下,但是好像還是跑單線程的方式,而且好像比循續的方式還要久(看起來是二倍左右的時間),不知小弟是不是那邊的問題,可能是觀念問題,上了ktop/google查過,目前能夠理解的部份是不是因為我把宣告的三張圖(二張比對的圖,與一張比對完後的圖)宣告在form上面造成只有main thread的執行?還是我沒有用safe thread來保護線程?有google到有人提說是vcl只能用單線程執行,還是那邊出問題,請有經驗的人幫忙告知小弟,感謝您花時間閱讀問題,謝謝。
1 我在form上面宣告三個tbitmap,二個為讀檔用的,一個為存比對完結果用的圖 2 接著建立thread,一開始先讓thread先暫停 FillBMP[i-1] := TFillBMP.Create(True) ; FillBMP[i-1].FreeOnTerminate := True; FillBMPHwnd[i-1] := FillBMP[i-1].Handle ; 3 然後啟動所有的thread,並設定每一個thread到各別的核心上(目前看來好像都沒跑到100%) FillBMP[i].Resume; SetThreadAffinityMask(FillBMP[i].Handle, CPU_Mask[i]); 4 最後用WaitForMultipleObjects來判斷是否全圖比對完,才輸出圖片 while (WaitForMultipleObjects(CPUNum, PWOHandleArray(FillBMPHwnd), True, INFINITE) = WAIT_TIMEOUT) do begin Sleep(1); end; 5 thread的部份直接在TFillBMP.Execute中直接呼叫處理比對的function procedure TFillBMP.Execute; begin //Synchronize(CMPR); //加這個好像會停住 CMPR(); end; 請幫忙看一下小弟是不是觀念上的問題,或是寫法那邊要注意,還是請提供一些可參考的資料,謝謝各位。
------
DELPHI初學者 |
mitchellhu
一般會員 ![]() ![]() 發表:23 回覆:53 積分:15 註冊:2007-06-12 發送簡訊給我 |
|
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
先謝謝你的回覆,
唉,昨天要上課,本來也想去上這門課的,之前就常到蕭沖大師的blog上去看一些資料,圖形這個部份我也不是很了解,程式也是從GOOGLE上一點一點組成的,目前只有用在bmp,其它格式我可能也不是很了解呢,抱歉幫不上忙, 我查過ktop,基本上我同事用vc 寫的,大致上與我相同,但是他們的cpu(多核)都可以完成,而且比對過程式碼的部份,也很相近,所以才會很麻煩,另外一點就是我對於這個部份可能不是很了解也是一個問題,所以最近查了一些資料,但也沒有明確的方向,所以才想詢問一下,是不是有經驗的人可以指導小弟,謝謝。 ===================引 用 mitchellhu 文 章=================== 昨天蕭沖大師有在捷康開了一場multithread的教學。 他有作了一個類似你的case來演示。 請個部份請問他應該有好的答案。 另外,對於你的題目,比對圖檔這部份。 我很好奇,你如何訂義2張圖檔的差異性呢? 而且可以在將差異顯示在第3張圖上? 是所有格式的圖檔都可以對比嗎? bmp, jpg, ai, cdr都可嗎? 那pdf呢? 若能,請指點一些想法可以嗎?
------
DELPHI初學者 |
aftcast
站務副站長 ![]() ![]() ![]() ![]() ![]() 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
while (WaitForMultipleObjects(CPUNum, PWOHandleArray(FillBMPHwnd),
True, INFINITE) = WAIT_TIMEOUT) do begin Sleep(1); end; 那個INFINITE應該要改成一個數值,才會timeout,否則永遠不會timeout,所以 sleep(1)的好處從來不會發生。 如果說 //Synchronize(CMPR); //加這個好像會停住 CMPR(); 那麼表示cmpr這個方法的寫法是關鍵,裡面有放 sleep ? critical section? waitforxxxxobjecs? 還是?? 最好po一下文看看 ===================引 用 macchen 文 章===================
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
jcjroc
高階會員 ![]() ![]() ![]() ![]() 發表:21 回覆:279 積分:115 註冊:2002-09-18 發送簡訊給我 |
1.多大張的圖?用不到Thread吧!
2.用TBitmap 慢死你!!! 3,嗯!!圖很大一張,而且目標機器是多核的CPU,用Multi thread來展現一下速度吧!!!阿.......用了VCL處理圖形.....唉!!!死路一條. 給你個方向吧!!! 1.去用力地啃一下BMP的格式!! 2.如果圖形來源是檔案,那再瞄一下CreateFile,CreateFileMapping,MapViewOfFile. 3.如果還要顯示比對(運算)後的結果,那再蹬一眼CreateWindow,GetDC,SelectObject,DeleteObject,CreateDIBSection 4.如果第3點成立,嗯!!來點酷一點的,青一眼InvalidateRect 5.啥!!這還不夠炫,還要再加上zoom in跟zoom out........那含著眼淚再看看SetMapMode,SetWindowExtEx,SetViewportExtEx. |
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
非常感謝affcast大的回覆,先回答一下,下面的問題
1 那個INFINITE應該要改成一個數值,才會timeout,否則永遠不會timeout,所以 sleep(1)的好處從來不會發生。 這個已經拿掉了,之前是以為沒加所以會慢,也是觀念問題沒搞好。 2 那麼表示cmpr這個方法的寫法是關鍵,裡面有放 sleep ? critical section? waitforxxxxobjecs? 還是?? 最好po一下文看看 這個function裡面什麼都沒有加呢,只有單純的比對圖片的程式碼,附上程式的部份,麻煩再指導小弟一下,感激不盡。 [code delphi] procedure TFillBMP.CMPR; var Y, NX, TBit, CX, TX, TBitIdx, CBitIdx, CBit: Integer; TRIPa, EZPa, NewPa: PByteArray; NewByte: string; CXFill: Boolean; newbin: string; i: Integer; begin for Y := StartY to EndY do begin if (Y TTop) > (TRBmp.Height - 1) then Break; if (Y CTop) > (EZBmp.Height - 1) then Break; TRIPa := TRBmp.ScanLine[Y TTop]; EZPa := EZBmp.ScanLine[Y CTop]; NewPa := NewBMP.ScanLine[Y CTop]; NX := 0; TBit := 0; TX := TBytePos; CX := CBytePos; NewByte := ''; TBitIdx := OTBitIdx; CBitIdx := OCBitIdx; CXFill := False; while true do begin if not CXFill then //2011.7.20 add TBit := TRIPa[TX] shr TBitIdx and 1; CBit := EZPa[CX] shr CBitIdx and 1; if not CXFill then //2011.7.20 add begin if TBit = CBit then NewByte := NewByte '0' else begin if (TBit = 0) and (CBit = 1) then NewByte := NewByte '1' else NewByte := NewByte '0'; end; end else NewByte := NewByte '0'; if Length(NewByte) = 8 then begin NewPa[NX] := StrToInt('0x' BinStrToHex(NewByte)); NewByte := ''; inc(NX); end; if not CXFill then //2011.7.20 add begin dec(TBitIdx); if TBitIdx < 0 then //Length(TLine) then begin inc(TX); TBitIdx := 7; end; end; dec(CBitIdx); if CBitIdx < 0 then //Length(CLine) then begin inc(CX); CBitIdx := 7; end; if CX > (TW div 8) - 1 then //2011.7.20 add CXFill := True; if CX > (W div 8) - 1 then begin if Length(NewByte) <> 0 then begin if length(NewByte) < 8 then begin newbin := ''; for i := 0 to 8 - length(NewByte) - 1 do newbin := newbin '0'; NewByte := NewByte newbin; end; NewPa[NX] := StrToInt('0x' BinStrToHex(NewByte)); NewByte := ''; end; Break; end; end; end; end; [/code] ===================引 用 aftcast 文 章=================== while (WaitForMultipleObjects(CPUNum, PWOHandleArray(FillBMPHwnd), True, INFINITE) = WAIT_TIMEOUT) do begin Sleep(1); end; 那個INFINITE應該要改成一個數值,才會timeout,否則永遠不會timeout,所以 sleep(1)的好處從來不會發生。 如果說 //Synchronize(CMPR); //加這個好像會停住 CMPR(); 那麼表示cmpr這個方法的寫法是關鍵,裡面有放 sleep ? critical section? waitforxxxxobjecs? 還是?? 最好po一下文看看 ===================引 用 macchen 文 章===================
------
DELPHI初學者 |
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
===================引 用 jcjroc 文 章=================== 1.多大張的圖?用不到Thread吧! ?那請問一下,可以用什麼處理會比較快呢?查google是用scanline的方式就相當快,還是還有別的,請指導小弟一下,謝謝。 3,嗯!!圖很大一張,而且目標機器是多核的CPU,用Multi thread來展現一下速度吧!!!阿.......用了VCL處理圖形.....唉!!!死路一條. 請問一下tbitmap是vcl嗎?查過用vcl好像要用Synchronize,但這又跑回到main thread了?不是還是一樣會比較慢嗎? 給你個方向吧!!! 1.去用力地啃一下BMP的格式!! 2.如果圖形來源是檔案,那再瞄一下CreateFile,CreateFileMapping,MapViewOfFile. 3.如果還要顯示比對(運算)後的結果,那再蹬一眼CreateWindow,GetDC,SelectObject,DeleteObject,CreateDIBSection 4.如果第3點成立,嗯!!來點酷一點的,青一眼InvalidateRect 5.啥!!這還不夠炫,還要再加上zoom in跟zoom out........那含著眼淚再看看SetMapMode,SetWindowExtEx,SetViewportExtEx.
------
DELPHI初學者 |
jcjroc
高階會員 ![]() ![]() ![]() ![]() 發表:21 回覆:279 積分:115 註冊:2002-09-18 發送簡訊給我 |
|
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
不好意思,不是很懂呢??答案是什麼?可以再指導小弟一下嗎?不好意思,真的不是很懂你在說什麼呢,謝謝你的回覆。
給你個方向吧!!! 1.去用力地啃一下BMP的格式!! ??格式有什麼特別嗎?? 2.如果圖形來源是檔案,那再瞄一下CreateFile,CreateFileMapping,MapViewOfFile. 為什麼要用這三個?? 3.如果還要顯示比對(運算)後的結果,那再蹬一眼CreateWindow,GetDC,SelectObject,DeleteObject,CreateDIBSection 我只是要用運算比對資料,你這幾個會用的到嗎??不是很了解,麻煩再告知一下。 4.如果第3點成立,嗯!!來點酷一點的,青一眼InvalidateRect 我沒有要繪圖?為什麼會用到這個?? 5.啥!!這還不夠炫,還要再加上zoom in跟zoom out........那含著眼淚再看看SetMapMode,SetWindowExtEx,SetViewportExtEx. ===================引 用 jcjroc 文 章=================== 答案不是給你了嗎????
------
DELPHI初學者 |
aftcast
站務副站長 ![]() ![]() ![]() ![]() ![]() 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
你好,
大致上看了一下程式。還有個疑問: TRBmp, EZBmp, NewBMP 這三個是每條thread都用同樣的這三個bmp? (我是bmp的內容是否都一樣?),或是每條thread裡的這三個都是不一樣的。是以什麼方式傳入thread中?這和 同步問題有些關係。可以的話 po 一下 建立起來的那部份。
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
affcast謝謝你的回覆,說明如下,謝謝您。
===================引 用 aftcast 文 章=================== 你好, 大致上看了一下程式。還有個疑問: TRBmp, EZBmp, NewBMP 這三個是每條thread都用同樣的這三個bmp? 內容都是pf1bit的格式,每個thread中的資料的來源都是相同的。 是以什麼方式傳入thread中? for i := 1 to CPUNum do begin FillBMP[i - 1] := TFillBMP.Create(True); FillBMP[i-1].FreeOnTerminate := True; FillBMPHwnd[i - 1] := FillBMP[i - 1].Handle; if i = CPUNum then FillBMP[i - 1].EndY := H - CTop - 1 else FillBMP[i - 1].EndY := (i * ((H - CTop) div CPUNum)) - 1; FillBMP[i - 1].TBytePos := TBytePos; FillBMP[i - 1].CBytePos := CBytePos; FillBMP[i - 1].OTBitIdx := OTBitIdx; FillBMP[i - 1].OCBitIdx := OCBitIdx; FillBMP[i - 1].TW := TW; FillBMP[i - 1].W := W; FillBMP[i - 1].CTop := CTop ; FillBMP[i - 1].TTop := TTop ; FillBMP[i - 1].TRBMP := @TRBmp; FillBMP[i - 1].EZBMP := @EZBmp; FillBMP[i - 1].NewBMP := @NewBMP; end; for i := 0 to CPUNum - 1 do FillBMP[i].Resume; WaitForMultipleObjects(CPUNum, PWOHandleArray(FillBMPHwnd), True, INFINITE) ; [/code] 這和 同步問題有些關係。可以的話 po 一下 建立起來的那部份。
------
DELPHI初學者 |
aftcast
站務副站長 ![]() ![]() ![]() ![]() ![]() 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
你好,
我終於感覺上是猜出你的想法了 :-) 如果上面我猜的沒錯的話。你要做的其實是「並行運算」。但目前你的做法是完全不一樣的。 1/ 其實你只要一條thread就好,就算你有二個cpu。(我猜你是二個,也因此你得到的是二倍時間!!) 2/ windows理論上會去計算二個cpu怎麼用。如果你還是一定要自己來配…那問題就變難了。你必需: a 把比對的演算法猜解成幾個部份 : 比如說,比圖的上半部與比圖的下半部二個部份。 b 接著起二條thread,其中一個算上部份。另一個算下半部。可能的話也可以指定哪個cpu 核用1,哪個用2… c 最後把二個結果整合一下。 d 當然,以上的做法就有「同步的問題」。但bmp的同步只需要用TBmp->Canvas->Lock 與 TBmp->Canvas->Unlock 這二個。不需要用synchronized,否則一如你測出來的。感覺好像當了! 因為那麼多的工作全轉到 main thread上去跑,於是main thread都在這個計算,就沒時間處理其他的事件了! 以上。 但我個人覺得那樣不會有什麼很大的幫助,除非你自己拆解演算法很精,才有一些些的幫助。 建議還是 單一條thread來處裡 計算就夠了! 最多把該thread的 priority 拉到最高再用SetThreadAffinityMask恉定該thread至另一個核上。
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan
編輯記錄
aftcast 重新編輯於 2011-07-25 03:52:43, 註解 無‧
|
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
===================引 用 aftcast 文 章=================== 你好, 我終於感覺上是猜出你的想法了 :-) 請問一下「並行運算」不是也是指將同一個工作拆成多個thread讓多個核心來個別處理的意思嗎?小弟的說法不知有沒有問題 1/ 其實你只要一條thread就好,就算你有二個cpu。(我猜你是二個,也因此你得到的是二倍時間!!) 請問一下,開二個thread,然後用SetThreadAffinityMask不是就是將這二個thread指定到這二個核心上嗎?因為這樣指定後cpu使用率變成70~80%了,但時間卻沒什麼變,這點我最覺的奇怪。 a 把比對的演算法猜解成幾個部份 : 比如說,比圖的上半部與比圖的下半部二個部份。 就是用SetThreadAffinityMask來指定的 c 最後把二個結果整合一下。 所以您的意思是指用「tbitmap」就是vcl嗎?不然怎麼會有「同步的問題」還是因為什麼原因(請指導一下小弟,因為小弟就是這邊觀念有問題,所以才會搞不懂為什麼會變成二倍時間) 但bmp的同步只需要用TBmp->Canvas->Lock 與 TBmp->Canvas->Unlock 這二個。 所以我拆成二個thread的做法有缺失,仍然還是用main thread在處理的意思嗎,所以才會造成二倍時間的關係。 以上。 但我個人覺得那樣不會有什麼很大的幫助,除非你自己拆解演算法很精,才有一些些的幫助。 最多把該thread的 priority 拉到最高再用SetThreadAffinityMask恉定該thread至另一個核上。 請問藍字的地方,是指說還是用二個thread的方式來處理嗎?不是很能了解這段話的意義。 謝謝你花時間幫忙小弟了解這個問題,再麻煩指導小弟,讓小觀念能更清楚,謝謝您的幫助。
------
DELPHI初學者 |
aftcast
站務副站長 ![]() ![]() ![]() ![]() ![]() 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
你的說法是正確的。但多數人使用multithread的原因並不是把「一個」工作「切成n個」並運用multithread處理。因為並行運算也有可能把工作切到不同的電腦上來算。 >>我原來的想法是以為你並「沒有」把演算法拆成二部份。剛又再細看,感覺上你有拆了,所以是誤會。 時間卻沒什麼變,關於這點,大概就是如我說的原本windows就會去使用雙核/cpu的所有資源,假設你增加成多核後,windows不懂的如何去運用它,那硬體變強不就沒意義了? 所以windows是一定會知道要怎麼去把多核使用到"較佳"的狀態。如果說一個核100%的跑,與二個核各自少跑一點,若真的會有很大的差異出來。那大概就是windows的調配真的很差很差! 我是這樣子做的沒錯,如四核心則拆成四分,quad的方式來處理各別的資料,最後用waitformultiobjects來做結束 就是用SetThreadAffinityMask來指定的 應該是指waitformultiobjects嗎?? 所以您的意思是指用「tbitmap」就是vcl嗎? 請問這個「TBmp->Canvas->Lock」的部份是加在for的下方嗎?還是加在那邊,因為我加在for的下方,時間還是比單thread的二倍久,而只加在newbmp的部份,時間還是比較久,但是比for的下面時間要快,是我加錯地方嗎? 所以我拆成二個thread的做法有缺失,仍然還是用main thread在處理的意思嗎,所以才會造成二倍時間的關係。 請問因為我問別人,他們也是說只要將圖片拆解,然後寫入即可增加計算速度,所以我才會用這種方式來處理,他們是用vc 寫的,還是因為我對delphi的觀念有問題,所以才無法增加速度? 最多把該thread的 priority 拉到最高再用SetThreadAffinityMask恉定該thread至另一個核上。 不用拆解演算,把「一個問題」「全然的」交給一個new 出一個thread來處理。也就是main form 1條 thread。但該thread指定到另一核/cpu上 (即與main form用的是不同的核)
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
=================== aftcast文章你的說法是正確的。但多數人使用的原因並不是把「一個」工作「切成個」並運用處理。因為並行運算也有可能把工作切到不同的電腦上來算。cpu100%ncpu
windows/cpuwindows? windows""100%windows! : ? threadcpucpu100%() 所以您的意思是指用「」就是嗎是所以並不是指有介面的程式才是囉,那是指只要是都是嗎在中,不好意思問了很笨的問題。 bmp []tbmp.canvas.lock/ tbmp.canvas.unlockmainthread(cpu50%) 以上。關於這點我上面有講到。我個人認為對於多核的運用應該是不會很差才是。也就是說它理論上知道如何把工作配給不同的核。當然,這方面我沒實測過,不了解是否真的可以透過自己的「調用」來提高效能。題外話,如果說把拆開的工作交給另外一台電腦的話理論上會有幫助,但前題也要是該工作真的對一台電腦來說要算超久的。當初會有這種想法,因為有提供這種東西,而沒有,所以去查了,找到一個多核計算的範例,其內容是同一段程式碼用雙核中的單核跑二次,與雙核分別各跑一次,時間差了快一倍,所以才會想在這邊做這種方式來減少時間。我是指不用拆解演算,把「一個問題」「全然的」交給一個出一個來處理。也就是條。但該指定到另一核上即與用的是不同的核意思是指用各自在單核上面執行的意思嗎還是指計算都給出來的那個來執行,那就做的等待嗎如有理解錯誤的地方請再麻煩告知,小弟先來試試看
------
DELPHI初學者 |
jcjroc
高階會員 ![]() ![]() ![]() ![]() 發表:21 回覆:279 積分:115 註冊:2002-09-18 發送簡訊給我 |
喔!!!那就是不牽涉UI啦
那把BCB(VCL)暫時丟到牆角去吧!! 有VC(MFC)的話一起!!! 就用前兩條 CreateCompatibleDC SelectObject,DeleteObject,CreateDIBSection 其實前兩條就夠了............但對那個答案,我基本上很懶,所以就拿來用啦!!! 你的問題用多執行緒一次同時處理多組來源也都OK!!!因為都是獨立的,所以跟同步一點關係都沒有!!! 根據發問需求.....這是最精簡而Powerful的解決方案,但最關鍵的前提是必須熟悉BMP格式. VCL&MFC&QT....都是好東西,但前提是使用者基礎要好,不然在我看來會是累贅..................害人喔!!! ===================引 用 macchen 文 章=================== 不好意思,不是很懂呢??答案是什麼?可以再指導小弟一下嗎?不好意思,真的不是很懂你在說什麼呢,謝謝你的回覆。 給你個方向吧!!! 1.去用力地啃一下BMP的格式!! ??格式有什麼特別嗎?? 2.如果圖形來源是檔案,那再瞄一下CreateFile,CreateFileMapping,MapViewOfFile. 為什麼要用這三個?? 3.如果還要顯示比對(運算)後的結果,那再蹬一眼CreateWindow,GetDC,SelectObject,DeleteObject,CreateDIBSection 我只是要用運算比對資料,你這幾個會用的到嗎??不是很了解,麻煩再告知一下。 4.如果第3點成立,嗯!!來點酷一點的,青一眼InvalidateRect 我沒有要繪圖?為什麼會用到這個?? 5.啥!!這還不夠炫,還要再加上zoom in跟zoom out........那含著眼淚再看看SetMapMode,SetWindowExtEx,SetViewportExtEx. ===================引 用 jcjroc 文 章=================== 答案不是給你了嗎????
編輯記錄
jcjroc 重新編輯於 2011-07-25 22:41:03, 註解 無‧
|
jow
尊榮會員 ![]() ![]() ![]() ![]() ![]() ![]() 發表:66 回覆:751 積分:1253 註冊:2002-03-13 發送簡訊給我 |
jcjroc 大大的意思是直接針對檔案內含值做比較...
以下測試碼提供你參考 // BITMAP檔案格式: // http://crazycat1130.pixnet.net/blog/post/1345538 [code delphi] unit fMain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type { TMyBitmap } TMyBitmap = class(TPersistent) private FFileName: string; FStream: TMemoryStream; function GetScanLineCount: Integer; function GetScanLineLength: Integer; function GetScanLines(Index: Integer): PByte; function GetFileHeader: PBitmapFileHeader; function GetInfoHeader: PBitmapInfoHeader; protected function _ptr(p: Pointer; offset: Integer): Pointer; procedure LoadFromFile(FileName: string); virtual; property FileName: string read FFileName; property Stream: TMemoryStream read FStream; property FileHeader: PBitmapFileHeader read GetFileHeader; property InfoHeader: PBitmapInfoHeader read GetInfoHeader; property ScanLineCount: Integer read GetScanLineCount; property ScanLineLength: Integer read GetScanLineLength; property ScanLines[Index: Integer]: PByte read GetScanLines; default; public constructor Create(FileName: string); virtual; destructor Destroy; override; function BitmapFileHeaderText: string; function BitmapInfoHeaderText: string; end; { TForm1 } TfrmMain = class(TForm) Button1: TButton; ListBox1: TListBox; ListBox2: TListBox; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private public end; var frmMain: TfrmMain; implementation {$R *.dfm} { TMyBitmap } function TMyBitmap._ptr(p: Pointer; offset: Integer): Pointer; begin Result := Pointer(Integer(p) offset); end; constructor TMyBitmap.Create(FileName: string); begin inherited Create; FFileName := ''; FStream := nil; LoadFromFile(FileName); end; destructor TMyBitmap.Destroy; begin FreeAndNil(FStream); inherited; end; function TMyBitmap.GetFileHeader: PBitmapFileHeader; begin if FStream=nil then Result := nil else Result := PBitmapFileHeader(FStream.Memory); end; function TMyBitmap.GetInfoHeader: PBitmapInfoHeader; begin if FStream=nil then Result := nil else Result := PBitmapInfoHeader(_ptr(FStream.Memory,$E)); end; function TMyBitmap.GetScanLines(Index: Integer): PByte; begin if(FileHeader=nil) or (InfoHeader=nil) or (Index<0) or (Index>InfoHeader.biHeight) then begin Result := nil; end else begin with FStream,FileHeader^,InfoHeader^ do Result := _ptr(Memory, Integer(bfOffBits) GetScanLineLength*Index); end; end; function TMyBitmap.GetScanLineCount: Integer; begin if InfoHeader=nil then Result := 0 else Result := InfoHeader.biHeight; end; function TMyBitmap.GetScanLineLength: Integer; begin if (FileHeader=nil) or (InfoHeader=nil) then Result := 0 else begin with FileHeader^,InfoHeader^ do Result := Integer(bfSize-bfOffBits) div biHeight; end; end; procedure TMyBitmap.LoadFromFile(FileName: string); begin if FileExists(FileName) then begin FFileName := FileName; FreeAndNil(FStream); FStream := TMemoryStream.Create; FStream.LoadFromFile(FFileName); end; end; function TMyBitmap.BitmapFileHeaderText: string; var L: TStringList; begin Result := 'Invalidate BitmapFileHeader'; if FileHeader=nil then EXIT; L := TStringList.Create; try with FileHeader^ do begin L.Add(Format('bfType=%s%s',[ AnsiChar(Lo(bfType)), AnsiChar(Hi(bfType))])); L.Add(Format('bfSize=%d',[bfSize])); L.Add(Format('bfReserved1=%d',[bfReserved1])); L.Add(Format('bfReserved2=%d',[bfReserved2])); L.Add(Format('bfOffBits=%d',[bfOffBits])); end; Result := L.Text; finally FreeAndNil(L); end; end; function TMyBitmap.BitmapInfoHeaderText: string; var L: TStringList; begin Result := 'Invalidate BitmapInfoHeader'; if InfoHeader=nil then EXIT; L := TStringList.Create; try with InfoHeader^ do begin L.Add(Format('biSize=%d',[biSize])); L.Add(Format('Width=%d',[biWidth])); L.Add(Format('Height=%d',[biHeight])); L.Add(Format('Planes=%d',[biPlanes])); L.Add(Format('BitCount=%d',[biBitCount])); L.Add(Format('Compression=%d',[biCompression])); L.Add(Format('SizeImage=%d',[biSizeImage])); L.Add(Format('XPelsPerMeter=%d',[biXPelsPerMeter])); L.Add(Format('YPelsPerMeter=%d',[biYPelsPerMeter])); L.Add(Format('ClrUsed=%d',[biClrUsed])); L.Add(Format('biClrImportant=%d',[biClrImportant])); L.Add(''); L.Add(Format('GetScanLineCount=%d',[GetScanLineCount])); L.Add(Format('GetScanLineLength=%d',[GetScanLineLength])); end; Result := L.Text; finally FreeAndNil(L); end; end; { TfrmMain } procedure TfrmMain.Button1Click(Sender: TObject); var O: TMyBitmap; begin if FileExists('D:\TEST.BMP') then begin O := TMyBitmap.Create('D:\TEST.BMP'); try ListBox1.Items.Text := O.BitmapFileHeaderText; ListBox2.Items.Text := O.BitmapInfoHeaderText; finally FreeAndNil(O); end; end; end; procedure TfrmMain.Button2Click(Sender: TObject); var I,Count: Integer; M: TMemoryStream; O: TMyBitmap; begin if FileExists('D:\TEST.BMP') then begin O := TMyBitmap.Create('D:\TEST.BMP'); try M := TMemoryStream.Create; try M.Write(O.FileHeader^,SizeOf(TBitmapFileHeader)); M.Write(O.InfoHeader^,SizeOf(TBitmapInfoHeader)); Count := O.ScanLineCount; //反轉圖形測試(uses ScanLines) for I := 0 to Count-1 do M.Write(O[Count-I-1]^,O.GetScanLineLength); M.SaveToFile('D:\TEST_2.BMP'); finally FreeAndNil(M); end; finally FreeAndNil(O); end; end; end; end. [/code] 謹供參考 ... ^_^
編輯記錄
jow 重新編輯於 2011-07-26 01:56:07, 註解 無‧
|
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
|
jcjroc
高階會員 ![]() ![]() ![]() ![]() 發表:21 回覆:279 積分:115 註冊:2002-09-18 發送簡訊給我 |
是這樣沒錯,但我採用記憶體映射,效能比你的方式還要好很多.程式也單純多多.(我是懶惰鬼,我的字典裡找不到"勤勞"兩個字)
===================引 用 jow 文 章=================== jcjroc大大的意思是直接針對檔案內含值做比較... 以下測試碼提供你參考 // BITMAP檔案格式: // http://crazycat1130.pixnet.net/blog/post/1345538 [code delphi] unit fMain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type { TMyBitmap } TMyBitmap = class(TPersistent) private FFileName: string; FStream: TMemoryStream; function GetScanLineCount: Integer; function GetScanLineLength: Integer; function GetScanLines(Index: Integer): PByte; function GetFileHeader: PBitmapFileHeader; function GetInfoHeader: PBitmapInfoHeader; protected function _ptr(p: Pointer; offset: Integer): Pointer; procedure LoadFromFile(FileName: string); virtual; property FileName: string read FFileName; property Stream: TMemoryStream read FStream; property FileHeader: PBitmapFileHeader read GetFileHeader; property InfoHeader: PBitmapInfoHeader read GetInfoHeader; property ScanLineCount: Integer read GetScanLineCount; property ScanLineLength: Integer read GetScanLineLength; property ScanLines[Index: Integer]: PByte read GetScanLines; default; public constructor Create(FileName: string); virtual; destructor Destroy; override; function BitmapFileHeaderText: string; function BitmapInfoHeaderText: string; end; { TForm1 } TfrmMain = class(TForm) Button1: TButton; ListBox1: TListBox; ListBox2: TListBox; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private public end; var frmMain: TfrmMain; implementation {$R *.dfm} { TMyBitmap } function TMyBitmap._ptr(p: Pointer; offset: Integer): Pointer; begin Result := Pointer(Integer(p) offset); end; constructor TMyBitmap.Create(FileName: string); begin inherited Create; FFileName := ''; FStream := nil; LoadFromFile(FileName); end; destructor TMyBitmap.Destroy; begin FreeAndNil(FStream); inherited; end; function TMyBitmap.GetFileHeader: PBitmapFileHeader; begin if FStream=nil then Result := nil else Result := PBitmapFileHeader(FStream.Memory); end; function TMyBitmap.GetInfoHeader: PBitmapInfoHeader; begin if FStream=nil then Result := nil else Result := PBitmapInfoHeader(_ptr(FStream.Memory,$E)); end; function TMyBitmap.GetScanLines(Index: Integer): PByte; begin if(FileHeader=nil) or (InfoHeader=nil) or (Index<0) or (Index>InfoHeader.biHeight) then begin Result := nil; end else begin with FStream,FileHeader^,InfoHeader^ do Result := _ptr(Memory, Integer(bfOffBits) GetScanLineLength*Index); end; end; function TMyBitmap.GetScanLineCount: Integer; begin if InfoHeader=nil then Result := 0 else Result := InfoHeader.biHeight; end; function TMyBitmap.GetScanLineLength: Integer; begin if (FileHeader=nil) or (InfoHeader=nil) then Result := 0 else begin with FileHeader^,InfoHeader^ do Result := Integer(bfSize-bfOffBits) div biHeight; end; end; procedure TMyBitmap.LoadFromFile(FileName: string); begin if FileExists(FileName) then begin FFileName := FileName; FreeAndNil(FStream); FStream := TMemoryStream.Create; FStream.LoadFromFile(FFileName); end; end; function TMyBitmap.BitmapFileHeaderText: string; var L: TStringList; begin Result := 'Invalidate BitmapFileHeader'; if FileHeader=nil then EXIT; L := TStringList.Create; try with FileHeader^ do begin L.Add(Format('bfType=%s%s',[ AnsiChar(Lo(bfType)), AnsiChar(Hi(bfType))])); L.Add(Format('bfSize=%d',[bfSize])); L.Add(Format('bfReserved1=%d',[bfReserved1])); L.Add(Format('bfReserved2=%d',[bfReserved2])); L.Add(Format('bfOffBits=%d',[bfOffBits])); end; Result := L.Text; finally FreeAndNil(L); end; end; function TMyBitmap.BitmapInfoHeaderText: string; var L: TStringList; begin Result := 'Invalidate BitmapInfoHeader'; if InfoHeader=nil then EXIT; L := TStringList.Create; try with InfoHeader^ do begin L.Add(Format('biSize=%d',[biSize])); L.Add(Format('Width=%d',[biWidth])); L.Add(Format('Height=%d',[biHeight])); L.Add(Format('Planes=%d',[biPlanes])); L.Add(Format('BitCount=%d',[biBitCount])); L.Add(Format('Compression=%d',[biCompression])); L.Add(Format('SizeImage=%d',[biSizeImage])); L.Add(Format('XPelsPerMeter=%d',[biXPelsPerMeter])); L.Add(Format('YPelsPerMeter=%d',[biYPelsPerMeter])); L.Add(Format('ClrUsed=%d',[biClrUsed])); L.Add(Format('biClrImportant=%d',[biClrImportant])); L.Add(''); L.Add(Format('GetScanLineCount=%d',[GetScanLineCount])); L.Add(Format('GetScanLineLength=%d',[GetScanLineLength])); end; Result := L.Text; finally FreeAndNil(L); end; end; { TfrmMain } procedure TfrmMain.Button1Click(Sender: TObject); var O: TMyBitmap; begin if FileExists('D:\TEST.BMP') then begin O := TMyBitmap.Create('D:\TEST.BMP'); try ListBox1.Items.Text := O.BitmapFileHeaderText; ListBox2.Items.Text := O.BitmapInfoHeaderText; finally FreeAndNil(O); end; end; end; procedure TfrmMain.Button2Click(Sender: TObject); var I,Count: Integer; M: TMemoryStream; O: TMyBitmap; begin if FileExists('D:\TEST.BMP') then begin O := TMyBitmap.Create('D:\TEST.BMP'); try M := TMemoryStream.Create; try M.Write(O.FileHeader^,SizeOf(TBitmapFileHeader)); M.Write(O.InfoHeader^,SizeOf(TBitmapInfoHeader)); Count := O.ScanLineCount; //反轉圖形測試(uses ScanLines) for I := 0 to Count-1 do M.Write(O[Count-I-1]^,O.GetScanLineLength); M.SaveToFile('D:\TEST_2.BMP'); finally FreeAndNil(M); end; finally FreeAndNil(O); end; end; end; end. [/code] 謹供參考 ... ^_^ |
aftcast
站務副站長 ![]() ![]() ![]() ![]() ![]() 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
哇,好熱鬧,大概是這問題算有些水準吧… 續繼來插花一下:
TO: jcjroc >>就用前兩條 CreateCompatibleDC SelectObject,DeleteObject,CreateDIBSection >>其實前兩條就夠了............但對那個答案,我基本上很懶,所以就拿來用啦!!! 根據你一開始講的五點,我怎覺得好像認識你? 你是jack 張? 不過我覺得這提問者的問題應該不至於需要用到那麼多的技巧。如 CreateFileMapping,MapViewOfFile 這類的… 如果眞的需要加速的話,應該是照jow的方式,不需要管DC與bmp的任何api。只管把檔案讀入記憶體中即可。 To Jow : 每次看你回覆都好用心,而且也常提供解答的範例,而且答案都很正確,真讓我配服。 針對這次的問題,我最好奇的是二條thread分別在不同的core上是否真的可以提高效能,而非TBitmap的封裝後造成變慢(當然這也是會)。你覺得呢? To machhen: 上面二位先進的講的都是運用較低階的方式來做比對。這樣的做法是可以提昇一些效能,尤其是如果把bmp整個讀入記憶體中,純靠指標在裡面取出互比。 jow 的範例就是在講那個 。 如此的做法就不管DC也因此不用管同步(理論上你每個寫入目標的記憶體位址不會是同一個)。你可以試著去了解一下。而要了解的前題就是知道bmp檔案的結構,即bmp的檔頭資訊與bmp的pixel內容。然後把檔案用一般的方式讀入.。 你原來的方法沒有錯。最多只能說用TBitmap的物件與方法會比較慢一點點。但是否用二條thread就可以增快,這是我比較想知道的,也想再研究的。但手上目前沒有例子可以做… ===================引 用 macchen 文 章=================== 恕刪,請問一下,是指我的方式所以造成速度變嗎?還是指我的作法有問題,因為我作圖形的比對,是整張圖每一個值都要抓出來比較,不是只做xor,而是要依據其中一張圖片的值來產生新的圖片,所以想請問一下,是我的方法錯了嗎?您附上的程式碼用意什麼,可以指點一下小弟,我有點不懂意思了,謝謝你的回覆。
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
jcjroc
高階會員 ![]() ![]() ![]() ![]() 發表:21 回覆:279 積分:115 註冊:2002-09-18 發送簡訊給我 |
效能.......一組一千組一萬組 0.5s 500s 5000s .............再加幾顆CPU,然後多泡幾杯咖啡,如此之差而已.
加油啦!!!! ===================引 用 aftcast 文 章=================== 哇,好熱鬧,大概是這問題算有些水準吧… 續繼來插花一下: TO: jcjroc >>就用前兩條 CreateCompatibleDC SelectObject,DeleteObject,CreateDIBSection >>其實前兩條就夠了............但對那個答案,我基本上很懶,所以就拿來用啦!!! 根據你一開始講的五點,我怎覺得好像認識你? 你是jack 張? 不過我覺得這提問者的問題應該不至於需要用到那麼多的技巧。如 CreateFileMapping,MapViewOfFile 這類的… 如果眞的需要加速的話,應該是照jow的方式,不需要管DC與bmp的任何api。只管把檔案讀入記憶體中即可。 To Jow : 每次看你回覆都好用心,而且也常提供解答的範例,而且答案都很正確,真讓我配服。 針對這次的問題,我最好奇的是二條thread分別在不同的core上是否真的可以提高效能,而非TBitmap的封裝後造成變慢(當然這也是會)。你覺得呢? To machhen: 上面二位先進的講的都是運用較低階的方式來做比對。這樣的做法是可以提昇一些效能,尤其是如果把bmp整個讀入記憶體中,純靠指標在裡面取出互比。 jow 的範例就是在講那個 。 如此的做法就不管DC也因此不用管同步(理論上你每個寫入目標的記憶體位址不會是同一個)。你可以試著去了解一下。而要了解的前題就是知道bmp檔案的結構,即bmp的檔頭資訊與bmp的pixel內容。然後把檔案用一般的方式讀入.。 你原來的方法沒有錯。最多只能說用TBitmap的物件與方法會比較慢一點點。但是否用二條thread就可以增快,這是我比較想知道的,也想再研究的。但手上目前沒有例子可以做… ===================引 用 macchen 文 章=================== 恕刪,請問一下,是指我的方式所以造成速度變嗎?還是指我的作法有問題,因為我作圖形的比對,是整張圖每一個值都要抓出來比較,不是只做xor,而是要依據其中一張圖片的值來產生新的圖片,所以想請問一下,是我的方法錯了嗎?您附上的程式碼用意什麼,可以指點一下小弟,我有點不懂意思了,謝謝你的回覆。 |
aftcast
站務副站長 ![]() ![]() ![]() ![]() ![]() 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
回 macchen 上面的問題:
1/ VCL 用另一種簡單的方式講就是 delphi 裡所提供的元件,無論是可視或不可視或可不可以在設計時期拉進來,通通可以當它是VCL元件。(不精準的說法,但差不多那樣想就可以) 2/ 你說「如果只用mainthread來執行時間卻比較快」。而且快近二倍。那是否表示…問題在同步? 再問一下,若thread裡不用synchronize,也不用lock,那情形如何? 一樣差了近二倍嗎? 3/ [ 當初會有這種想法,因為c 有提供openmp這種東西,而delphi沒有,所以去google查了,找到一個多核計算的範例,其內容是同一段程式碼用雙核中的單核跑二次,與雙核分別各跑一次,時間差了快一倍,所以才會想在這邊做這種方式來減少時間。] 我想找時間也去研究一下,有心得在和你分享一下。 4 mainform 本身就是一條thread,即mainthread。我指的是new一個thead,然後把計算都給new出來的那個用,但指定此new出來的thread至另一核上 (非mainform上的那個核) 5 若照我上面4的做法。那就不用waitforsingleobject。mainform也不能這樣做!!!。你只要在new出來的thread的excute的最後一行sendmessage 給 mainform 通知一下就可以。但建議目前測速的情形下,用MessageBox這個api來show一下,就表示結束。如此測時間方便一點。若確定合你要的,再去設剛講的message (這要自訂一個message)。
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
jow
尊榮會員 ![]() ![]() ![]() ![]() ![]() ![]() 發表:66 回覆:751 積分:1253 註冊:2002-03-13 發送簡訊給我 |
再提供一個沒有資料封裝的版本,
僅提供個人對於資料處理的看法,無關平行運算 謹供參考 ^_^ [code delphi] procedure TfrmMain.Button10Click(Sender: TObject); var M: TMemoryStream; fh: PBitmapFileHeader; ih: PBitmapInfoHeader; p1,p2,tt: PByte; size: Integer; Label DO_EXIT; begin if not FileExists('D:\TEST.BMP') then EXIT; M := TMemoryStream.Create; try M.LoadFromFile('D:\TEST.BMP'); fh := M.Memory; ih := Pointer(Integer(fh) SizeOf(fh^)); //限定 Bitmap 格式... if (fh=nil) or (PWORD(fh)^<>$4D42) then goto DO_EXIT; if (ih=nil) or (ih.biBitCount<>24) then goto DO_EXIT; with fh^,ih^ do begin size := Integer(bfSize-bfOffBits) div biHeight; GetMem(tt,size); try //pointer of Bitmap Data p1 := Pointer(Integer(fh) Integer(bfOffBits)); p2 := Pointer(Integer(p1) size*(biHeight-1)); repeat Move(p2^,tt^,size); Move(p1^,p2^,size); Move(tt^,p1^,size); Inc(p1,size); Dec(p2,size); until Integer(p1)>=Integer(p2); M.SaveToFile('D:\TEST_2.BMP'); finally FreeMem(tt,size); end; end; DO_EXIT: finally FreeAndNil(M); end; end; [/code] |
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
抱歉下面太多恕刪。
謝謝你的回覆,想請問 一下所謂用「記憶體映射」的方式是指記憶體移動嗎?還是指「MapViewOfFile」,這個不是只是用來處理不同程序間資料溝通用的嗎?? 另外問一下,採用jow大大的程式碼,就算我的圖是pf1bit而且是每一個bit都要處理,速度也是很快嗎?因為這個程式碼第一次看過,自已也沒寫過這種,所以不是很了解,加上上班又在忙別的事 更不能專心看文,但還是感謝您的回文。 ===================引 用 jcjroc 文 章=================== 是這樣沒錯,但我採用記憶體映射,效能比你的方式還要好很多.程式也單純多多.(我是懶惰鬼,我的字典裡找不到"勤勞"兩個字)
------
DELPHI初學者 |
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
感謝aftcast大大的回覆,觀念問題真是很難搞,但一定要先了解,才能處理。
===================引 用 aftcast 文 章=================== 回 macchen 上面的問題: 1/ VCL 用另一種簡單的方式講就是 delphi 裡所提供的元件,無論是可視或不可視或可不可以在設計時期拉進來,通通可以當它是VCL元件。(不精準的說法,但差不多那樣想就可以) 一開始就是沒加synchronize及lock的方式,就是一樣很慢,是差二倍時間沒錯,所以才會想說是不是vcl的關系,但沒想到其他的大大提出了別種方式,可以更快,但是我還沒測試。 3/ [ 當初會有這種想法,因為c 有提供openmp這種東西,而delphi沒有,所以去google查了,找到一個多核計算的範例,其內容是同一段程式碼用雙核中的單核跑二次,與雙核分別各跑一次,時間差了快一倍,所以才會想在這邊做這種方式來減少時間。] 我想找時間也去研究一下,有心得在和你分享一下。 嗯,了解。 5 若照我上面4的做法。那就不用waitforsingleobject。mainform也不能這樣做!!!。你只要在new出來的thread的excute的最後一行sendmessage 給 mainform 通知一下就可以。但建議目前測速的情形下,用MessageBox這個api來show一下,就表示結束。如此測時間方便一點。若確定合你要的,再去設剛講的message (這要自訂一個message)。 嗯,應該用一個message來處理即可。
------
DELPHI初學者 |
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
|
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
抱歉,恕刪。
非常感謝jow大大的程式碼,花時間打這些code應該手會很酸吧,想請問一下,我這個圖片是pf1bit,所以我需要1個1個bit去處理,用您提供的程式碼也行嗎,最近公事又在忙了,所以想先請教一下觀念,不是直接做xor,因為要 依據其中一張圖來決定是否要填入1的值,請問是在「Move(p2^,tt^,size);」這段做處理即可嗎?非常謝謝您的代碼,話說,新的代碼真的省很多了,也比較好理解,但我還是會將這二個代碼努力的啃一下,如有任何問題再請jow指 導一下小弟,畢竟沒碰過的東西實在太多了,謝謝。 ===================引 用 jow 文 章=================== 再提供一個沒有資料封裝的版本, 僅提供個人對於資料處理的看法,無關平行運算 謹供參考 ^_^ [code delphi] procedure TfrmMain.Button10Click(Sender: TObject); var M: TMemoryStream; fh: PBitmapFileHeader; ih: PBitmapInfoHeader; p1,p2,tt: PByte; size: Integer; Label DO_EXIT; begin if not FileExists('D:\TEST.BMP') then EXIT; M := TMemoryStream.Create; try M.LoadFromFile('D:\TEST.BMP'); fh := M.Memory; ih := Pointer(Integer(fh) SizeOf(fh^)); //限定 Bitmap 格式... if (fh=nil) or (PWORD(fh)^<>$4D42) then goto DO_EXIT; if (ih=nil) or (ih.biBitCount<>24) then goto DO_EXIT; with fh^,ih^ do begin size := Integer(bfSize-bfOffBits) div biHeight; GetMem(tt,size); try //pointer of Bitmap Data p1 := Pointer(Integer(fh) Integer(bfOffBits)); p2 := Pointer(Integer(p1) size*(biHeight-1)); repeat Move(p2^,tt^,size); Move(p1^,p2^,size); Move(tt^,p1^,size); Inc(p1,size); Dec(p2,size); until Integer(p1)>=Integer(p2); M.SaveToFile('D:\TEST_2.BMP'); finally FreeMem(tt,size); end; end; DO_EXIT: finally FreeAndNil(M); end; end; [/code]
------
DELPHI初學者 |
jcjroc
高階會員 ![]() ![]() ![]() ![]() 發表:21 回覆:279 積分:115 註冊:2002-09-18 發送簡訊給我 |
你可能會錯意了!!!
我是在跟你說,錯誤的觀念 錯誤的邏輯 錯誤的技術引用是經不起實際商業運用的考驗........不過Demo的話,隨便就好......... 給台車給舒馬克開,他絕對大腳一踩油門到底........阿!!啥極速才90公里喔!!!舒馬克夠爛.........還號稱是車神....... 給台法拉利讓我開........看我神氣坐上駕駛座發動引擎......大腳一踩油門到底........阿!!啥極速才60公里喔!!!法拉利夠爛.........還號稱是超級跑車....... ===================引 用 macchen 文 章=================== 抱歉恕刪。 感謝jcjroc大大的回覆,這個時間是呈線性的嗎?這樣還真的很快,非常感謝您提供的觀念,小弟不是很了解,但會再花時間看完jow提供的代碼。 ===================引 用 jcjroc 文 章=================== 效能.......一組一千組一萬組 0.5s 500s 5000s .............再加幾顆CPU,然後多泡幾杯咖啡,如此之差而已. 加油啦!!!! |
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
jcjroc大大你好,可以請說的白話一點嗎?每次都搞不太懂你的意思,謝謝。
===================引 用 jcjroc 文 章=================== 你可能會錯意了!!! 我是在跟你說,錯誤的觀念 錯誤的邏輯 錯誤的技術引用是經不起實際商業運用的考驗........不過Demo的話,隨便就好......... 給台車給舒馬克開,他絕對大腳一踩油門到底........阿!!啥極速才90公里喔!!!舒馬克夠爛.........還號稱是車神....... 給台法拉利讓我開........看我神氣坐上駕駛座發動引擎......大腳一踩油門到底........阿!!啥極速才60公里喔!!!法拉利夠爛.........還號稱是超級跑車.......
------
DELPHI初學者 |
jcjroc
高階會員 ![]() ![]() ![]() ![]() 發表:21 回覆:279 積分:115 註冊:2002-09-18 發送簡訊給我 |
舒馬克當然是車神...........極速90是因為給他的車是台20幾年前的裕隆速利1200
法拉利當然是超級跑車...........問題是我不知道要換檔...................... 以上的共通點是......裕隆速利是我給舒馬克的................法拉利是我開的.......... 結論是不管法拉利或是舒馬克都很爛............而我是最好的............ 程式跑不快...........是硬體還是軟體關係?????阿災............反正這時候我是路人甲買醬油路過的....... 題外話........如果你的題目是我做的話,依需求,對我來說會趨近線性沒錯. jow:根據需求然後只使用單執行緒,如果我來弄至少會快你4倍,相信你會知道原因的.但只是Demo而已隨便就好. ===================引 用 macchen 文 章=================== jcjroc大大你好,可以請說的白話一點嗎?每次都搞不太懂你的意思,謝謝。 ===================引 用 jcjroc 文 章=================== 你可能會錯意了!!! 我是在跟你說,錯誤的觀念 錯誤的邏輯 錯誤的技術引用是經不起實際商業運用的考驗........不過Demo的話,隨便就好......... 給台車給舒馬克開,他絕對大腳一踩油門到底........阿!!啥極速才90公里喔!!!舒馬克夠爛.........還號稱是車神....... 給台法拉利讓我開........看我神氣坐上駕駛座發動引擎......大腳一踩油門到底........阿!!啥極速才60公里喔!!!法拉利夠爛.........還號稱是超級跑車....... |
macchen
初階會員 ![]() ![]() 發表:66 回覆:102 積分:33 註冊:2006-07-07 發送簡訊給我 |
好吧,感謝你的回覆,我沒有慧根,還是不了解,但畢竟我是發問問題的人,本來就該虛心指教,並且不是每個人都願意教導別人的,謝謝大家。
===================引 用 jcjroc 文 章=================== 舒馬克當然是車神...........極速90是因為給他的車是台20幾年前的裕隆速利1200 法拉利當然是超級跑車...........問題是我不知道要換檔...................... 以上的共通點是......裕隆速利是我給舒馬克的................法拉利是我開的.......... 結論是不管法拉利或是舒馬克都很爛............而我是最好的............ 程式跑不快...........是硬體還是軟體關係?????阿災............反正這時候我是路人甲買醬油路過的....... 題外話........如果你的題目是我做的話,依需求,對我來說會趨近線性沒錯.
------
DELPHI初學者 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |