2016年9月12日 星期一

Emgucv3.1快速配置教學_開發環境 2015_Emgucv_快速入門








Emgucv3.1快速配置教學
開發環境 2015

Step1.新增WindowsForm專案

Step2.配置emgucv
Tools
-->NuGet Package Manager
-->Manage NuGet Packages for Solution



會自動幫你添加好相關的dll檔案


而且就連以前我們要自己手動去添加emgucv
提供的四個組件都已經幫我們弄好了喔

四個組件依序是
ImageBoxMatrixBoxHistogramBoxPanAndZoomPictureBox
30秒內我們完成了配置
是不是很方便不用再捨麼系統環境變數一堆拉哩拉紮的東西
好緊接著我們要先來顯示一張靜態圖片




Unit1.靜態圖片的處理

回到WindowsForm  可視化視窗介面布局 地方


引用三個特定命名空間

圖檔開啟




【程式技巧_按下按鈕將圖片A傳遞至圖片B
介面部分

Step1.改到外面宣告

Step2.Emgucv Clone方法


Unit2.常見的影像處裡
2-1.灰度(單通道)



2-2.BGR三通道分割及合併





寫法1.直觀寫法


private void button2_Click(object senderEventArgs e)
{
            //寫法1.直觀寫法          
            Image<BgrByteimgBimgGimgR;
            imgB = img1.Clone();
            imgG = img1.Clone();
            imgR = img1.Clone();

            for (int i = 0; i < imgB.Colsi++)
                for (int j = 0; j < imgB.Rowsj++)
                {
                    imgB.Data[ji, 0] = 255; //B
                    //imgB.Data[j, i, 1] = 0;   //G
                    //imgB.Data[j, i, 2] = 0;   //R
                }
           
            for (int i = 0; i < imgG.Colsi++)
                for (int j = 0; j < imgG.Rowsj++)
                {
                    //imgG.Data[j, i, 0] = 0; //B
                    imgG.Data[ji, 1] = 255;//G
                    //imgG.Data[j, i, 2] = 0;  //R
                }           
            for (int i = 0; i < imgR.Colsi++)
                for (int j = 0; j < imgR.Rowsj++)
                {
                    //imgR.Data[j, i, 0] = 0; //B
                    //imgR.Data[j, i, 1] = 0;   //G
                    imgR.Data[ji, 2] = 255;   //R
                }         
            pictureBox2.Image = imgB.ToBitmap();
            pictureBox3.Image = imgG.ToBitmap();
            pictureBox4.Image = imgR.ToBitmap();
}
寫法2.Emgucv函數
Step1.CvInvoke.Split Method
通道分割



Split()可以用上面提到Mat陣列
也可以用Image<Gray, byte> 陣列去接收



Step2.
通道合併
1. 利用img.Split()先丟到channels
2. 將不感興趣的channel設定為零 【感興趣的channel : COI
3. 宣告一個VectorofMat資料型態可以輸入三個Gray level的資料







