首先要說明的是,在講義 1.2.2 儲存影像陣列裡的
第一部分程式碼 (page.14)
TCanvas *csBuf=new TCanvas;
HDC hDC=GetDC(Panel->Handle);
csBuf->Handle=hDC;
Graphics::TBitmap*Source=new Graphics::TBitmap();
Source->Width=Panel->Width;
Source->Height=Panel->Height;
Source->Canvas->CopyRect(Rect(0, 0, Source->Width, Source->Height),
csBuf,
Rect(0, 0, Panel->Width, Panel->Height));
Image->Picture->Bitmap->Assign(Source);
for(i=0;i<BitmapInfoHead.biHeight;i++)
{
ptr=(Byte *) Image->Picture->Bitmap->ScanLine[i];
for(k=0,j=0;j<BitmapInfoHead.biWidth;j++)
{
background[i][j][0] =ptr[k+2];
background[i][j][1]= ptr[k+1];
background[i][j][2] =ptr[k];
k+=3;
}
}
只要key in藍色部分,
顯示圖片靠 Image->Picture->Bitmap->Assign(Source);裡的Assign( )函數
(我覺得這範例寫得不好,傳回給source會影響截圖計算,
可能會給初學者錯誤的觀點,所以我改成background
而且範例需要修改正確 ... 講義上都是不完整的code)
是給後續使用的,跟顯示影像無關
如果你只是想顯示一張擷取的影像,請不要理後續Scanline的部分
這樣瞭解了吧?
anyway, 下面接著講 Scanline
ptr=(Byte*) Image->Picture->Bitmap->ScanLine[i];
就是這條混蛋指令讓人死一堆腦細胞
ptr是什麼? 為什麼可以這樣做?? Scanline的功能???
也就是如下:
所以 *ptr儲存的是Byte型態的記憶體位址
而
(Byte*)Image->Picture->Bitmap->ScanLine[1]; 回傳的就是0xB0
(Byte*)Image->Picture->Bitmap->ScanLine[2]; 回傳的就是0xC0
用很白話的講,Scanline就是掃瞄一條線,
如果你要問我為什麼要加
別傻了,單純用Image->Picture->Bitmap->ScanLine[i];
跑出來的應該是RGB的值吧
我猜的
想多認識(Byte*)可以參考此網誌
http://www.wretch.cc/blog/hhmmjj/9594208
這樣應該懂Scanline是做什麼的了吧?
所以,
{
ptr=(Byte *) Image->Picture->Bitmap->ScanLine[i];
for(k=0,j=0;j<BitmapInfoHead.biWidth;j++)
{
background[i][j][0] =ptr[k+2];
background[i][j][1]= ptr[k+1];
background[i][j][2] =ptr[k];
k+=3;
}
}
這段,其實就是將Image裡每個pixel的RGB值傳給background
讓你可以將background的值累加起來後取平均,
然後把background顯示出來,就可以得到視訊的背景圖了
再囉嗦一點
上一篇文章作者提到因不懂Scanline
所以改用GetRValue()、GetGValue()、GetBValue()
去擷取Image的RGB值
這兩者有什麼差異?
最大的差異就是在執行速度吧
上禮拜在作業系統的課上老師有提到,
以前ANSI C用來寫OS的武器之一就是指標 => *
用指標直接存取記憶體的速度本來就較快,
更何況用了三個函數才能去得RGB值
假設
ptr[k] 取出R值的速度是0.01秒
GetRValue() 取出R值的速度是0.1秒
相差10倍
每一個pixel有RGB三個值,等於需要花 0.03 : 0.3
一張800x600的圖片有480000個pixel
這樣用函數取RGB所花的時間會比用指標多花上10x480000倍 ...
應該是這樣算吧,我只是舉例有錯不能怪我
p.s.
=================================================
附錄: i++ v.s. ++i
老師說這個不會也不影響寫程式是沒錯
但是多瞭解一些還是可以幫助釐清觀念
尤其是上arping的課如果有要寫程式時,沒分清楚可能就哉了
雖然我也沒很懂,簡易的描述使用上的差異應該還是ok的
把寫好的程式進行編譯時,
編譯器也是從上到下,由左至右讀取文字判斷要編譯成什麼樣的低階語言
所以
i++; 編譯器先讀到 i 再讀到++,所以把 i 加1
++i; 編譯器先讀到++,再讀到 i ,接著把 i 加1
看起來意思都相同,但這是因為這兩句語法都是獨立使用
如果程式碼長這樣呢?
int a[3]={0,0,0};
i=0;
a[i++]=1;
i=0;
a[++i]=1;
看起來似乎都是把a[1]的值變成1,輸出就會是 {0,1,0} 對吧?
其實執行結果陣列a的內容會是這樣 => {1,1,0}
i=0;
a[i++]=1;
編譯器會先把 i 提出來,並把 i 的值,0給a[]使用
然後才做 i++
所以這裡其實是 a[0]=1; i 的值為1
i=0;
a[++i]=1;
編譯器會先執行 ++ 的動作,也就是把 i 加1之後,
才把 i 的值,1給a[]使用
也就是這裡其實是 a[1]=1; i 的值為1
所以真正的執行結果陣列a的內容會是 {1,1,0}
就我的印象,arping好像還講過 i++ 和 ++i 在執行上還有別的差異
那時他沒多講我也沒多問就 .... 現在就不會了
i=0;
a[(i++)]=2;
你覺得陣列a之中哪個位置會變成2?
i=1;
c = (i++)+(++i)+(i++)+(++i)+i+(i++)+(++i);
最後c的值會是多少?
我用手算是29,用Dev-C++執行結果卻是19
怎麼會這樣 ... ??? (使用不同的IDE可能會有不同的執行結果)
試試看吧 很好玩的 :D
1 則留言:
將變數 ptr 宣告為 (BYTE *) 的用意很簡單, * 用來告訴電腦 ptr 是一個指標的資料型態, BYTE 用來告訴電腦, 這個指標所指向的位址, 其資料是一個 BYTE, 一個BYTE 為單位來看待的, 因此, ptr+1 就是指向下一個 BYTE, 在實際的電腦記憶體中, +1 就是差一個 BYTE。
可以做一個實驗, 如果今天將變數 ptr 宣告為一個 (INT *), 將 ptr+1 時, 其實際的位址差了多少?
張貼留言