Friday, November 15

Let ‘s Change Scheme of Visual Studio

      โปรแกรมเมอร์ส่วนใหญ่ ที่ต้องทำงานเกี่ยวกับการเขียนโค๊ด ที่ต้องอยู่หน้าจอนานๆ มักไม่ค่อยชอบที่จะเขียนโค๊ดบนหน้าจอ ที่มี scheme ที่โทนสี ออกสว่างๆ เนื่องจาก จะทำให้สายตาเกิดความล้าได้ง่าย จึงมึกจะชอบแก้ไข scheme ให้มีโทนสีทึบๆ แต่ ให้สีสันของฟังก์ชั่น ขื่อตัวแปร ต่างๆ มีสีสันสดสน เพื่อให้ง่ายต่อการสังเกต

วันนี้ ผมมี scheme สวยๆ มาแนะนำ ซึ่งทำให้การเขียนโค๊ดของเรา ดูน่าสนใจยิ่งขึ้น สามารถเลือกดาวน์โหลด scheme ที่น่าสนใน และได้รับความนิยม จาก http://studiostyl.es/

Create and share Visual Studio color schemes

ขั้นตอน ก็ไม่ยาก ให้เลือกดาวน์โหลด scheme ที่ชอบได้เลย ให้ตรงกับเวอร์ชั่น Visual Studio ของเรา

Create and share Visual Studio color schemes

เปิดโปรแกรม Visual C# express 2010 (หรือเวอร์ชั่น ที่มีอยู่) จากนั้น คลิกที่เมนู Tools->Setting  แล้ว เลือก Import and Export Setting…..

Create and share Visual Studio color schemes

เลือก Import Seleted environment setting

Create and share Visual Studio color schemes

แล้วทำการ Browse ไปหา Setting ไฟล์ที่เราดาวน์โหลดมา ซึ่งโปรแกรมจะเก็บ setting เก่าไว้ด้วย หากเราเลือกให้เก็บไว้ ดังรูป

Create and share Visual Studio color schemes

อ่านเพิ่มเติม...

Wednesday, October 23

Emgu Convert Colour image to Gray,Binary Image

พอดีมีคนถามหาโค๊ด ซึ่งเป็นโค๊ดที่ผมเริ่มศึกษา Emgu ใหม่ๆ (ตอนนี้ ก็ยังใหม่อยู่เหมือนเดิม ;P ) ก็เลยเอามาอัพไว้ที่บล๊อกสักหน่อย

ไม่มีอะไรมากครับ เป็นการโหลด Image เข้ามา แล้วทำการแปลงเป็นภาพ Gray , Binary Image เฉยๆ

Emgu Convert Colour image to Gray,Binary Image

ไลบรารี่ที่ดึงเข้ามาใช้ในโปรเจค

Emgu Convert Colour image to Gray,Binary Image

อันนี้เป็นโค๊ด

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.IO;
using Emgu.CV;
using Emgu.CV.Structure;


namespace CovertImage
{
    public partial class Form1 : Form
    {
        string imageFileName;
        Image<Bgr, Byte> imageCoverted;
        public Form1()
        {
            InitializeComponent();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            string extension;
            OpenFileDialog openFile = new OpenFileDialog();
            openFile.Filter = "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*";
            openFile.FilterIndex = 1;
            openFile.RestoreDirectory = true;
            if (openFile.ShowDialog() == DialogResult.OK)
            {
                extension = Path.GetExtension(openFile.FileName);
                if (extension == ".jpg" | extension == ".gif" | extension == ".bmp")
                {
                    imageFileName = openFile.FileName;
                    Image<Bgr, byte> img = new Image<Bgr, byte>(openFile.FileName);
                    imageCoverted = new Image<Bgr, Byte>(openFile.FileName);
                    pictureBox1.Image = img.ToBitmap(pictureBox1.Width, pictureBox1.Height);
                    pictureBox2.Image = null;
                }
                else
                {
                    pictureBox1.Image = null;
                    pictureBox2.Image = null;
                    MessageBox.Show("File does not supported");
                }

            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            processImage(imageCoverted, 0);
        }

        private void button4_Click(object sender, EventArgs e)
        {
            processImage(imageCoverted, 1);
        }

        private void processImage(Image<Bgr,byte> img,int Mode)
        {
            switch (Mode)
            {
                case 0:
                    label2.Text = "Gray";
                    pictureBox2.Image = img.Convert<Gray, byte>().ToBitmap(pictureBox2.Width, pictureBox2.Height);
                    break;
                case 1:
                    label2.Text = "Binary";
                    pictureBox2.Image = img.Convert<Gray, Byte>().ThresholdBinary(new Gray(127), new Gray(255)).ToBitmap(pictureBox2.Width, pictureBox2.Height);
                    break;
            }

        }

        private void toolStripStatusLabel1_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://vs-visual-studio.blogspot.com/");
        }
    }
}

ดาวน์โหลดซอร์สโค๊ดและโปรเจค https://dl.dropboxusercontent.com/u/65353188/CovertImage.zip

อ่านเพิ่มเติม...

Saturday, October 19

Seven-segment LED Control for .NET

Seven-segment LED Control for .NET         บางที การแสดงผลตัวเลข แบบ 7-segment บน C# application form ก็ดูดีเหมือนกันนะ ยิ่งถ้าเรากำลังออกแบบหน้าต่างสำหรับงานควบคุม แสดงผล แล้วหล่ะก็ ดูดีเลยทีเดียว

        วันนี้ เรามาติดตั้้ง 7-Segment ลงบน C# win form กันนะครับ พอดี มีคนทำไว้แล้ว เราก็แค่ ดึงมาใช้งานเลย

เริ่มจากดาวน์โหลด ซอร์สโค๊ดมาก่อนครับ จาก CodeProject จากนั้นทำการแตกไฟล์ไว้ที่ไหนก็ได้ เราต้องการแค่ไฟล์ SevenSegment.cs และ ไฟล์ SevenSegmentArray.cs ของเขามาใส่ไว้ที่ toolbox ของเรา

ทีนี้ เรามาสร้างโปรเจคใหม่ บน C# ของเรา ให้เลือกเป็น windows form นะครับ เราจะได้ form เปล่าๆ ขึ้นมา  1 form  ยังไม่ต้องทำอะไร กับมันครับ ให้เราไปคลิกขวาที่ project ของเรา แล้วเลือก Add->Existing Items… แล้วก็เลือกไฟล์ SevenSegment.cs และ ไฟล์ SevenSegmentArray.cs  ที่ดาวน์โหลดมา เอามาไว้ที่โปรเจคของเรา

Seven-segment LED Control for .NET

