2008年2月23日 星期六

講義 1.2 程式 & 提問 (二)

(接上文)

接著是把 Image 儲存到陣列的部分

 for(i=0;i<BitmapInfoHead.biHeight;++i)
 {
  ptr=(Byte*)Image1->Picture->Bitmap->ScanLine[i];
  for(k=0,j=0;j<BitmapInfoHead.biWidth;++j)
  {
   Source[i][j][0] = ptr[k+2];
   Source[i][j][1] = ptr[k+1];
   Source[i][j][2] = ptr[k];
   k+=3;
  }
 }

我在 compile 的時候,錯誤訊息都是在 Source[i][j][0] = ptr[k+2]; 這三行
內容是什麼我忘了
應該是因為型態的不同吧,我猜的
要研究一下 Byte 和 TBitmap 的內容是什麼才能知道
ptr 是 *Byte
Source 是 *Graphics::TBitmap


又或許是要另外宣告一個動態陣列來儲存而不是用 Source !?
我還沒試過

補充:
for loop 前面要先宣告 ptr,然後用動態配置 ptr 的長度
 Byte *ptr;
 ptr = new Byte [ Image1->Width*3 ];
寬度 x3是因為 Source[ ][ ][ ] 在這裡儲存的應該是 RGB
每次執行 ScanLine 函數都是讀取一整行的 RGB 值

至於 BitmapInfoHead.biHeight 和 BitmapInfoHead.biWidth
是經由宣告 BITMAPINFOHEADER 類別得到的
也就是如這一行程式碼
 BITMAPINFOHEADER BitmapInfoHead;
不過這樣還要去指定 BitmapInfoHead 的長寬
有點多此一舉的感覺, 所以在講義裡應該只是示意用
在 for loop 中用 Panel1->Width & Panel1->>Height
或是 Source->Width & Source->>Height 應該也可以
因為都是一樣的數值, 也就是會變成如下
 for(i=0;i<Source->>Height;++i)
 {
  ptr=(Byte*)Image1->Picture->Bitmap->ScanLine[i];
  for(k=0,j=0;j<Source->Width;++j)
  {
   Source[i][j][0] = ptr[k+2];
   Source[i][j][1] = ptr[k+1];
   Source[i][j][2] = ptr[k];
   k+=3;
  }
 }
不過這個部分我到現在還是沒 compile 過過


然後是第二個方法
先把單張擷取畫面儲存到 buffer 中再複製到剪貼簿裡,
然後再 assign 給 Image

在這裡要先引進剪貼簿的標頭檔
 #include <vcl\Clipbrd.hpp>
才能使用 Clipboard( ) 函數

一樣用個 button 然後丟進程式碼, 內容很短, 只有這樣
 capGrabFrameNoStop( hwndCapture );
 capEditCopy( hwndCapture );
 if( Clipboard()->HasFormat(CF_DIB) )
  Image1->Picture->Bitmap->Assign( Clipboard() );
就可以在 Image 中顯示擷取的圖片了

有個好玩的地方是,
當這裡的程式結束後,
開個小畫家按 Ctrl+V 也會在小畫家中顯示剛剛擷取到的圖片

講義 1.2 程式 & 提問 (一)

【1.2.1 視訊擷取 】

講義裡有提供建立視訊視窗、連線視訊裝置和顯示視訊的程式碼
但是只有提供粗略的函數

在 BCB 中,要顯示視訊,要先在 Form 中建立一個 Panel
Panel 元件在 Standard 裡的倒數第二個
然後要在程式碼中引進 vfw 的標頭檔才能使用 cap 系列的函數
 #include <vfw.h>

Photobucket
(點擊放大看全圖)

這是講義上沒提到的部分

然後建立一個 button,
把建立視訊視窗、連線視訊裝置和顯示視訊三個部分的程式碼都放在一起就可以了
compile 有錯的話只是缺少一些宣告 int i; 之類的程式碼,看錯誤訊息自己補一下就可以了

再補充兩個函數
1. 截斷視訊連結
 capDriverDisconnect( hwndCapture );
2. 恢復視訊連結
 capDriverConnect( hwndCapture,0 );

程式碼直接丟在 button 裡面或是 menu 的按鍵中就可以使用了
hwndCapture 是建立視訊視窗時宣告的 HWND class


【1.2.2 儲存影像陣列 】

講義裡提供了三種方法,都是先把影像顯示在 Image 元件中,
然後再把影像的內容儲存到陣列裡

第一個方法是是使用 CopyRect函數
複習一下 CopyRect 函數
 CopyRect( Rect(0,0,Source->Width,Source->Height) ,
      csBuf ,

      Rect(0,0,Panel1->Width,Panel1->Height) );

CopyRect 是將 csBuf(第二個參數)中的影像資料,

依照 Panel1 指定的矩形大小(第三個參數)複製到 Source 指定的矩形位置(第一個參數) 內

然後再用 Bitmap->Assign 函數將 Source 的內容指定給 Image1->Bitmap

其實程式碼只要執行到
 Image1->Picture->Bitmap->Assign(Source);
這一條指令, Image 上就會顯示擷取的單張影像了
挺神奇的!!