經過修改
        private void button2_Click(object senderEventArgs e)
        {
            Image<BgrByteimgBgr;
            imgBgr = img1.Clone();

            Image<Graybyte>[] imageChannels1 = imgBgr.Split();
            //imageChannels1[0] BlueimageChannels1[1] GreenimageChannels1[2] Red
            /* remove Green and Red channels, ie. only Blue channel is saved */ 
            int[] zeroCHs1 = new int[2] { 1, 2 };
            for (int i = 0; i < 2; i++)
                imageChannels1[zeroCHs1[i]].SetZero();          
            VectorOfMat c1 = new VectorOfMat();
            c1.Push(imageChannels1[0]);
            c1.Push(imageChannels1[1]);
            c1.Push(imageChannels1[2]);
            Image<BgrByteimgB = new Image<Bgrbyte>(imgBgr.Size);
            CvInvoke.Merge(c1imgB);
            pictureBox2.Image = imgB.ToBitmap();//B

            Image<Graybyte>[] imageChannels2 = imgBgr.Split();
            //imageChannels1[0] BlueimageChannels1[1] GreenimageChannels1[2] Red
            /*remove Blue and Red channels, ie. only Green channel is saved*/
            int[] zeroCHs2 = new int[2] { 0, 2 };
            for (int i = 0; i < 2; i++)
                imageChannels2[zeroCHs2[i]].SetZero();
            VectorOfMat c2 = new VectorOfMat();
            c2.Push(imageChannels2[0]);
            c2.Push(imageChannels2[1]);
            c2.Push(imageChannels2[2]);
            Image<BgrByteimgG = new Image<Bgrbyte>(imgBgr.Size);
            CvInvoke.Merge(c2imgG);
            pictureBox3.Image = imgG.ToBitmap();//G

            Image<Graybyte>[] imageChannels3 = imgBgr.Split();
            //imageChannels1[0] BlueimageChannels1[1] GreenimageChannels1[2] Red
            /*remove Blue and Green channels, ie. only Red channel is saved*/
            int[] zeroCHs3 = new int[2] { 0, 1 };
            for (int i = 0; i < 2; i++)
                imageChannels3[zeroCHs3[i]].SetZero();
            VectorOfMat c3 = new VectorOfMat();
            c3.Push(imageChannels3[0]);
            c3.Push(imageChannels3[1]);
            c3.Push(imageChannels3[2]);
            Image<BgrByteimgR = new Image<Bgrbyte>(imgBgr.Size);
            CvInvoke.Merge(c3imgR);
            pictureBox4.Image = imgR.ToBitmap();//R
        }
2-3.& 2-4. Canny_高斯模糊