จากนั้น ก็ไปที่เมนู Build—> Build Solution (F6) ไม่น่าจะมี Error อะไรเกิดขึ้น เพราะเรายังไม่ได้ Coding อะไรเลย น่าจะ success นะครับ จากนั้น ให้สังเกตที่ Toolbox ของเรา จะเกิดกลุ่ม Tab ใหม่ขึ้นมา ชื่อ SenvenSegTest Components

Seven-segment LED Control for .NET

เพียงแค่นี้ เราก็ได้ 7-segment มาไว้ใช้งานบนหน้าฟอร์มของเราแล้วครับ ที่เหลือ ก็แล้วแต่จะโปรแกรมมิ่ง กันเอาเองนะครับ ลองศึกษาดูวิธีการใช้งานจาก source code ที่ดาวน์โหลดมาแล้วกันครับ ไม่น่าจะยากเกินความสามารถกันนะครับ

อ่านเพิ่มเติม...

C# Random number

ปกติก็ใช้ไม่บ่อยนะ แต่เวลาจะใช้ทีไรลืมทุกที ปกติจะใช้เวลาทดสอบโปรแกรม ให้มันสุ่มตัวเลขขึ้นมา แล้วเอาไปแสดงที่หน้า control แต่ด้วยความที่มักจะลืม ก็เลยเขียนไว้ที่บล๊อกซะเลย ดูซิ มึงจะลืม อีกไหม  55555+

ประกาศตัวแปรไว้ใน class project ของเรา เป็นตัวแปร Random

Random num = new Random();

ทีนี้ พอเราจะนำมันไปใช้งาน ก็แค่ สั่งให้มันสุ่มตัวเลขมาให้เรา โดยจะมี 2 เมธอดที่สำคัญคือ

Next และ Double ( 2 ตัวนี้ ก็น่าจะเพียงพอแล้ว )

Random object C#

ถ้าเราต้องการให้มันสุ่มตัวเลขจำนวนเต็ม ตั้งแต่ 0 จนถึง System.Int32.MaxValue เช่น เราต้องการให้มีค่าตั้งแต่ 0 ถึง 1000 เราก็ใช้รูปแบบนี้  num.Next(1000)

หากต้องการสุ่มจำนวนเต็มตั้งแต่ 500 ถึง 1000 ก็ใช้รูปแบบนี้ num.Next(500,1000)

หากเราต้องการสุ่มเลยทศนิยม ก็ใช้ num.NextDouble() มันจะสุ่มตัวเลขระหว่าง 0.0 ถึง 1.0 ซึ่งเป็นตัวเลขชนิด Double

แล้วถ้าอยากได้ค่าอยู่ระหว่า่ง 0.0 ถึง 100.99 หล่ะ ง่ายๆ ก็แค่เอา

num.NextDouble() * 100  แค่นี้ เราก็จะได้ตัวเลขที่ถูกสุ่มมาระหว่าง 0.0 ถึง 1.0 แล้วคูณด้วย 100 

หวังว่า คงไม่ลืมแล้วหล่ะ เขียนเอง อ่านเอง แบบนี้

อ่านเพิ่มเติม...

Saturday, October 5

C# ติดต่อโลกภายนอกด้วย SerialPort Class

     ถึงแม้ว่าคอมพิวเตอร์จะพัฒนาไปไกล จนถึงระดับ 64 บิตแล้วก็ตาม สิ่งหนึ่งที่ยังเป็นที่นิยม ยังมีใช้อยู่ทั่วไปก็คือ พอร์ตอนุกรม โดยเฉพาะในโลก Embedded system แล้ว หากคุณต้องการที่จะรับส่งข้อมูลระหว่างอุปกรณ์ภายนอก และโปรแกรมภายในคอมพิวเตอร์แล้ว พอร์ตอนุกรม หรือ Serial Port ก็ยังเป็นที่นิยมอยู่ ด้วยความที่มันติดต่อกันในรูปแบบที่ไม่ซับซ้อน สามารถเข้าใจได้ง่าย ช่วยให้งานจบได้เร็ว จึงทำให้ทุกวันนี้ เรายังพบเห็นโปรแกรมที่รับส่งข้อมูลทางพอร์ตอนุกรมอยู่ ถึงแม้่ว่าคอมพิวเตอร์บางเครื่องจะไม่มีพอร์ตอนุกรมแล้วก็ตาม เราก็ยังสามารถที่จะใช้ตัวแปลง USB to Serial ทำงานได้เหมือนๆ กัน

C# ติดต่อโลกภายนอกด้วย  SerialPort Class

วันนี้เรามาเขียนโปรแกรมรับส่งข้อมูลทางพอร์ตอนุกรมกันครับ โดยผมจะเขียน application เพื่อรับส่งข้อมูลระหว่างคอมพิวเตอร์ กับ ไมโครคอนโทรลเลอร์ผ่านทาง Serial Port โดยมีเงือนไขดังนี้

MCU ทำการส่งข้อมูลออกไป โดยมีรูปแบบดังนี้  #ADC1,ADC2,ADC3* โดยเราให้

  • # แสดงการเริ่มต้นส่งข้อมูล
  • ADCx ค่าอนาล๊อกที่อ่านได้จากช่อง Analog input ของ MCU มีค่าอยู่ระหว่าง 0-1023
  • * แสดงจุดสิ้นสุดข้อมูล

ซึ่ง Visual C# จะรับข้อมูลแล้วไปประมวลผลตามที่เราออกแบบไว้ จากนั้น Visual C# สามารถส่งข้อมูลออกไปหาที่ตัว MCU ได้ด้วยรูปแบบดังนี้ #Button1,Button2,Button3* โดยเราให้

  • # แสดงการเริ่มต้นส่งข้อมูล
  • Buttonx แสดงค่าสถานะการกดปุ่ม  0:ปุ่มไม่ถูกกด,  1:ปุ่มถูกกด 
  • * แสดงจุดสิ้นสุดข้อมูล

ผมออกแบบหน้าต่างฟอร์มแบบนี้ครับ

C# ติดต่อโลกภายนอกด้วย  SerialPort Class

ในส่วนของโค๊ด

เริ่มจากเราต้อง using System.IO.Ports; เพื่อจะสร้างออปเจค serial port จาก class SerialPort เมื่อเราได้ using เข้ามาแล้ว เราจึงสามารถทีจะสร้างออปเจคได้

serial = new SerialPort(comportComboBox.SelectedItem.ToString(), 9600, Parity.None, 8, StopBits.One);

เราทำการเพิ่ม event handler ให้กับออปเจค เพื่อจะแยกโค๊ดไปเขียนการรับค่าทาง serial port

serial.DataReceived += new SerialDataReceivedEventHandler(serial_DataReceived); // พิมพ์ serial.DataReceived += แล้่วกด Tab 2 ครั้ง โปรแกรม Visual C# ide เขาจะสร้าง method serial_DataReceived  ให้อัตโนมัติ

