半年前寫過應用裝飾模式於影像處理函式,溫故知新後想嘗試重新翻寫,希望對於正在學習裝飾模式的同好有所助益!
在上一篇 裝飾模式應用: 使用C#,提到三個類別Building、Furniture(Building子類別)、及繼承Furniture子類別,透過裝飾模式方式,讓客戶端可以任意順序裝飾物件,搭配不同資料型態儲存如陣列或List(長度可不固定),這篇將利用裝飾模式應用於影像處理步驟組裝。
1. Line 4: img私有影像成員
2. Line 5: name儲存影像處理方法名稱
3. Line 6~10: 存取name
4. Line 11~21: 存取img
5. Line 22~25: ImageObject創建子
6. Line 27~30: Process()虛擬函式: 影像處理函式
7. Line 31~35: ShowImg()虛擬函式: 顯示影像
8. Line 36: 保護級資料成員 ImageObject componet,用來裝飾(掛載)下一個物件
9. Line 37~40: 裝飾物件函式
1: public class ImageObject
2: {3: public ImageObject() { }
4: protected Mat img = new Mat();
5: protected string name;
6: public string Name
7: {8: get { return name; }
9: set { name = value; }
10: }11: public Mat Image
12: { 13: get 14: {15: return img;
16: } 17: set 18: {19: value.CopyTo(img);
20: } 21: }22: public ImageObject(string name)
23: {24: this.name = name;
25: } 26: 27: public virtual void Process()
28: {29: Console.WriteLine("{0} 影像處理", name);
30: }31: public virtual void ShowImg()
32: { 33: CvInvoke.Imshow(name, img);34: //CvInvoke.WaitKey();
35: }36: protected ImageObject component;
37: public void Decorate(ImageObject component)
38: {39: this.component = component;
40: } 41: 42: }1. Line9: 將目前影像處理結果(img)複製給下一個裝飾物件(component.Image)
2. Line10: 執行下一個裝飾物件影像處理: component.Process()
1: public class ImageCV:ImageObject
2: {3: public override void Process()
4: {5: if(component!=null)
6: {7: Console.WriteLine("{0} 影像處理", name);
8: // 將目前影像處理結果複製給下一個裝飾物件(component)
9: component.Image = img.Clone(); 10: component.Process(); 11: } 12: } 13: 14: }LoadImage類別(繼承ImageObject)
1. Line 5~9: LoadImage創建子,其中輸入filename為影像名稱,name為影像處理名稱。
2. Line 10~20: 覆寫Process(),載入一張影像
3. Line 19: 相當於執行ImageObject.Process(),把目前影像複製給下一個裝飾物件【component.Image = img.Clone();】,並執行下一個裝飾物件Process()
【component.Process();】
1: public class LoadImage : ImageCV
2: {3: string filename;
4: public LoadImage() { }
5: public LoadImage(string filename)
6: {7: this.filename = filename; // 影像名稱(完整路徑)
8: this.name = "LoadImage()"; // 影像處理名稱
9: }10: public override void Process()
11: { 12: img = CvInvoke.Imread(filename);13: if (img.IsEmpty)
14: {15: Console.WriteLine("{0} Error, Image is empty! ", name);
16: Console.ReadLine();17: return;
18: }19: base.Process();
20: } 21: }RGB2Gray類別(繼承ImageObject)
1. Line 14: 新增一個local影像變數imgDst,影像大小與img相同,但channel數為1。
2. Line 15: 執行彩色轉灰階 CvtColor(…)
3. Line 16: 將灰階影像在存回原本img。
4. Line 17: 相當於執行ImageObject.Process(),把目前影像複製給下一個裝飾物件【component.Image = img.Clone();】,並執行下一個裝飾物件Process()
【component.Process();】
1: public class RGB2Gray :ImageCV
2: {3: public RGB2Gray() { name = "RGB2Gray()"; }
4: public override void Process()
5: {6: if (img.IsEmpty)
7: {8: Console.WriteLine("{0} Error, Image is empty! ", name);
9: Console.ReadLine();10: return;
11: }12: int width = img.Width;
13: int height = img.Height;
14: Mat imgDst = new Mat(width, height, DepthType.Cv8U, 1);
15: CvInvoke.CvtColor(img, imgDst, ColorConversion.Bgr2Gray);16: img = imgDst.Clone(); // 將灰階影像在存回原本img
17: base.Process();
18: } 19: }PyrDown類別(繼承ImageObject)
1: public class PyrDown:ImageCV
2: {3: public PyrDown() { this.name = "PyrDown()"; }
4: public override void Process()
5: {6: if (img.IsEmpty)
7: {8: Console.WriteLine("{0} Error, Image is empty! ", name);
9: Console.ReadLine();10: return;
11: }12: Mat imgDst = new Mat();
13: CvInvoke.PyrDown(img, imgDst); 14: img = imgDst.Clone();15: base.Process();
16: } 17: 18: }PyrUp類別(繼承ImageObject)
1: public class PyrUp : ImageCV
2: {3: public PyrUp() { this.name = "PyrUp()"; }
4: public override void Process()
5: {6: if (img.IsEmpty)
7: {8: Console.WriteLine("{0} Error, Image is empty! ", name);
9: Console.ReadLine();10: return;
11: }12: Mat imgDst = new Mat();
13: CvInvoke.PyrUp(img, imgDst); 14: img = imgDst.Clone();15: //ShowImg();
16: base.Process();
17: } 18: }Smooth類別(繼承ImageObject)
1: public class Smooth : ImageCV
2: {3: public Smooth() { this.name = "Smooth()"; }
4: public override void Process()
5: {6: if (img.IsEmpty)
7: {8: Console.WriteLine("{0} Error, Image is empty! ", name);
9: Console.ReadLine();10: return;
11: }12: Mat imgDst = new Mat();
13: CvInvoke.PyrDown(img, imgDst); 14: CvInvoke.PyrUp(imgDst, imgDst); 15: img = imgDst.Clone();16: //ShowImg();
17: base.Process();
18: } 19: }客戶端測試1
假設一個影像處理步驟如下
1: LoadImage loadImage = new LoadImage(@"C:\Emgu\images\lena.jpg");
2: RGB2Gray rgb2gray = new RGB2Gray();
3: PyrDown pyrDown = new PyrDown();
4: PyrUp pyrUp = new PyrUp();
5: Smooth smooth = new Smooth();
6: string name = "object #1";
7: ImageObject imageObject1 = new ImageObject(name);
8: 9: loadImage.Name = name + " : (1)LoadImage()";
10: pyrDown.Name = name + " : (2)pyrDown()";
11: rgb2gray.Name = name + " : (3)rgb2gray()";
12: pyrUp.Name = name + " : (4)pyrUp()";
13: smooth.Name = name + " : (5)Smooth()";
14: 15: List<ImageObject> imgList1 = new List<ImageObject>();
16: imgList1.Add(loadImage); 17: imgList1.Add(pyrDown); 18: imgList1.Add(rgb2gray); 19: imgList1.Add(pyrUp); 20: imgList1.Add(smooth); 21: imgList1.Add(imageObject1); 22: 23: ImgProcList.Run(imgList1);ImgProcList類別
1: public static class ImgProcList
2: {3: public static void Run(List<ImageObject> imgList)
4: {5: // 執行影像處理流程
6: for (int i = 0; i < imgList.Count - 2; i++)
7: imgList[i].Decorate(imgList[i + 1]); 8: imgList[0].Process(); 9: 10: // 顯示每個步驟影像處理結果
11: for (int i = 0; i < imgList.Count - 1; i++)
12: { 13: imgList[i].ShowImg(); 14: } 15: CvInvoke.WaitKey(0); 16: } 17: }客戶端測試2
假設一個影像處理步驟如下
1: name = "object #2";
2: ImageObject imageobject2 = new ImageObject(name);
3: List<ImageObject> imgList2 = new List<ImageObject>();
4: 5: loadImage.Name = name + ": (1)loadimage()";
6: imgList2.Add(loadImage);7: rgb2gray.Name = name + ": (2)rgb2gray()";
8: imgList2.Add(rgb2gray);9: pyrDown.Name = name + ": (3)pyrdown()";
10: imgList2.Add(pyrDown);11: pyrUp.Name = name + ": (4)pyrup()";
12: imgList2.Add(pyrUp); 13: imgList2.Add(imageobject2); 14: 15: ImgProcList.Run(imgList2);
參考資料:
1. 裝飾模式應用: 使用C#
3. 大話設計模式, 作者:程杰






留言列表
