星期二, 4月 26, 2011

Week 11: 預覽回呼函數實作

1. 預覽回呼函數 preview callback function 

  當視訊擷取驅動程式接收到來自視訊裝置的畫面(frame), 在 preview 模式之下, 將此畫面顯示所連結的視訊視窗之中。

  我們可以透過 capSetCallbackOnFrame 這個函數來指定當發生 frame preview 之前, 先執行一個特定的 callback function, 即預覽回呼函數。這個預覽回呼函數的名稱可以由我們自由命名, 但是傳入的參數個數與其資料型態則必須符合 VFW 的規定。

// 使用者自行寫的預覽回呼函數必須在公用變數宣告區宣告
LRESULT CALLBACK FrameCallBack( HWND hwndCapture, PVIDEOHDR lpvhdr );

// 設定 callback function 與視訊擷取視窗之間的連結,
// 請將此行放到開啟視訊擷取視窗, 並開始 preview 的指令後

capSetCallbackOnFrame(hwndCapture, &FrameCallBack);

2. 實驗: 當程式開啟視訊擷取視窗後, 顯示預覽的畫面總數到 Label 上。

 實驗目的: 了解視訊擷取視窗之預覽回呼函數的設定與使用方法。

 範例程式: W11-SP


3. 如何關閉預覽回呼函數?

 capSetCallbackOnFrame(hwndVideo, NULL);


  
 
4. 預覽回呼函數可以做些什麼?

 好處: 就是我們可以在畫面預覽之前, 先對畫面資料做預先處理, 例如: 加入文字、物件或特效等等。

 

 這段影片就是利用預覽回呼函數, 將龍珠放置到畫面之中, 再與攝影機所拍攝的手進行互動... 

 但, 問題是這些畫面資料到底怎麼存取呢?

5. 如何從記憶體直接擷取視訊畫面?

 透過 capSetCallbackOnFrame 這個函式設定: 當視訊擷取視窗(代碼為 hwndViedo) 取得一個 frame 後, 必須執行我們所定義的 callback function: FrameCallBack,

capSetCallbackOnFrame(hwndVideo, &FrameCallBack);

LRESULT CALLBACK FrameCallBack( HWND hwndCapture, PVIDEOHDR lpvhdr );

 在我們所自行定義的 FrameCallBack callback function 中, 有兩個輸入參數:

 a. HWND hwndVideo,

  指明哪一個視訊擷取視窗, 即該視訊擷取視窗的 handle。

 b. PVIDEOHDR lpvhdr,

  capSetCallbackOnFrame 這個函式會自動把視訊擷取視窗的相關資訊透過 PVIDEOHDR lpvhdr 這個結構變數, 讓 FrameCallBack callback function 來使用。

  有關 PVIEDOHDR 這個結構的相關資訊, 可以在 vfw.h 中, 找到如下的結構定義:

/* video data block header */
typedef struct videohdr_tag {
LPBYTE lpData;      /* pointer to locked data buffer */
DWORD dwBufferLength;   /* Length of data buffer */
DWORD dwBytesUsed;   /* Bytes actually used */
DWORD dwTimeCaptured;  /* Milliseconds from start of stream */
DWORD_PTR dwUser;   /* for client's use */
DWORD dwFlags;      /* assorted flags (see defines) */
DWORD_PTR dwReserved[4];   /* reserved for driver */
} VIDEOHDR, NEAR *PVIDEOHDR, FAR * LPVIDEOHDR;

  透過 結構 videohdr_tag 的宣告, 我們獲知擷取視窗的 data buffer 的指標可以用 lpData 這個變數來取得, 即

  CaptureData = LPVIDEOHDR(lpvhdr);
  ptrCapture = CaptureData->lpData;


  // 全域變數宣告
  LPVIDEOHDR CaptureData;
  BYTE *ptrCapture, *ptrImage;


  說明:
  a. CaptureData 是全域結構變數, 其資料型態亦為 PVIDEOHDR。
  b. *ptrCapture 與 *ptrImage 是兩個指向記憶體位址的全域指標變數。