แล้วผมก็เขียนโค๊ดจัดการการรับข้อมูลใน event handler นี้

void serial_DataReceived(object sender, SerialDataReceivedEventArgs e)

        {

            string d = serial.ReadLine();

            int intBegin = d.IndexOf("#");

            int intEnd = d.IndexOf("*");

            int length = intEnd - (intBegin+1);

            char[] ch = { ','};

            raw = d;

            data = d.Substring(intBegin + 1, length).Split(ch);

            this.BeginInvoke(new updateAnalogLabel(updateLabel));

        }

ส่วนการอัพเดทตัวเลขที่ได้รับมาไปที่ control ต่างๆบนฟอร์มนั้น เราต้องอาศัย delegate พังก์ชั่นจัดการในส่วนนี้ เพราะในระหว่างที่รับข้อมูลอยู๋นั้น มันไม่มีส่วนไหนของโปรแกรมไปอัพเดทข้อมูลบนฟอร์มเลย เราจึงต้องพึง delegate เพื่อทำ callback ฟังก์ชั่น

private delegate void updateAnalogLabel();

        private void updateLabel()

        {

            analog1Label.Text = data[0];

            analog2Label.Text = data[1];

            analog3Label.Text = data[2];

            serialRecieveTextBox.AppendText(raw);

        }

ในส่วนของการส่งข้อมูลออกจากโปรแกรมไปทาง serial port ที่เราได้ตกลงกันไว้คือ โปรแกรม C# จะทำการส่งสถานะการกดปุ่มบนฟอร์ม เพื่อไปบอกให้ MCU ขับหลอด LED 

private void sendStateButton()

        {

            string s = "#" + Convert.ToInt32(stateButton1).ToString() + "," + Convert.ToInt32(stateButton2).ToString() + "," + Convert.ToInt32(stateButton3).ToString() + "*";

            if (serial != null)

            {

                if (serial.IsOpen)

                {

                    serial.Write(s);

                }

            }

        }

ผมอัพไว้ที่ dropboxแล้ว

https://dl.dropboxusercontent.com/u/65353188/easySerial2013.zip

อ้างอิง : SerialPort Class  , Delegates Tutorial

หรืออ่านเต็มๆ ได้ที่นี่ครับ คลิก

อ่านเพิ่มเติม...

Thursday, September 26

Properties.Settings.Default.Save(); จำค่าไว้ก่อนปิด

พอดีมีคนถามมา ก็เลยลองหาดูในเนต ก็เจอว่ามีวิธีการเก็บบันทึกค่าต่างๆ ที่เรากรอกทิ้งไว้ในฟอร์ม ก่อนปิดหน้าต่างโปรแกรม แล้ว สามารถเรียกกลับมาคืนได้ ผมเคยคิดว่าจะเก็บลง Registry ของ windows (ซึ่งไม่น่าจะง่าย) แต่ มาเจอวิธีที่ง่ายกว่านั้นอีก เรามาดูกันเลย

เริ่มแรกก็สร้างฟอร์มง่ายๆ ก่อน ให้มีแค่ Textbox อันเดียวก็พอ

จากนั้นคลิกขวาที่โปรเจคของเรา ในหน้าต่าง Solution Explorer แล้วเลือก Properties เลือกที่ Tab setting และทำการกรอกค่าตามรูป

simple form

------+-------+-------
Name          Type         Scope
------+-------+-------
text             string       User
x                  int           User
y                   int          User

Properties Settings

ในที่นี้ เราจะให้ text เก็บค่าใน textbox ที่เคยพิมพ์ไว้ ส่วน x และ y จะเก็บค่าตำแหน่ง form ก่อนปิดหน้าต่างโปรแกรม เมื่อกำหนดเรียบร้อยแล้วให้ทำการบันทึกไฟล์ไว้ก่อน

จากนั้นทำการกำหนดและเขียนโค๊ดดังนี้

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace persistingForm
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.StartPosition = FormStartPosition.Manual;
        }

        private void textBox1_KeyUp(object sender, KeyEventArgs e)
        {
            Properties.Settings.Default.text = textBox1.Text; // เก็บค่าสตริงจาก textbox1 ลงใน properties text
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Properties.Settings.Default.x = this.Location.X;
            Properties.Settings.Default.y = this.Location.Y;
            Properties.Settings.Default.Save(); // อย่าลืมสั่ง save ก่อนปิดโปรแกรม
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.Location = new Point(Properties.Settings.Default.x, Properties.Settings.Default.y);
            textBox1.Text = Properties.Settings.Default.text;
        }
    }
}

ลองรันโปรแกรม ดูครับ แล้วลองเปรียบเทียบกับโปรแกรมก่อนๆ หน้านี้ดูครับ จะเห็นว่า โปรแกรมนี้ที่เราเขียนขึ้น จะมีการจดจำค่าก่อนปิดโปรแกรมตามที่เรากำหนดไว้ในโค๊ด  ลองเอาไปประยุกต์ดูครับ

ขอให้สนุกกับ .NET ครับ

อ้างอิง:  http://msdn.microsoft.com/en-us/library/aa730869(v=vs.80).aspx

อ่านเพิ่มเติม...

Saturday, September 14

List video devices from PC by DirectShowLib

ในกรณีที่เราอยากทำให้ Application ของเราสามารถเลือกได้ว่าจะติดต่อกับกล้องตัวใน ถ้าเครื่องคอมพิวเตอร์ของเรามีมากกว่า 2 ตัว เราจะทำอย่างไร ถึงจะทำให้ application ที่เรากำลังสร้างนั้นมองเห็นกล้องทั้งหมดในเครื่องคอมพิวเตอร์เครื่องนั้นได้

วันนี้ผมจะแนะนำความสามารถของ Library ตัวหนึ่งชื่อ DirectShowLib ที่เอาไว้ดึงรายชื่อกล้องทั้งหมดที่ต่ออยู่ในเครื่องคอมพิวเตอร์ของเราออกมาเป็นตัวแปร array จากนั้นเราก็สามารถที่จะใช้ ComboBox ใช้แสดงรายชื่อกล้องทั้งหมด ไว้ให้ user เอาไว้เลือกต่อได้ ว่าจะติดต่อกับกล้องตัวไหน

อันดับแรก ก็ให้ไปดาวน์โหลด Library ตัวนี้ก่อนครับ อยู่ใน sourceforge ก็มี ดาวน์โหลดได้ที่นี่ http://sourceforge.net/projects/directshownet/files/ เมื่อดาวน์โหลดมาได้แล้ว เราต้องการไฟล์ DirectShowLib-2005.dll ที่อยู่ในโฟลเดอร์ \DirectShowLibV2-1\lib ของมัน

