2012年9月14日 星期五

EmguCV Image Process: Processing Image with Classes part3

中正紀念堂天色變化縮時

EmguCV 2.3 Application Programming : Processing Images with Classes

參考OpenCV 2 Computer Vision Application Programming Cookbook第三章

本篇介紹如下:

Using the Singleton design pattern

Using the Model-View-Controller architecture to design an application

Using the Singleton design pattern

上一篇介紹利用一個簡單的UI介面來操作顏色偵測

Singleton 是另一個相當常見的設計模式

通常翻譯成:獨體模式

Singleton的使用可以幫助方便存取class的instance

並且在program的執行中只會對此class產生一個instance

在這邊利用Singleton的實作,來存取上一篇提到的Controller物件


首先在ColorDetectorController中加入一個private的static成員

private static ColorDetectorController Singleton=null;
Singleton用來維持一個class的instance

再來要提供一個取得instance的方法

而這個方法必須確保只會建立這個class的instance一次!

採用static的方法來建立class的instance

其中必須判斷是否已經建立過instance了

//Gets access to Singleton instance
public static ColorDetectorController GetInstance()
{ 
    //create the instance at first call
    if (Singleton == null)
        Singleton = new ColorDetectorController();
    return Singleton;
}
先判斷Singleton是否為null

如果是才建立此class的instance,並回傳此instance

這邊要注意的是

這樣的寫法並不是thread-safe

如果要應付多個thread要有所改變,這裡先暫不討論!

//Releases the singleton instance of this controller.
public static void Destroy()
{
    if (Singleton != null)
    {
        //calls the dispose method of the singleton instance
    }
    Singleton=null;
}
由於C#無法直接delete instance

所以在if判斷式裡面

可以去呼叫此instance的dispose方法(如果有的話)
(或是任何釋放使用資源的方法)

這樣就完成了!


這時候要使用ColorDetectorController的class

都可以透過GetInstance()來存取ColorDetectorController的instance

就算有多個class要使用ColorDetectorController

也能保證只會建立一個ColorDetectorController的instance

在上一篇介紹的Chapter3Form在使用ColorDetectorController時就要做一些修改

這時候原本的區域成員_Controller就可以拿掉了

ColorDetectorController _Controller;
這行可以刪掉了!!

原本有使用到此成員的地方都要做修正

依序把OpenButton_Click跟ProcessButton_Click改一改

private void OpenButton_Click(object sender, EventArgs e)
{
    if (OpenFile.ShowDialog(this) == DialogResult.Cancel)
    {
        return;// User selects nothing
    }
    String imagePath = OpenFile.FileName;
    //Set the input image
    ColorDetectorController.GetInstance().SetInputImage(imagePath);
    //Show the input image
    CvInvoke.cvShowImage("Input Image", ColorDetectorController.GetInstance().GetInputImage());
}
OpenButton_Click修正如上

所有之前參考_Controller的地方都要改成ColorDetectorController.GetInstance()

private void ProcessButton_Click(object sender, EventArgs e)
{
    //Target color is hard-code here
    ColorDetectorController.GetInstance().SetTargetColor(30, 30, 45);
    ColorDetectorController.GetInstance().Process();
    //Show the output image
    CvInvoke.cvShowImage("Output Image", ColorDetectorController.GetInstance().GetLastResult());
}
ProcessButton_Click修正如上

這時候使用ColorDetectorController,不必再去找方法create這個class

也不必考慮什麼時候create

反正需要用到的時候就用ColorDetectorController.GetInstance()來取得唯一的instance!

ColorDetectorController.Destroy();
而在程式被關閉時就可以呼叫Destroy的方法


當Controller實作Singleton的設計模式時

任何class要去存取Controller都會變得相當容易

這時候如果要更嚴謹的實作這個應用程式(application)

就需要更慎密的GUI了

這時候就需要用到MVC架構


Using the Model-View-Controller architecture to design an application

Model-View-Controller簡稱MVC,在維基中有詳細的介紹

在之前的實作中,應該有發現三個很重要的設計模式:

Strategy,Controller,Singleton

而這裡介紹的MVC的架構,就使用了這三種設計模式來做整合

MVC架構的好處就是清楚的切割應用邏輯上的關係

相信維基上已經說明得相當清楚了!

這裡就直接來討論實做吧!!


來記得我們當初寫的ColorDetector的class吧

這就是屬於實作演算法的部分

也就是所謂的Model這層

接下來我們又實做了ColorDetectorController

負責轉發請求給ColorDetector,對請求進行處理

也就是Controller這層

由於Controller的關係,使得建立一個UI變得容易

而之前寫的Windows Form就是屬於View這層

所以其實之前的實作就是逐漸在建立一個MVC的架構

只是之前的方式在設定偵測顏色、顏色的threshold都是寫死在程式中

現在再把這邊好好改一下就OK了!!


由於這裡要選擇顏色

所以從工具箱中拉入一個叫做:ColorDialog的物件

並把這個物件重新命名成:ColorDialog

然後再加入一個選擇顏色的Button,命名:SelectButton

在button click的時候抓取顏色

private void SelectButton_Click(object sender, EventArgs e)
{
    if (ColorDialog.ShowDialog() != DialogResult.Cancel)
    {
        Color color= ColorDialog.Color;
        ColorDetectorController.GetInstance().SetTargetColor(color.R, color.G, color.B);
    }
}
這樣會跳出一個視窗,選擇顏色

然後將顏色的Red、Green、Blue傳入之前寫的方法SetTargetColor

這樣顏色就設定完成!!


再來從工具箱加入一個TrackBar,命名:DistanceBar

並把Minimum的值設為0,Maximum設為255

然後加入一個Label讓它顯示:Color Distance Threshold

再用另一個Label,命名為DistanceValue,並把value設為0

在拉動TrackBar的時候把值設定給Controller

private void DistanceBar_Scroll(object sender, EventArgs e)
{
    DistanceValue.Text = DistanceBar.Value.ToString();
    ColorDetectorController.GetInstance().SetColorDistanceThreshold(DistanceBar.Value);
}
拉動的時候把值給DistanceValue這個Label,讓它顯示在畫面上

這樣使用者才知道拉到多少數值

再把拉到的數值傳給SetColorDistanceThreshold


之前的畫面顯示是跳出新的視窗來

這邊從工具箱加入一個PictureBox,命名為:PictureBox

設定好長、寬,拖拉到適合的位置

在OpenImage跟Process時,要把圖顯示在這個PictureBox上面

    
//Show the input image
ColorDetectorController.GetInstance().GetInputImage());
PictureBox.Image = ColorDetectorController.GetInstance().GetInputImage().ToBitmap();
把OpenButton_Click原本show圖的程式改成用PictureBox來顯示

    
//Show the output image
PictureBox.Image = ColorDetectorController.GetInstance().GetLastResult().ToBitmap();
把ProcessButton_Click原本show圖的程式改成用PictureBox來顯示

整體的GUI畫面會變成這樣

多了顯示畫面、Color Distance Threshold的設定bar、Select Color的按鈕


操作的情況如下:

按下Open Image選擇你要的圖檔,這時候就會直接顯示在GUI上

這時候按下Select Color的按鈕就會跳出調色盤,讓使用者可以自由的選擇顏色

 拉動Bar去調整Color Distance Threshold的值

再按下Process的按鈕就會看到最後處理的結果!!

這樣一個簡單的顏色偵測應用程式就完成了!!

你也可以來試試看!!

沒有留言:

張貼留言