2013/8/29

[C#] QRCode Generator & Reader

現在很多海報、廣告等文宣上面角落都會放一個QRCode(二維條碼)
方便智慧型手機讀取資料及連結網站

QRCode 當初的設計就是希望能方便被讀取,希望節省輸入的時間
裡面最多可以藏入1800個中文字,可以提供的服務就相當廣泛....

QRCode 編碼&解碼方式其實沒有什麼機密
很多元件都已經都寫好,就因為是這樣才能廣泛的被利用





使用之前要先下載一個開放的函示庫(DLL) "Zxing"
解壓縮之後找到適合開發環境的版本
在裡面就可以看到 zxing.dll ,這這個檔案複製到開發的專案中

接著打開 Visual Studio 加入參考

這樣就設定完成了
接下來就可以開始寫程式了...(當然是要先拉一下畫面拉)

        private void button1_Click(object sender, EventArgs e)
        {
            System.Drawing.Bitmap bitmap = null;
            //要轉成QRCode 的內容
            string content = textBox1.Text;
            //QRCode的設定
            ZXing.BarcodeWriter writer = new ZXing.BarcodeWriter
            {
                Format = ZXing.BarcodeFormat.QR_CODE,
                Options = new ZXing.QrCode.QrCodeEncodingOptions
                {
                    //產生出圖片的高度
                    Height = 180,
                    //產生出圖片的寬度
                    Width = 180,
                    //文字是使用哪種編碼方式
                    CharacterSet = "UTF-8",

                    //錯誤修正容量
                    //L水平    7%的字碼可被修正
                    //M水平    15%的字碼可被修正
                    //Q水平    25%的字碼可被修正
                    //H水平    30%的字碼可被修正
                    ErrorCorrection = ZXing.QrCode.Internal.ErrorCorrectionLevel.H

                }
            };
            //將要編碼的文字產生出QRCode的圖檔
            bitmap = writer.Write(content);
            //儲存圖片
            bitmap.Save(@"D:\Test\QRCode\temp.png", System.Drawing.Imaging.ImageFormat.Png);
            //顯示在畫面中
            pictureBox1.Image = bitmap;
        }

到這邊就可以產生出QRCode的圖檔了

編碼跟產生檔案很簡單就完成了
有發現產生的QRCode的複雜程度會跟裡面包含的文字長度成正比嗎?

解碼也一樣很簡單

        private void button2_Click(object sender, EventArgs e)
        {
            System.Drawing.Bitmap bitmap = null;
            //宣告 QRCode Reader 物件
            ZXing.IBarcodeReader reader = new ZXing.BarcodeReader();

            //讀取要解碼的圖片
            FileStream fs = new FileStream(@"D:\Test\QRCode\temp.png", FileMode.Open);
            Byte[] data = new Byte[fs.Length];
            // 把檔案讀取到位元組陣列
            fs.Read(data, 0, data.Length);
            fs.Close();
            // 實例化一個記憶體資料流 MemoryStream,將位元組陣列放入
            MemoryStream ms = new MemoryStream(data);
            // 將記憶體資料流的資料放到 BitMap的物件中
            bitmap = (Bitmap)Image.FromStream(ms);

           //將圖片顯示於 PictureBox 中
            pictureBox2.Image = bitmap;
            //進行解碼的動作
            ZXing.Result result = reader.Decode(bitmap);
            
            if (result != null)
            {   //如果有成功解讀,則顯示文字
                label1.Text = result.Text;
            }
        }

在讀取圖檔的時候有遇到一些問題
原本讀取的寫法是
bitmap = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromFile(@"D:\Test\QRCode\temp.png");

這樣的寫法在讀取後要再產生新的圖片就會發生錯誤


研究了一下發現Image還在開啟的狀態,不能進行寫入的動作
所以一開始將圖片讀出來放到Memory就可以了

參考文獻: http://blog.miniasp.com/post/2009/05/30/A-generic-error-occurred-in-GDI-plus.aspx

很簡單就可以自己製作QRCode吧
雖然Google上可以找到很多工具可以使用
但是還是自己做比較有FU~~

下次就可以連結攝影機來解讀QRcode了!!

DEMO

2013/8/26

[C#] 使用WebCam 錄影(Record video)&拍照(Take picture)


之前的文章講到如何取得WebCam影像
現在我做了些修正,加入了錄影(Record video)&拍照(Take picture)的功能



首先我使用Timer 替換掉之前的 Application_Idle 的Function
原因是使用原本的Application_Idle在錄影的過程中
畫面上PictureBox不會跟著更新

private void TimerEventProcessor(object sender, EventArgs e)
        {
            Image<Bgr, Byte> frame = cap.QueryFrame(); // Query 攝影機的畫面

            pictureBox1.Image = frame.ToBitmap(); // 把畫面轉換成bitmap型態,在丟給pictureBox元件

            //錄影模式
            if (_isRecording)
            {
                //將影格寫入影片中
                video.WriteFrame<Bgr, byte>(frame);
            }
        }

之前的範例一開始就會自動啟動WebCam
只有顯示影像的功能
但是這次的範例就有三個功能(顯示影像、錄影、拍照)
都會去初始化攝影機,所以就抽出來寫成一個Function

        /// <summary>
        /// 開啟攝影機
        /// </summary>
        private void openWebCam()
        {
            //如果webcam沒啟動
            if (cap == null)
            {
                try
                {
                    //打開預設的webcam
                    cap = new Capture();
                }
                catch (NullReferenceException excpt)
                {
                    MessageBox.Show(excpt.Message);
                }
            }
        
        }

顯示影像的功能跟上個範例差別不大
只是多了按鈕去觸發而已

        private void button1_Click(object sender, EventArgs e)
        {
            openWebCam();

            //webcam啟動
            if (cap != null)
            {
                //frame啟動
                if (_captureInProgress)
                {
                    //stop the capture
                    _captureInProgress = false;
                    button1.Text = "開啟";
                    _timer.Stop();
                }
                //frame關閉
                else
                {
                    //start the capture
                    _captureInProgress = true;
                    button1.Text = "關閉";
                    _timer.Start();
                }
            }
        }

接著是在畫面新加入錄影和停止的按鈕
錄影的觸發事件一開始就是啟動Timer
決定好存放路徑跟檔名
New 一個 Video Object 出來
將_isRecording的Flag 設為True
這樣在Timer 裡面就會把擷取到影格寫入影片檔中

        private void button2_Click(object sender, EventArgs e)
        {
                openWebCam();

                _timer.Start();

                _fileName = string.Format("{0}{1}{2}", _movieDirectory, DateTime.Now.ToString("yyyyMMddHmmss"), ".avi");

                //cap.Width 取得攝影機可支援的最大寬度
                //cap.Height 取得攝影機可支援的最大高度
                video = new VideoWriter(_fileName, 0, 10, cap.Width, cap.Height, true);

                //開啟錄影模式
                _isRecording = true;

        }

當按下停止時
將_isRecording的Flag 設為False
Timer就不會再寫入影片了
這樣簡單就完成影片的製作了

private void button3_Click(object sender, EventArgs e)
        {            
            //錄影完需將影像停止不然會出錯
            _isRecording = false;
            video.Dispose();

        }

拍照功能也很簡單
先在畫面拉一個拍照的按鈕
決定好存放路徑跟檔名
呼叫Image的Save Function
也是輕鬆完成拍照的功能

        //拍攝照片
        private void button4_Click(object sender, EventArgs e)
        {
            openWebCam();

            // Query 攝影機的畫面
            Image<Bgr, Byte> phtoFrame = cap.QueryFrame();

            //儲存路徑
            _fileName = string.Format("{0}{1}{2}", _phtoDirectory, DateTime.Now.ToString("yyyyMMddHmmss"), ".JPG");

            //儲存影像
            phtoFrame.Save(_fileName);
        }

忘了說兩個變數
一個是影片的存放位置
一個是照片的存放位置

        string _movieDirectory = @"d:\Test\movies\";
        string _phtoDirectory = @"d:\Test\photos\";

因為偷懶沒有自動建立資料夾的程式,想用的人可能自己建喔

DEMO

2013/8/25

在Blogger分享程式碼區塊(code block)

上一篇的文章之中有貼上一些程式碼
但是只能貼上圖片....看起來很奇怪也不方便使用
同時也看到別人網誌上的程式碼都可以放得很漂亮
所以就來研究一下怎麼在Blogger 上加入程式碼區塊(code block)

首先登入Blogger
到管理者的頁面

範本 --> 自訂

選擇進階 -->新增 CSS --> 在右邊空白處填入下列的程式碼   --> 套用置網誌

CODE {
display: block; /* fixes a strange ie margin bug */
font-family: Courier New;
font-size: 8pt;
overflow:auto;
background: #f0f0f0 url(http://klcintw.images.googlepages.com/Code_BG.gif) left top repeat-y;
border: 1px solid #ccc;
padding: 10px 10px 10px 21px;
max-height:200px;
line-height: 1.2em;
}


這樣算是設定完成了

在寫文章的過程中,遇到要插入程式碼區段的時候
要切換到 HTML 模式
再加入之前要用 HTML Eecode
將特殊字元轉換成HTML的格式
在程式碼的前後加上<code>程式碼</code>標籤



CODE { display: block; /* fixes a strange ie margin bug */ font-family: Courier New; font-size: 8pt; overflow:auto; background: #f0f0f0 url(http://klcintw.images.googlepages.com/Code_BG.gif) left top repeat-y; border: 1px solid #ccc; padding: 10px 10px 10px 21px; max-height:200px; line-height: 1.2em; }
就會出現文字區塊了
但是好像不能排版換行
找了一些文章之後發現....
有個簡單的方式就可以做到程式碼區塊了......(寫到一半才發現)

其實是可以不用作上面圖片中去修改 CSS
只要連到這個網站  http://formatmysourcecode.blogspot.com/
將你的程式碼貼上去,他就會轉出HTML的語法
以及呈現的效果
 接著將轉出來的內容直接貼到 Blogger 的 HTML模式底下就可以了

切回去選寫模式就會長這樣

第二個方法真的是相當的方便
為了留下學習的紀錄還是將第一個方法(修改 CSS)記錄下來



CODE {
display: block; /* fixes a strange ie margin bug */
font-family: Courier New;
font-size: 8pt;
overflow:auto;
background: #f0f0f0 url(http://klcintw.images.googlepages.com/Code_BG.gif) left top repeat-y;
border: 1px solid #ccc;
padding: 10px 10px 10px 21px;
max-height:200px;
line-height: 1.2em;
}

2013/8/21

[C#] 取得WebCam影像

突然心血來潮想要 WebCam 來做一些實驗
上網找一下資料發現C# 可以很容易就可以取得WebCam的影像

要使用Emgu這個套件
EmguCV 封裝了 OpenCV image processing library,允許在.Net的平台上使用

首先下載並安裝 ( libemgucv-windows-x86-2.3.0.1416.exe )
http://sourceforge.net/projects/emgucv/files/emgucv/2.3.0/libemgucv-windows-x86-2.3.0.1416.exe/download

軟體備份

安裝步驟其實就是一直點下一步

點開執行檔的畫面  --> 下一步


License 說明 -->我接受

選擇要安裝的位置 ,可以使用預設也可以自訂安裝路徑
但是要記得裝在哪裡,因為等一下設定環境變數時要用
選好之後 --> 下一步

建立程式的捷徑名稱  -->下一步

選擇要安裝的原件  --> 安裝
一般都是使用預設的設定,如果有其他需求再自行調整

接著就開始安裝了

過程中會問說是否要加入 Debugger 到 VS(Visual Studio 2010) 中 -->是

安裝完成之後要修改環境變數
如果使用預設應該 C:\Emgu\emgucv-windows-x86 2.3.0.1416\bin
如果剛剛安裝是選用自訂路徑,這邊就要跟著調整

環境變數 -> Path -> 編輯
在變數值欄位加入 Emgu的安裝路徑,記得前後面要用分號(;)隔開


到目前為止Emgu算是安裝設定完成了
接下來是如何把 Emgu 加入到 VS 中了

將 Emgu.CV.UI.dll 加入工具箱內
工具 -->選擇工具箱項目


.NET FrameWork 元件 --> 瀏覽
選擇 C:\Emgu\emgucv-windows-x86 2.3.0.1416\bin\Emgu.CV.UI.dll
如果安狀選自訂路徑,這邊也要跟著調整
按下開啟舊檔之後,會出現 Histogrambox 工具箱的選項  -->確定

完成之後到工具箱看有沒有出現下圖紅框裡的四個元件
有的話表示安裝成功了


在執行的專案裡面加入所需要的dll


瀏覽 -->C:\Emgu\emgucv-windows-x86 2.3.0.1416\bin\
選擇 "Emgu.Util.dll" "Emgu.CV.dll" "Emgu.CV.ML.dll" "Emgu.CV.UI.dll" 
如果安裝時自訂路徑,這邊要跟著修正路徑
加入成功之後


還會使用兩個opencv 的dll
opencv_core231.dll
opencv_highgui231.dll

可以在 C:\Emgu\emgucv-windows-x86 2.3.0.1416\bin 裡面找到
如果安裝時自訂路徑,這邊要跟著修正路徑
因為無法參考這兩個dll,所以只能手動放入

放到所要執行專案底下的 bin\Debug


接著就可以來寫個簡單的程式來連接WebCam了
我是使用Window Form來實作
先在設計頁面拉進一個 PictureBox
並命名為 pictureBox1

加入引用會使用到的dll


宣告 WebCam 物件

在建構式中將 WebCam物件連結到攝影機
 抓取畫面事件


執行應該就可以看到畫面了



如果遇到  'Emgu.CV.CvInvoke' 的型別初始設定式發生例外狀況。 的錯誤

在專案的屬性設定裡面將平台目標設為 X64 應該就可以執行



DEMO

2013/8/12

[Map]Google Map VS Bing Map VS Baidu Map

最近研究了一下各家的地圖服務,順便整理各家地圖的比較

Bing Map :

目前的開發環境是使用 Silverlight 去做GUI的呈現
因為是微軟的東西,第一個當然想到使用Bing Map來做
發現可以很快速的整合進去,算是蠻好的優勢


但是有一個致命的缺點...沒有支援中文地圖
這對使用者來說是極度的不友善
找了一下有看到Bing Map有中文路名

找了資訊才知道有些是把Bing Map地圖資訊換成其他家地圖資訊(支援中文路名)
只有控制項還沿用Bing Map
下面是使Bing Map 顯示中文的相關文章
http://rritw.com/a/caozuoxitong/Windows/20130416/340806.html
http://www.cnblogs.com/yoainet/archive/2012/04/12/2444108.html
這種做法會違法版權喔~建議不要在商業活動上使用

Google Map:
接著就來研究地圖服務的龍頭 Google Map的可用性了
Google Map 就不能直接整合進去 Silverlight
需要透過 JavaScript來做整合,再去跟Silverlight這邊可以要多花一點功夫了


他有中文化的地圖,也是大家都習慣的使用方式
品質也很精細,看起來都很不錯..
對.....只是看起來...
後來才知道因為Google已經退出了中國市場
所以在大陸地區是不能使用Google Map
如果產品要進入中國市場的,這一點就必須要考量的

百度Map & 騰訊 Map
大陸比較常用的兩個地圖(百度 & 騰訊)

這兩家的內容只有大陸地區的地圖資訊,沒有其他地區的內容
 如果要做跨國市場的產品要注意一下



優缺點比較


Bing Map
Google Map
百度地圖
騰訊地圖
相容性
可以直接整合silverlight
需透過 JavaScript做溝通
需透過 JavaScript做溝通
需透過 JavaScript做溝通
收費
每天調用次數少於200,000次免費,超過的部分要跟Microsoft License
每天調用次數少於25,000次免費,超過的部分每一千次調用4-10美元(依據不同的服務)
商業行為的話請與百度地圖另行達成協議或獲得百度地圖的事先書面許可
商業行為的話您需要同SOSO地圖另行達成協議或獲得SOSO地圖的事先書面許可
限制
沒有提供中文
大陸地區不能使用
只有大陸地區的地圖資訊
只有大陸地區的地圖資訊
SLA
99.9%/Month
99.9%/Month
找不到資訊
找不到資訊

SLA 相關聯結

Google Map:
Bing Map:

Google 在SLA的認定上有比較奸詐的地方,他認為如中斷10分鐘之內,不列入計算之中
而且要自己提出google Map什麼時候中斷服務的證明,且經過google認定他們才承認

補充說明:
雖然Google Map 每天使用次數在25,000次以下,是免費的
但是他有限制條件,不是說所有網站都可以免費使用...

我可以在商業網站上使用 Google Maps API 嗎?
只要消費者不需要支付費用就可以使用您網站的一般功能,您就可以使用 Google Maps API。舉例來說,假如您的網站支援廣告功能,網站即可能屬於《Google Maps API服務條款》的適用對象。如果您向在地圖上刊登資訊的使用者收取費用 (例如刊登其住宅的出售訊息),但您是在網站的免費使用部分中利用 Google Maps API 顯示該項資訊,則您也符合《Google Maps API 服務絛款》的規定。
不過,我們並非接受所有商業上的使用。舉例來說,假使您的網站符合下列任一條件,您就必須購買適當的 Google Maps API for Business 授權:
  • 您的網站只提供給付費客戶使用。
  • 您的網站只能在公司內部或內部網路中使用。
  • 您的應用程式與企業派遣、車隊管理、企業資產追蹤等其他類似的應用工作有關。


希望這份資料的整理對其他人有所幫助
如果有資料不正確的地方,請各位大大不吝指教

2013/8/6

從研究所畢業到進入職場工作,不知不覺也已經過了兩年....
這段時間裡學到了很多東西,才知道以前在學校所學的東西是多麼的不足...

伴隨著初老症的到來,記憶力也越來越薄弱,因此興起寫Blog的念頭
一方面希望可以記錄下自己學習的過程,有時候一個議題會重複學習很多次(老了....)
希望可以快速的回顧到之前所學的東西,達到溫故而知新

另一方面希望記錄下來的原因是希望可以把經驗分享給更多的人
相信我遇到過的問題,其他人也可能會遇到
希望可以幫助他人減少學習時間,能有更多的時間精力去完成工作或是夢想

分享的內容大部分會是我所遇過的問題
我對技術沒有太多的狂熱,我比較偏向解決問題為導向
所以分享的內容或是解法可能不盡完全,還是請多多見諒
如果我分享的東西可以對其他人有幫助,那我就很滿足了