เรามาเริ่มสร้างโปรเจคกัน ในที่นี้ผมให้เป็น Windows Forms Application ที่เมนู Project เลือก Add reference หรือคลิกขวาที่ References ที่ ใต้ชื่อ Project เราที่ solution explorer ทำการ Browse หาไฟล์  DirectShowLib-2005.dll

image

สร้างหน้าต่าง form ตามรูป แล้วทำการเขียนโค๊ด (อันนี้ผมไม่บอกละเอียดแล้วนะ ถือว่า พอมีประสบการณ์กันบ้างหล่ะ)

image

เรามาดูที่โค๊ดกันครับ หัวใจของเรื่องนี้ ก็อยู่ตรงที่ เราสร้างตัวแปร object จาก Class DsDevice ที่อยู่ใน namespace ของ DirectShowLib (ฉะนั้นอย่าลืมที่ using DirectShowLib; ด้วยนะครับ)

ผมประกาศตัวแปร DsDevice[] videoDevices; ก่อน

จากนั้น ผมก็ทำการสร้างอินสแตนซ์จาก Class DsDevice แล้วก็เอามาวนลูปแสดงใน ComboBox


videoDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
if (videoDevices.Length == 0)
{
     throw new Exception();
}

for (int i = 1, n = videoDevices.Length; i <= n; i++)
{
     string cameraName = i + " : " + videoDevices[i - 1].Name;
     cameraCombo.Items.Add(cameraName);
}
cameraCombo.SelectedIndex = 0;

ทีเหลือก็ไม่มีอะไรมาก เอา index ที่ได้จากการเลือก combobox สร้างอินสแตนซ์ Capture แล้วก็โยนให้ picturebox แสดงผล

ลองดูโค๊ดเต็มๆ

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using Emgu.CV;
using Emgu.Util;
using Emgu.CV.Structure;

using DirectShowLib;

namespace AnyCameras
{
    public partial class Form1 : Form
    {
        DsDevice[] videoDevices;
        private Capture capture = null;

        public Form1()
        {
            InitializeComponent();
            timer.Interval = 100;

            // show device list
            try
            {
                videoDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
                if (videoDevices.Length == 0)
                {
                    throw new Exception();
                }

                for (int i = 1, n = videoDevices.Length; i <= n; i++)
                {
                    string cameraName = i + " : " + videoDevices[i - 1].Name;
                    cameraCombo.Items.Add(cameraName);
                }
                cameraCombo.SelectedIndex = 0;
            }
            catch
            {
                cameraCombo.Items.Clear();
                cameraCombo.Items.Add("No cameras found");
                cameraCombo.SelectedIndex = 0;
                cameraCombo.Enabled = false;
            }       
       
        }

        private void StartCamera()
        {
            capture = new Capture(cameraCombo.SelectedIndex);
            timer.Start();
        }

        private void StopCamera()
        {
            timer.Stop();
            if (capture != null)
            {
                capture.Dispose();
            }
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            Image<Bgr, Byte> frame = capture.QueryFrame();
            cameraPictureBox.Image = frame.ToBitmap();
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            StartCamera();
            startButton.Enabled = false;
            stopButton.Enabled = true;
        }

        private void stopButton_Click(object sender, EventArgs e)
        {
            StopCamera();
            startButton.Enabled = true;
            stopButton.Enabled = false;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            timer.Stop();
            if (capture != null)
            {
                capture.Dispose();
            }
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            System.Diagnostics.Process.Start("http://vs-visual-studio.blogspot.com/");
        }

    }
}

 

ลองดาวน์โหลดโค๊ดไปเล่นกันครับ https://dl.dropboxusercontent.com/u/65353188/AnyCameras.zip

อ่านเพิ่มเติม...

Thursday, September 12

AdvancedHMI with Visual C# 2010

HMI หรือ Human Machine Interface คือ อุปกรณ์ที่ใช้ในการติดต่อระหว่่างผู้ใช้ กับ เครื่องจักร เพื่อใช้ในการควบคุมและการแสดงผล ผ่านทางหน้าจอ เรามักใช้ในการแสดงผลแบบกราฟฟิก ซึ่งส่วนใหญ่ จะแสดงผลในเชิงสัญลักษณ์ หรือไอค่อนที่เป็นตัวแทน เครื่องจักร ถังน้ำ ปั้ม วาล์วน้ำ มอเตอร์ไฟฟ้า และอื่นๆ ที่เป็นส่วนที่เราต้องการติดตามการทำงานของพวกมัน โดยจะแสดงสถานะ ค่าต่างๆ บนหน้าจอแสดงผล พร้อมกับโครงสร้างของระบบการทำงานที่เรายกมาแสดง
ในปัจจุบันมีโปรแกรมหลายๆ ค่ายที่สามารถแสดงผลแบบ HMI ได้ ซึ่งมีทั้งแบบที่ง่าย แต่เสียเงิน และแบบที่ยาก แต่ ฟรี ก็มี วันนี้ เรามาลองติดตั้ง AdvancedHMI กับ C# กันดูครับ
AdvancedHMI
เริ่มแรกก็ไปดาวน์โหลด AdvancedHMI จากที่นี่ http://advancedhmi.com/ จากนั้น ทำการแตกไฟล์ออก ไปวางไว้ที่ไหนก็ได้ครับ เพราะเราจะสนใจแค่ dll ไฟล์ของมัน
เปิดโปรแกรม Visual C# 2010 express ขึ้นมาครับ เริ่มสร้างโปรเจค ตามปกติ ในที่นี้ผมสร้างโปรเจคเป็น windows form application นะครับ
ต่อมาให้เราทำการ add toolbox ที่เป็นของ AdvancedHMI ขึ้นมา  อาจจะสร้าง Add tab ขึ้นมาแล้วตั้งชื่อ AdvancedHMI แล้วคลิกขวา Choose items.. ไปที่
Add components AdvancedHMI
แท๊ป .NET Framework Components ให้เรา Browse ไปที่เก็บไฟล์  AdvancedHMIBeta358\AdvancedHMIDrivers\Support\MfgControl.AdvancedHMI.Drivers.dll แล้วคลิกเลือก OK
AdvancedHMI components
เราจะได้ Components ที่ทาง AdvancedHMI สร้างมาให้
ทำการ Add reference MfgControl.AdvancedHMI.Drivers.dll เข้าไปกับโปรเจคด้วย
Add reference MfgControl.AdvancedHMI.Controls.dll
จากนั้น ก็ลาากวางๆ ได้เลยครับ จินตนาการเอาว่า เราจะสร้างระบบเฝ้าติดตามอะไร ในที่นี้ ผมสร้างระบบปั้มน้ำ โดยให้มอเตอร์ปั้มน้ำเข้าถัง หากระดับน้ำต่ำกว่า ระดับที่เราตั้งไว้ และมีวาล์วคอยปิดเปิดทางน้ำออก ซึ่งสามารถปรับอัตราการไหลได้
AdvancedHMI Form design
ที่ส่วนหัวของโค๊ด ให้ทำการ using MfgControl.AdvancedHMI.Controls; เข้าไปด้วย ถ้าต้องการสร้าง object เพิ่ม
ในการเขียนโค๊ดส่งค่าให้แต่ละ Component ไม่ว่าจะเป็น Guage , Tank  หรืออะไรก็ตามแต่ ที่มีการแสดงผล แสดงค่าต่างๆ ต้องเช็คให้ดีด้วย ว่ามันรับค่าเป็น float , int หรือว่า double ถ้าเราส่งค่าให้มันไม่ตรงชนิดที่มันจะรับ มันจะแสดงผลผิดพลาด ลองเอา mouse ชี้ค้างไว้ตอนเรา กำหนดค่า ให้ field ที่ชื่อ value ของมันดูครับ มันจะบอกไว้อยู่
image
AdvancedHMI object
ในที่นี้ ผมใช้ Timer 3 ตัวในการกำหนดจังหวะให้กับระบบ มาดูโค๊ดเต็มๆ กันเลยครับ
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MfgControl.AdvancedHMI.Controls;
namespace AdvanceHMI
{
    public partial class Form1 : Form
    {
        Random rnd = new Random();
        float waterActual = 100.0f;
        float flowrateIn = 2.0f;
        float flowrateOut = 2.0f;
       