6. 實驗: 將視訊擷取視窗的內容即時顯示於影像物件之中。

  實驗目的: 了解視訊擷取視窗資料緩衝區的記憶體存取方法。
 
  本實驗說穿了就是把某一塊記憶體(視訊擷取視窗資料緩衝區/data buffer) 複製到另一塊記憶體(影像物件存放色彩資料的記憶體) 之中。因此, 我們只要弄清楚兩個記憶體的起始位址, 自然可以輕鬆完成實驗。

  透過 videohdr_tag 結構中的 lpData, 我們可以得到視訊擷取視窗的資料暫時存放區的起始位址。

  CaptureData = LPVIDEOHDR(lpvhdr);
  ptrCapture = CaptureData->lpData;


  透過 TBitmap::ScanLine 這個 property 我們可以得到影像元件中, 每一列(row) 的影像資料存放的記憶體起始位置。

  ptrImage = (BYTE *)Form1->imCW->Picture->Bitmap->ScanLine[i];

  
 

星期二, 4月 19, 2011

Week 10: 如何消除雜訊的干擾?

 

1. Difference 黑白影像中所有的白點都是實質上所出現的物件嗎?
  a. 如果不是, 哪些是雜訊呢?
  b. 如何消除雜訊的干擾?

延續 Week 7 的討論, 我們想要忽略小白雜訊點的干擾, 只對進入畫面的大型物件互動, 最簡單的方式就是降低畫面的解析度, 那這些小雜訊點就會 "看不到" 了。

將視訊監控畫面以 8*8 大小的區塊為單位, 當區塊中的白點總數超過一半 (>31) 時, 整個區塊都輸出成白色區塊, 如下圖。

  

從 另外一種角度思考, 其實就是把整個畫面縮小成 40*30 的大小來監控, 這樣那些小雜訊就縮小到完全沒有影響了, 如下圖。

   

範例程式: W10-SP

2. 什麼是 Callback Function ?

 2.1 函數的呼叫 (call) 與 結束 (return)

 在程式的執行過程中, 當主程式呼叫一個函數 (call function) 時, 程式會跳到函數繼續執行, 當遇到 return 指令時, 就會返回主程式的呼叫點繼續執行。

 2.2 Callback Function = Call + Back + Function

 當我們執行某個應用程式時, 針對 Form 上各個物件所發生的事件, 嚴格來說可以分成兩類:

 a. 由使用者觸發, 如使用者透過滑鼠或鍵盤所觸發的事件。

  這類事件, 在 object-oriented 程式語言中, 是用 event-driven 的設計, 使用者針對個別物件, 撰寫不同事件處理程序來因應。

 b. 非由使用者觸發, 乃系統自行發生的事件。

  如程式發生錯誤情況, 或系統做了特定事件, 如從視訊裝置擷取一個畫面。此類事件, 使用者就可以設定 callback function 來因應這些事件的發生。

3. 預覽回呼函數 preview callback function 

  當視訊擷取驅動程式接收到來自視訊裝置的畫面(frame), 在 preview 模式之下, 將此畫面顯示所連結的視訊視窗之中。

 我們可以透過 capSetCallbackOnFrame 這個函數來指定當發生 frame preview 之前, 先執行一個特定的 callback function, 即預覽回呼函數。這個預覽回呼函數的名稱可以由我們自由命名, 但是傳入的參數個數與其資料型態則必須符合 VFW 的規定。

星期日, 4月 17, 2011

Week 9: 期中考

 題目:



 成績公布:

  全班平均達 60.1 分, 剛好及格。
  最高 96 分, 次高 88 分, 第三 84 分。



 成績分布統計圖:



 各題平均分數統計圖:



 問答題第一題之範本解答