private void button4_Click(object senderEventArgs e//Smooth
        {
            Image<BgrByteimgBgr;
            imgBgr = img1.Clone();
            /*convolution(捲積)*/
            //Image<Bgr, Byte> blur = imgBgr.SmoothBlur(5,5);  // 效果不太明顯
            //透過一個5*5kernek矩陣來計算pixel的值以也就是鄰近25個點的平均值
            //每個鄰點都需乘上所對應的權重值然後再加總起來!!
            //pictureBox6.Image = blur.ToBitmap();


            /*高斯模糊*/
            Image<BgrBytegaussian = imgBgr.SmoothGaussian(7);
            pictureBox6.Image = gaussian.ToBitmap();
        }

        private void button5_Click(object senderEventArgs e)
        {
            Image<BgrByteimgBgr;
            imgBgr = img1.Clone();

            Image<Graybytecanny = imgBgr.Canny(120,180);
            pictureBox7.Image = canny.ToBitmap();

        }



===============================================================================

如何使用emgucv_基礎技巧_L1(CvInvoke偵錯及使用、視窗文字和標題、文字擺放顏色、圖片物件使用)

Step1.先弄好開發環境





















環境 (Emgucv2.2.1 +  visual studio 2013)


Step2.

先試著載圖
這裡嘗試用看看Emgucv 中的  介面工具組
加入方式如下

工具 -->  選擇工具箱項目

































你已經成功把工具載入了

記得左側工具箱移過去(等一下確認一下版本~~  之前試過太多版啦 快錯亂了)




















先拉一個  imagebox  進去 我們的視窗panel吧!!!!

看他的效果


右鍵  可以直接載入圖片  真方便~



出現 錯誤

























錯誤修正兩個程序

【第一】.  確認是在  對應的  x64 系統執行下執行

右擊右方  『方案總管』  選擇最底  『屬性』

這邊我們需要改變一下  是去組態-->組態管理員-->改成x64

























【第二.】確認是否有載入opencv  dll檔

CvInvoke裡面提供了很多影像處理的基本方法

他們全部都是接自openCV的DLL函式庫

【EmguCV官網架構圖   說明】










立即修正  Emgucv.CV.CvInvoke  錯誤

























加入\bin\x64下的opencv dll
(2.2.0為例可加入opencv_core220.dll與opencv_imgproc220.dll,其餘的依需求加入)
這裡考慮到日後需要就全添加了

























加入後對DLL右鍵->屬性->複製到輸出目錄改成永遠輸出





再次編譯執行之後,他就會把檔案複製到輸出目錄直接從那邊找到參考路徑,
也就不會有例外發生


成功可秀圖





嘗試其他功能

右鍵屬性   還可以看   各通道色彩直方圖

===================================

用程式碼實現

(1)控制視窗大小
(2)控制視窗背景顏色
(3)視窗標題改變
(4)視窗中秀文字


首先   引用 表頭檔三行


先用字串   宣告  並初始化  我們想在視窗    上標中   呈現的文字

例如  :  「冠羽學長的視窗」 ....「xx的視窗」
CvInvoke  這個類提供cvNamedWindow這個method  來幫助開發者幫視窗命名  


public static int cvNamedWindow(
 string name
)







學會使用using 陳述式基本的 C# 語法,在實務開發上經常會使用到

使用 using 最主要的目的是為了讓物件建立的同時能確保該物件所佔用的資源
一定會被完整釋放

如果沒有釋放這些無法自動釋放的資源
就很有可能讓 .NET 應用程式發生 資源耗盡 (Resource Exhausted) 的狀況。

一個簡單的using 陳述式  基本架構
using (System.IO.StreamReader sr = new System.IO.StreamReader(@"C:\test.txt"))
{
    string s = null;
    while((s = sr.ReadLine()) != null)
    {
        Console.WriteLine(s);
    }
}

被一組using  包起來一個block
using  後頭放的子句  是一個建構子

用 using 陳述式的建議條件,

就是物件被建立的語法必須寫在 using 子句中

否則物件很有可能在被釋放後還有其他物件存取的情況

進而引發例外狀況!




大家都知道
C#中字符串常量可以以@開頭聲名,這樣的優點是轉義序列“不”被處理,

按“原樣”輸出,即我們不需要對轉義字符加上\ (反斜槓) ,就可以輕鬆coding。


string  filePath  =  @" c:\Docs\Source\a.txt "   //  rather than "c:\\Docs\\Source\\a.txt"


轉義序列

在C語言程序中,常常會看到這樣的語句:
    printf(“Welcome to C!\n”);
    在最後執行的時候我們發現,語句最後的\n並沒有被打印在屏幕上。反斜槓(\)稱為“轉義字符”,指示printf做一些非正常的事。在碰到反斜槓時,printf把反斜槓和下一個字符結合起來構成“轉義序列”,例如(\n)的意思是“新行”,它使光標定位到下一行的開始位置。下面列出了一些常用的轉義序列:

\n 換行。把光標定位到下一行的開始位置
\t 水平制表符。把光標跳到tab鍵的下一個輸出區
\r 回車。把光標定位在當前行(而不是下一行)的開始位置
\a 響鈴。使系統發聲
\\ 反斜槓。打印一個反斜槓字符
\' 雙引號.打印一個雙引號符號

這裡我們以  Emgucv  來做示範

一組   using   

using  後頭放的是   要創立的   圖片物件
.Net會自動完成垃圾回收,對於比較大的圖片,
我們可以使用using關鍵字在不需要的時候自動對其進行回收




使用   Image<Bgr , Byte> 來實現

Namespace: Emgu.CV

關於Image類的使用
Image<TColor, TDepth>用兩個參數定義:Color和Depth
TColor类型TDepth类型
GrayByte
Bgr (Blue Green Red)SByte
Bgra (Blue Green Red Alpha)Single (float)
Hsv (Hue Saturation Value)Double
Hls (Hue Lightness Saturation)UInt16
Lab (CIE L*a*b*)Int16
Luv (CIE L*u*v*)Int32 (int)
Xyz (CIE XYZ.Rec 709 with D65 white point)
Ycc (YCrCb JPEG)

範例

        // 創建一張灰度圖 
        Image<Gray, Byte> imgGray = new Image<Gray, Byte>( 480 , 320 );
         // 創建一張藍色的圖片 
        Image<Bgr, Byte> imgBlue = new Image<Bgr , Byte>( 480 , 320 , new Bgr( 255 , 0 , 0 ));
        
         // 從文件創建Image 
        Image<Bgr, Byte> imgFile = new Image<Bgr, Byte>( " MyImage.jpg " );
         
        // 從Bitmap創建Image 
        Bitmap bmp = new Bitmap( " MyImage.jpg " );
        Image<Bgr, Byte> imgBmp = new Image<Bgr, Byte>(bmp);


來看一 個using 搭配Image<Gray , Single>的例子


 using (Image<Gray, Single> image = new Image<Gray, Single>(1000, 800))
        {
            //對image的操作
        }


先有視窗
指定了  視窗的  寬(600) 和  高(200)
創建的圖片當背景了























code_秀綠背景圖視窗

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;

namespace Emgucv_ex_hand_gesture_recognition
{
    public partial class Form1 : Form
    {
        //設定視窗標題文字
        String winname = "冠羽學長的視窗";
        public Form1()
        {
            InitializeComponent();
            //Create a window with the specific name
            CvInvoke.cvNamedWindow(winname);
            //Create an image of 600*200 with color green
            using ( Image<Bgr, Byte> img1 = new Image<Bgr, byte>(600, 200, new Bgr(0, 255, 0)) )
            {                
                CvInvoke.cvShowImage(winname, img1.Ptr);
                CvInvoke.cvWaitKey(0);
                //Destory the window
                CvInvoke.cvDestroyWindow(winname);
            }
        }
    }
}



如何在上面加字?? 並指定字型
使用MCvFont Constructor (type, hscale, vscale)

Namespace: Emgu.CV.Structure

public MCvFont(
FONT type,
double hscale,
double vscale
)

type (FONT)
       The type of the font
hscale (Double)
       The horizontal scale of the font
vscale (Double)
       The vertical scale of the fonr

Create a Font of the specific type, horizontal scale and vertical scale

MCvFont 寫法 (還不會被秀出  只是指定字型、高度、寬度)


MCvFont f = new MCvFont(FONT.CV_FONT_HERSHEY_TRIPLEX, 1.0, 1.0);

通常習慣   讓他在   Image<Tcolor , Tdepth>這個類的    物件上  進行  繪製

因為   Image<Tcolor , Tdepth> 這個類別  提供Draw的  method可協助我們進行文字的秀出


img.Draw("hello world", ref f, new Point(10, 80), new Bgr(0, 0, 0));
























這裡我把它寫在   public Form1()  {....}這組括號中

在視窗一初始化後  就會進行



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;

namespace Emgucv_ex_hand_gesture_recognition
{
    public partial class Form1 : Form
    {
        //設定視窗標題文字
        String winname = "冠羽學長的視窗";
        public Form1()
        {
            InitializeComponent();
            //Create a window with the specific name
            CvInvoke.cvNamedWindow(winname);

            //Create an image of 480x180 with color yellow
            using (Image<Bgr, Byte> img1 = new Image<Bgr, byte>(480, 200, new Bgr(0, 255, 255)))
            {
                //Create a font
                MCvFont font = new MCvFont(Emgu.CV.CvEnum.FONT.CV_FONT_HERSHEY_COMPLEX, 1.0, 1.0);
                //Draw "Hello, world" on the yellow image;Start point is (25, 100) with color blue
                img1.Draw("Hello, world", ref font, new Point(25, 100), new Bgr(255, 0, 0));

                //Show the image in the window
                CvInvoke.cvShowImage(winname, img1.Ptr);
                //A key pressing event
                CvInvoke.cvWaitKey(0);
                //Destory the window
                CvInvoke.cvDestroyWindow(winname);
            }
        }
    }
}


不能秀中文字喔!!

























===========================================================================================














沒有留言:

張貼留言