        public Form1()
        {
            InitializeComponent();
            tank1.Value = waterActual;
            waterPump1.Value = false;
            txtWaterDetect.Text = "70";
            trackBar1.Value = 70;
            lbWaterLevel.Text = ((int)waterActual).ToString();
        }
        private void btnStart_Click(object sender, EventArgs e)
        {
            timer1.Enabled = true; // timer system
            timer2.Enabled = true; // timer water flow rate in
            timer3.Enabled = true; // timer water flow rate out
            timer1.Interval = 200;
            timer2.Interval = 200;
            timer3.Interval = 500;
            timer1.Start();
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            lbWaterLevel.Text = waterActual.ToString();
            if ((int)waterActual <100)
            {
                if ((int)waterActual <= trackBar1.Value)
                {
                    timer2.Start();
                    waterPump1.Value = true;
                }
               
            }
            else
            {
                timer2.Stop();
                waterPump1.Value = false;
            }
            if (pneumaticBallVave1.Value == true)
            {
                timer3.Start();
                pneumaticBallVave1.Value = true;
            }
            else
            {
                timer3.Stop();
                pneumaticBallVave1.Value = false;
            }
        }
        private void btnStop_Click(object sender, EventArgs e)
        {
            timer1.Stop();
            timer2.Stop();
            timer3.Stop();
        }
        private void label1_Click(object sender, EventArgs e)
        {
        }
        private void timer3_Tick(object sender, EventArgs e)
        {
           
            waterActual = waterActual - flowrateOut;
            tank1.Value = waterActual;
        }
        private void timer2_Tick(object sender, EventArgs e)
        {
            waterActual = waterActual + flowrateIn;
            tank1.Value = waterActual;
        }
        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            txtWaterDetect.Text = trackBar1.Value.ToString();
        }
        private void button1_Click(object sender, EventArgs e)
        {
        }
        private void pneumaticBallVave1_DoubleClick(object sender, EventArgs e)
        {
           
        }
        private void trackBar2_Scroll(object sender, EventArgs e)
        {
            flowrateOut = (float)trackBar2.Value;
            label3.Text = trackBar2.Value.ToString();
        }
        private void pneumaticBallVave1_Click(object sender, EventArgs e)
        {
            pneumaticBallVave1.Value = !pneumaticBallVave1.Value;
        }
    }
}
ลองโหลดไฟล์ไปเปิดกันดูครับ ไม่รู้ว่าจะเปิดกันได้หรือเปล่า ถ้าไม่ได้ก็สร้างเอาใหม่ ก็แล้วกันครับ แลบลิ้น
https://dl.dropboxusercontent.com/u/65353188/AdvanceHMI.zip
อ่านเพิ่มเติม...

Saturday, April 13

How to use ImageBox control

ImageBox คือ เครื่องมือในการสร้างพื้นที่การแสดงภาพ คล้ายๆ กับ PictureBox แต่ ต่างกันตรงที่ ImageBox นั้นมีฟังก์ชั่นเพิ่มเติมในการจัดการรูปภาพติดมาด้วย นอกจากนี้ เรายังสามารถกำหนดให้ ImageBox มีคุณสมบัติเทียบเท่า หรือมากกว่า PictureBox ได้เช่นกัน  ซึ่งนับว่ายืดหยุ่นกว่า PictureBox แบบเก่าๆ

แต่ ก่อนที่เราจะเรียกใช้ ImageBox ได้ เราจะต้องทำการเพิ่ม Control ตัวนี้เข้ามาในหน้าต่างของ Visual C# ซะก่อน ทำตามขั้นตอนดังนี้

คลิกขวา เลือก Choose Items.... ที่บริเวณพื้นที่ว่างของ หน้าต่าง Toolbox

Toolbox

ะปรากฏหน้าต่าง Choose Toolbox Items ให้ทำการคลิก Browse แล้วเลือกไฟล์ 'Emgu.CV.UI.dll' จาก C:\Emgu\emgucv-windows-x86-gpu 2.4.2.1777\bin หรือที่เราติดตั้ง emgu ไว้

จากนั้น เลื่อนหา ImageBox เมื่อเจอแล้ว ให้ทำการเช็คบอกซ์ แล้วกด OK

Choose Toolbox Items

กลับมาที่ Toolbox จะปรากฏ ImageBox control ขึ้นมา ให้ลากมาวางบนพื้นที่ว่างบนฟอร์ม ปรับแต่งขนาดให้เหมาะสม ทดสอบรันโปรแกรม

ImageBox control

นอกจากนี้ เราสามารถกำหนดคุณสมบัติของ ImageBox ได้ด้วย ในระหว่างการพัฒนา และการปล่อยซอร์ฟแวร์ให้ลูกค้าใช้ เราอาจะเปิดฟังก์ชั่นบางอย่างเท่านั้น  ด้วยการใช้ preprocessor กำหนดค่า เช่น

#if DEBUG
imageBox1.FunctionalMode = ImageBox.FunctionalModeOption.Everything;
#else
imageBox1.FunctionalMode = ImageBox.FunctionalModeOption.PanAndZoom;
#endif

ถ้าเราไม่ได้อยู่ในโหมด Debug ให้ ImageBox มีแค่ ฟังก์ชั่นการ ซูม เท่านั้น 

ลองนำไปประยุกต์กันดูนะัครับ ขอให้สนุกกับ Emgu

อ้างอิง http://www.emgu.com/wiki/index.php/ImageBox

อ่านเพิ่มเติม...

Sunday, April 7

How to implement property sheet to other project in Visual C++

เราสามารถก๊อปปี้ค่าต่างๆ ใน Project Properities จากงานที่เราเคยกำหนดค่าไว้แล้ว มาใช้ใน Project ใหม่ได้ จะทำให้เราสามารถที่จะสร้างโปรเจคได้เลย โดยไม่ต้องไปกำหนดที่ Project Properties ทุกครั้งที่เราสร้างโปรเจคใหม่

เช่นงาน HelloOpenCV ที่เราได้กำหนด Project Properties path การเรียกใช้ library และการดึงไฟล์ dll เข้ามาร่วมในโปรเจคของเรา หากเรามีการสร้างไฟล์ Property sheet ไว้ก่อนแล้ว เราสามารถ add property sheet เข้ามาในโปรเจคใหม่ของเราได้เลย ซึ่งจะทำให้ path ต่างๆ ที่เคยกำหนดไว้ที่ C/C++ และ Linker ถูกกำหนดไว้อย่างเรียบร้อย ช่วยลดเวลาความยุ่งยากในการสร้างโปรเจคบน Visual C++ ได้เป็นอย่างดี เรามาดูกันครับว่าทำอย่างไร


ก่อนอื่น เราจะต้องสร้างไฟล์ properity sheet ขึ้นมาก่อน โดยจะอยู่ที่ tab property manager ซึ่งบางเครื่อง อาจจะยังไม่ปรากฏ tab นี้ ให้เราไปที่เมนู Tools->Settings->Expert Settings จะปรากฏ tab property manager ด้านล่าง

open tab property manager

 

Property manager tab bar

ในวีดีโอ ผมได้ทำการสร้างไฟล์ properity sheet โดยอาศัยจากโปรเจค HelloOpenCV ก่อน โดยให้เก็บไฟล์ OpenCVPropertiesDebug.props และไฟล์ OpenCVPropertiesRelease.props ไว้แยกต่างหาก จากโฟวเดอร์โปรเจคเรา จากนั้นกำหนดค่า ตามที่เราเคยได้กำหนดจากตัวอย่างก่อนหน้านี้  เรียบร้อยแล้วให้ทำการบันทึกไฟล์ทั้งสอง

ต่อจากนั้น เมื่อเราทำการ add new project เข้าไปใน  project solution ของเราให้ทำการไปเพิ่มไฟล์ property sheet เข้าไปที่ debug และ release ใน tab property manager ในโปรเจคที่เราสร้างใหม่

เมื่อเรามาทำการเขียนโค๊ด C++ ตอนที่เราสั่ง #include <cv.h> สังเกตได้ว่า Visual C++ IDE จะมองหา path ตามที่เราได้เพิ่มไฟล์ property sheet ตามที่เราได้กำหนดไว้ให้อัตโนมัติ

ง่ายไหมหล่ะครับ ทีนี้เวลาเราสร้างโปรเจคใหม่ขึ้นมา เราก็สามารถเพิ่มไฟล์ property sheet เข้าไป ทีเหลือ ก็ไม่ต้องไปกำหนดค่าอะไรให้วุ่นวายอีก จากนั้นก็บรรเลงเพลงโค๊ด C++ เราได้เลย

ขอให้สนุกกับ OpenCV นะครับ

อ่านเพิ่มเติม...

Saturday, March 30

Getting started Emgu with Visual C# 2010 Express

ถ้าหากเรามองว่า OpenCV คือ ไลบรารี่สำเร็จรูปที่ใช้สำหรับจัดการงานด้าน Computer Vision ซึ่งรองรับภาษา C/C++,JAVA,Python แล้วหล่ะก็ Emgu ก็คือฟังก์ชั่นที่ทำขึ้นมาครอบ OpenCV อีกชั้นหนึ่ง แต่ ทำขึ้นมาเพื่อรองรับภาษา Visual C# นั่นเอง  ซึ่งทำให้นักพัฒนาด้วยภาษา Visual C# สามารถก้าวเข้ามาเล่น Computer Vision ได้อย่างง่ายดาย

วันนี้ผมจะพาเพื่อนๆ มาติดตั้ง Emgu กันครับ เริ่มแรก เราต้องเตรียมซอร์ฟแวร์ที่จะติดตั้งกันก่อน โดยอ้างอิงจากที่ผมติดตั้งไว้แล้ว ดังนี้

ระบบปฏิบัติการ Windows7
Visual C# 2010 Express edition หากยังไม่มี ติดตั้งโปรแกรนี้ก่อน ได้จาก ที่นี่
ดาวน์โหลด Emgucv2.4.2 libemgucv-windows-x86-gpu-2.4.2.1777.exe ได้จาก ที่นี่
เมื่อได้ไฟล์ libemgucv-windows-x86-gpu-2.4.2.1777.exe ให้ทำการติดตั้งไว้ที่ Dirve C: เลยครับ

หรือจะไว้ที่ Drive ก็ได้ แล้วแต่สะดวก ในระหว่างการติดตั้ง ถ้ามีปัญหา เช่น

- Uninstall or Repair Microsoft C++ Redistributable ให้ตอบ Cancel
หรือ
- Visual Studio Debugger ถ้าเรายังไม่เคยติดตั้ง Emgu มาก่อน ใหคลิก Yes แต่ถ้าเคยติดตั้งมาแล้วให้คลิก No

Emgucv1Emgucv2Emgucv3Emgucv4Emgucv5

เมื่อเสร็จเรียบร้อยแล้ว เราต้ิองมาทำการ set path ให้ Windows มองหา Emgu ก่อน เพื่อป้องกันปัญหาต่างๆ ในการ Build solution โดยไปตั้งค่าที่

Control Panel->System->Advance system setting ที่แท๊บ Advanced คลิก

Environment Variables ที่ System Variables คลิกที่ Path แล้ว Edit..
ให้เอา path ที่เราติดตั้ง Emgu ไปใส่ต่อท้าย ในที่นี้ผมติดตั้งไว้ที่ C:\Emgu\emgucv-windows-x86-gpu2.4.2.1777\bin ผมก็ก๊อปปี้ไปต่อท้าย โดยคั่นด้วย ; ก่อน และหลัง path ที่ผมใส่เพิ่มเข้าไป จากนั้นกด OK เรื่อยๆ แล้วทำการรีสตาร์ทคอมพิวเตอร์ 1 ครั้ง

image

ต่อไป ให้ทำการ เปิด Visual C# ขึ้นมา แล้วทำการ New Project โดยเราจะสร้างโปรเจค แบบ  ตั้งชื่อโปรเคตามต้องการ จากนั้น สร้างหน้าตา form ดังรูป

image

กำหนดค่า text properties ให้ button1 และ button2 เป็น Image-1, Image-2 ตามลำดับ
กำหนดค่า text properties ให้ form1 เป็น  Hello Emgu
ส่วน PictureBox1 กำหนดให้มี Size เท่ากับ 400,300

Emgu Visual C# 2010 express

เสร็จแล้ว ที่หน้าต่าง Solution Explorer ทางขวามือ ที่ References ให้คลิกขวา แล้วทำการเลือก Add references..

ให้ทำการ add *.dll จากโฟวเดอร์ C:\Emgu\emgucv-windows-x86-gpu 2.4.2.1777\bin โดย

คลิก Ctrl ค้างไว้ แล้วคลิกที่ไฟล์ แต่ละไฟล์  แล้วกด OK

Add Reference_

จากนั้น กลับมาที่หน้า form design ของเรา ให้ดับเบิลคลิกที่ button1 เพื่อทำการเขียนโค๊ด โปรแกรมจะพาเราเข้ามาเขียนโค๊ดที่หน้า Form1.cs ให้เพิ่มโค๊ดเข้าไปดังรูป (เราทำการคลิกที่ button2 แล้วก็เพิ่มโค๊ดเข้าไปเช่นเดียวกัน กับครั้งแรก)

ก่อนที่เราจะรันโปรแกรมของเรา ให้เราทำการเตรียมภาพ ไว้ สองภาพ ในทีนี้ ผมได้เตรียมภาพที่ชื่อ linux.jpg และ windows.jpg เก็บไว้ที่ Drive E: ของผม (สังเกตจากในโค๊ด) โดยผมค้นหาภาพจาก อินเตอร์เนต โดยหาภาพที่มีขนาด 400x300 pixel ให้เท่ากับ size ของ picturebox ทีผมกำหนดไว้ตอนแรก

เมื่อเรียบร้อยแล้ว ให้กด F6 เพื่อ Build Solution หากไม่มีข้อความแสดง Error ใดๆ ให้กด F5 เพื่อ Start Debugging

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;

namespace HelloEmgu
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Image<Bgr, Byte> img = new Image<Bgr, byte>("E:\\linux.jpg");
            pictureBox1.Image = img.ToBitmap(pictureBox1.Width, pictureBox1.Height);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Image<Bgr, byte> img = new Image<Bgr, byte>("E:\\windows.jpg");
            pictureBox1.Image = img.ToBitmap(pictureBox1.Width, pictureBox1.Height);
        }
    }
}

HelloEmgu - Microsoft Visual C# 2010 Express

ทดลองกด Image-1 และ Image-2 ดูผลลัพธ์ครับ ถ้าโปรแกรมที่เราเขียนขึ้น แสดงภาพได้ตามต้องการ ก็แสดงความยินดีด้วยครับ และขอให้สนุกกับ Emgu นะครับ

 

----------------------------------------------------------------------------------------------------------------

แก้ปัญหา “The type initializer for 'Emgu.CV.CvInvoke' threw an exception.”

The type initializer for 'Emgu.CV.CvInvoke' threw an exception.

เนื่องจากเกิดปัญหาเครื่องผมถูกอัพเกรดให้เป็น WIndows7 64 บิต อย่างเต็มตัว ซึ่งก่อนหน้าถูกอัพเกรดโค๊ดเหล่านี้ยังทำงานได้เป็นปรกติ แต่พอมาเป็น WIndows7 64 บิต กลับพบว่า ไม่สามารถทำงานได้ ฉะนั้นจึงต้องมาการเปลี่ยนแปลงดังนี้

1. ใ้ห้ทำการติดตั้ง libemgucv-windows-x86-2.4.0.1717.exe ดาวน์โหลดจาก ที่นี่ ติดตั้งเหมือนเดิม แต่อาจไม่จำเป็นต้องเป็น Drive C: แล้ว เพราะเราจะใช้การก๊อปปี้ไฟล์ dll มาใส่ในโปรเจคเลย

2. ติดตั้งเสร็จแล้ว ให้ทำการแก้ไขโค๊ด โดยทำการ Add references ใหม่ (reference เก่าให้ delete ทิ้งไป) โดยให้ browse ไปที่ path ที่เราติดตั้ง Emgu เวอร์ชั่น 2.4.0 แทน ในที่นี้ผม browse ไำปที่ E:\Emgu\emgucv-windows-x86 2.4.0.1717\bin แล้วเลือกไฟล์ Emgu.CV.dll,Emgu.CV.GPU.dll, Emgu.CV.ML.dll, Emgu.CV.UI.dll, Emgu.Util.dll

3. ทำการ add file dll อื่นมาเลย ในที่นี้เราต้องทำการเลือก Add Existing items..  แล้วเลือกเอาไฟล์ dll เข้ามาในโปรเจค 2 ไฟล์ คือไฟล์ opencv_core240.dll, opencv_imgproc240.dll ซึ่งอยู่ใน E:\Emgu\emgucv-windows-x86 2.4.0.1717\bin\x86 ที่หน้าต่าง properties ช่อง Copy to output directory ให้เลือก copy always

แล้วลองกด F5 (Start debugging) อีกครั้ง

-----------------------------------------------------------------------

แก้ไข 18/07/2014

เจอปัญหาเก่าอีกครั้ง ตอนนี้เปลี่ยนเครื่องคอมพ์ กับ windows 7 64bit ไม่แน่ใจว่าเกิดอะไรขึ้นเหมือนกัน ปัญหาเยอะจริงๆ เวลาเปลี่ยนเวอร์ชั่นเนี้ย เท่าๆ ที่อ่านดูคล้ายๆ กับว่าตอนที่ make file มาให้เรา มีปัญหาเรื่อง dirver card vga ไม่รองรับกับเครื่องอื่นๆ ก็รอเขาแก้ปัญหากันต่อไป ตอนนี้ ก็โหลดเวอร์ชั่นเบต้า มาใช้ก่อน เป็นเวอร์ชั่นที่ใช้กับ driver card vga ได้ทุกรุ่น Download libemgucv-windows-universal-cuda-2.9.0.1922-beta.exe (214.0 MB) หลังจากติดตั้งแล้ว ให้ทำการแก้ไข path ใหม่ ใน

Control Panel->System->Advance system setting ที่แท๊บ Advanced คลิก

เพิ่ม path นี้เข้าไป (สำหรับ windows7 64 bit)

C:\Emgu\emgucv-windows-universal-cuda 2.9.0.1922\bin\x64

แล้วทำการ รีสตาร์ทเครื่องคอมพ์ หนึ่งครั้ง จากนั้นก็ทำการสร้างโปรเจคใน Visual C# เหมือนเดิม ทำการ add referrence เอาเฉาพะ EMGU.CV.dll, EMGU.CV.UI.dll, Emgu.Util.dll ซึ่งอยู่ใน

C:\Emgu\emgucv-windows-universal-cuda 2.9.0.1922\bin\

ที่เหลือไม่ต้องทำอะไรเหมือนคราวที่แล้ว เพราะเราได้กำหนด path ไว้แล้ว ทำการเขียนโค๊ดทดสอบ  อ่อ อย่าลืมเลือก solution platforms ให้เป็น x64 ด้วยหล่ะ ให้ตรงกับที่เราอ้าง path

"The type initializer for 'Emgu.CV.CvInvoke' threw an exception."

"The type initializer for 'Emgu.CV.CvInvoke' threw an exception."

เป็นวิธีแก้ปัญหาที่ง่ายดี ก็ได้หวังว่าผู้พัฒนา EMGU จะทำให้ง่ายกว่านี้ และ bug น้อยลงไปเรื่อยๆ นะครับ เอาหล่ะ ขอให้สนุกกับ EMGU กันต่อ

อ่านเพิ่มเติม...

Thursday, March 28

How to implement system variables on Visual C++ Project

วันนี้ จะมาแนะนำการสร้างตัวแปร system variables เพื่อนำตัวแปรนี้ไปอ้างอิงในการกำหนดค่า path ใน Project ของ Visual C++ ครับ จากครั้งที่แล้ว เราได้สร้างโปรเจค HelloOpenCV กันไปแล้ว จะเห็นได้ว่า กว่าจะกำหนดค่าต่างๆ ให้กับโปรเจคนั้น ค่อนข้างมีรายละเอียดยุบยิบ เต็มไปหมด (นี่ยังไม่รวมถึงขั้นตอนเขียนโปรแกรมนะ) ทีนี้ เราจะมาลองใช้ลูกเล่น system variables ใน  Environment variables ใน windows กันดูครับ

เริ่มจากเปิด Environment variables ที่ system variables คลิกที่ New
จะมีหน้าต่าง dialog ขึ้นมา ให้เรากำหนดค่าดังนี้

Variable name : OPENCV_DIR
Variable value : E:\software\opencv

จุดประสงค์ก็คือ เราต้องการให้ตัวแปร OPENCV_DIR ซึ่งต่อไปเราจะเรียกใช้ด้วยการอ้างถึง $(OPENCV_DIR) มีค่าเท่ากับ E:\software\opencv ซึ่งเป็นการอ้างถึง directory path ที่อยู่ของไฟล์ต่างๆ ใน  E:\software\opencv นั่นเอง

กำหนดเสร็จแล้วให้กด OK แล้วก็รีสตาร์ทคอมพิวเตอร์ 1 ครั้ง

system variables

กลับมาที่โปรเจค HelloOpenCV ที่เราได้เคยสร้างไว้แล้ว ให้ทำการเปลี่ยนแปลงค่าต่างๆ ที่เราเคยกำหนดไว้ จากตอนที่แล้ว โดยให้เปลี่ยนแปลงตั้งแต่ E:\software\opencv ให้กลายเป็น $(OPENCV_DIR)

refer to system variables

เช่น ผมเคยกำหนดให้
จากเดิม E:\software\opencv\build\include\opencv
เปลี่ยนเป็น $(OPENCV_DIR)\build\include\opencv

เปลี่ยนให้หมดเลยนะครับ ทุกที่ ที่เราเคยกำหนด path มันไว้ เสร็จแล้วก็ลอง Build Solution ใหม่อีกครั้ง ซึ่้งก็ควรจะ build ผ่าน เหมือนที่มันเคย build ผ่านมาก่อน
หลายคนอาจจะสงสัยว่า ทำแบบนี้ มันดีอย่างไร นอกจากได้การได้การเรียก path ที่สั้นลง

อย่างแรกนะครับ ลองนึกดูเล่นๆ นะครับ หากผมกับเพือน ต้องการแชร์โปรเจคให้กันและกัน แต่บังเอิญว่าเพื่อนผม เค้าติดตั้ง OpenCV2.4 ไว้ที่ C:\Program Files (x86)\OpenCV2.4 แต่ผมติดตั้งไว้ที่  E:\software\opencv จะเกิดอะไรขึ้น หากผมนำโปรเจคของเพื่อนมารันที่เครื่องผม ถึงแม้เราจะใช้ Visual C++ เวอร์ชั่นเดียวกันก็ตาม ก็ต้องมานั่งแก้ค่าคอนฟิคต่างๆ ก่อนจะ build solution อย่างแน่นอน แต่ถ้าใช้วิธีนี้ เราสามารถนำโปรเจคคนอื่นมา build solution ใหม่ได้เลยทันที

อย่างที่สองก็คือ หากวันข้างหน้า  OpenCV ออกเวอร์ชั่นใหม่มา จากเดิมที่เราใช้อยู่ คือ OpenCV2.4 แล้วเปลี่ยนมาเป็นเวอร์ชั่น OpenCV2.5 หรือ OpenCV3.0 บางคนอาจจะเลือกที่จะแตกไฟล์ใหม่ทับของเก่า หรือไม่ก็ rename folder เอา แต่ ถ้าเรากำหนดค่าใน system variables ใน Environment variables ของ Windows แล้วหล่ะก็ เราก็แค่เปลี่ยนแปลงที่นี่ เท่านั้น จากเดิม

Variable name : OPENCV_DIR
Variable value : E:\software\opencv

ก็กำหนดใหม่เป็น

Variable name : OPENCV_DIR
Variable value : E:\software\OpenCV2.5\opencv

ที่เหลือในโปรเจค เราก็แค่ไปเปลี่ยน Linker>Input ให้ไปเรียกไฟล์ใหม่ อย่างน้อยเราก็ไม่ต้องตามไปแก้ไข config ใหม่ทั้งหมด  นี่ก็เป็นอีกเทคนิคหนึ่ง ที่ผมอยากจะนำเสนอครับ  ก็ลองเอาไปปรับๆ กันดูครับ หากใครมีเทคนิคใด น่าสนใจ ก็แชร์กันได้ครับ

อ่านเพิ่มเติม...
 

แจกฟรี พื้นที่ฝากไฟล์ 2 GB

ads

ติดตามข่าวสารผ่าน Twitter

ติดตาม Blog นี้

About Me

My photo

สวัสดีครับ ชื่อเปิ้ลนะครับ ถ้ามีอะไรให้ช่วยเหลือได้ ก็จะช่วยครับ
ผมได้สร้างบล๊อกไว้ เพื่อเก็บรวบรวมความรู้ และประสบการณ์ในการทำงานครับ แวะไปเยี่ยมชมกันได้ครับ http://mechacity.blogspot.com และบล๊อก http://faker-programmer.blogspot.com ครับ

Blog อื่นๆของฉัน

จำนวนการเยี่ยมชมบล๊อก