2015年1月31日 星期六

[Java]JavaCV播放影片(1)

程式碼參考自這裡 - OpenCV Lover  ,但這個範例會出現奇怪的問題:

warning couldn't read movie file

後來我稍微改了一下就正常了,不過它用的是比較舊版本的JavaCV,所以import 的

package name會不一樣,先說明一下,這個範例不會有聲音 ,下一篇才會寫聲音的部

分,請見諒。


專案內容




程式碼

 
package javacvplayvideo;

import java.io.File;
import org.bytedeco.javacpp.opencv_core.IplImage;
import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.javacv.FFmpegFrameGrabber;


public class JavaCVPlayVideo {

    public static void main(String[] args) {
       //new一個File,路徑為要撥放的檔案
       File f=new File("/Users/flowercatswets/Desktop/demo.mp4");
       
      //建立一個CanvasFrame ,用來撥放影片
      CanvasFrame canvas=new CanvasFrame("北七部落格 - JavaCV Play Video Demo");
      //設定關閉CanvasFrame時一併結束程式
      canvas.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
      //宣告一個FrameGrabber用來取得影片Frame
       FFmpegFrameGrabber frameGrabber =
            new FFmpegFrameGrabber(f.getAbsolutePath());
      
      try
      {
         //開始取得影片Frame
          frameGrabber.start();
          
          //宣告一個IplImage用來裝取出的Frame
          IplImage img;
          
           //把Frame取出放進img(先取一張做畫面大小的設定)
           img=frameGrabber.grab();
           //設定畫面大小
           canvas.setCanvasSize(img.width(), img.height());
          
          while (true)
          {
              //把Frame取出放進img
              img=frameGrabber.grab();
              
              if (img!=null)
              {
                  //顯示取出來的畫面
                  canvas.showImage(img);
              }
              
          }
      }
      catch(Exception e)
      {
          e.printStackTrace();
      }
    }
    
}


執行畫面




啟動撥放時,Console會輸出影片的詳細資訊





2015年1月29日 星期四

[Opensuse] zypper se -t pattern devel

 zypper se -t pattern devel


























如果要安裝C/C++ 開發。

sudo zypper install -t pattern devel_C_C++



[Java]JavaCV 人臉偵測(Face Detcet)

上一篇筆記 紀錄了如何用JavaCV開啟WebCam ,這篇來紀錄一下人臉偵測。

人臉偵測其實很常見,一般的相機,手機的相機APP 都支援人臉偵測,在拍照時可以以偵測

到的人臉做為對焦區域,Face Detect基本上就是找出人臉所在的位置,本篇所使用的原理

參考這一篇  , 在opencv中有己經訓練好的檔案可以使用,常見包含人臉偵測,雙眼偵

測,以本篇來說只要換一下訓練的檔案,程式不用改一個字,就可以改成偵測雙眼的功能。


人臉偵測和人臉識別是2個不同的東西,就好比我看到人(偵測)以及我認識這個人(識

別),是二個不同層面的事情,當然你要識出這個人之前你要先看到這個人的人臉。


程式流程如下:

取得WebCam畫面 -> 轉成灰階 ->偵測人臉位置 ->把人臉標記在WebCam畫面上 ->顯

示 -> 重頭來過


package javacv2;

import java.io.File;
import java.net.URL;
import org.bytedeco.javacpp.Loader;
import static org.bytedeco.javacpp.helper.opencv_objdetect.cvHaarDetectObjects;
import static org.bytedeco.javacpp.opencv_core.CV_AA;
import org.bytedeco.javacpp.opencv_core.CvMemStorage;
import org.bytedeco.javacpp.opencv_core.CvRect;
import org.bytedeco.javacpp.opencv_core.CvScalar;
import org.bytedeco.javacpp.opencv_core.CvSeq;
import static org.bytedeco.javacpp.opencv_core.IPL_DEPTH_8U;
import org.bytedeco.javacpp.opencv_core.IplImage;
import static org.bytedeco.javacpp.opencv_core.cvClearMemStorage;
import static org.bytedeco.javacpp.opencv_core.cvGetSeqElem;
import static org.bytedeco.javacpp.opencv_core.cvLoad;
import static org.bytedeco.javacpp.opencv_core.cvPoint;
import static org.bytedeco.javacpp.opencv_core.cvRectangle;
import static org.bytedeco.javacpp.opencv_imgproc.CV_BGR2GRAY;
import static org.bytedeco.javacpp.opencv_imgproc.cvCvtColor;
import org.bytedeco.javacpp.opencv_objdetect;
import static org.bytedeco.javacpp.opencv_objdetect.CV_HAAR_DO_CANNY_PRUNING;
import org.bytedeco.javacpp.opencv_objdetect.CvHaarClassifierCascade;
import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.OpenCVFrameGrabber;

public class JavaCV2 {

    public static void main(String args[]) {

        //用 FrameGrabber 取得 得webcam
        FrameGrabber grabber = new OpenCVFrameGrabber("");

        //宣告一個CanvasFrame ,就把它當作是一個JFrame用。
        CanvasFrame canvas = new CanvasFrame("Webcam", CanvasFrame.getDefaultGamma() / grabber.getGamma());
        //設定這一個JFrame關閉時順便把程式結束。
        canvas.setDefaultCloseOperation(
                javax.swing.JFrame.EXIT_ON_CLOSE);

        try {
            //從網路上取得訓練好的檔案(不太建議用2.4版本的會有問題)
            URL url = new URL("https://raw.github.com/Itseez/opencv/2.2/data/haarcascades/haarcascade_frontalface_alt.xml");
            //把網頁上取回來的資料寫入本地端檔案
            File file = Loader.extractResource(url, null, "classifier", ".xml");
            //假如有相同檔名己存在則刪除舊友的
            file.deleteOnExit();
            //指定classifier檔案名稱(也就是剛才由網路上捉下來的檔案路徑)
            String classifierName = file.getAbsolutePath();

            // 預先載入 opencv_objdetect module .
            Loader.load(opencv_objdetect.class);
            //初始化HaarClassifierCascade
            CvHaarClassifierCascade classifier = new CvHaarClassifierCascade(cvLoad(classifierName));
            //假如載入HaarClassifierCascade 失敗則結束程式
            if (classifier.isNull()) {
                System.err.println("Error loading classifier file \"" + classifierName + "\".");
                System.exit(1);
            }

            //啟動WebCam
            grabber.start();

            //定義一個IplImage 存放取出來的影像
            IplImage img;

            //先取一張畫面放入IplImage            
            img = grabber.grab();
            //取得影像的長寬
            int width = img.width();
            int height = img.height();

            //建立一個灰階影像(用IPL_DEPTH_8U 原因為,灰階影像每一個pixel R,G,B值皆相等,只需要存一份即可)
            IplImage grayImage = IplImage.create(width, height, IPL_DEPTH_8U, 1);
            //建立一個CvMemStorage做運算用
            CvMemStorage storage = CvMemStorage.create();
            
            //設定顯示用的CanvasFrame為取出的影像大小
            canvas.setCanvasSize(grabber.getImageWidth(),
                    grabber.getImageHeight());

            while (canvas.isVisible() && (img = grabber.grab()) != null) {
                //重置運算用的CvMemStorage
                cvClearMemStorage(storage);

                // 把原始影像變成灰階
                cvCvtColor(img, grayImage, CV_BGR2GRAY);
                //偵測人臉
                CvSeq faces = cvHaarDetectObjects(grayImage, classifier, storage,
                        1.1, 3, CV_HAAR_DO_CANNY_PRUNING);
                //取得捉到的人臉
                int total = faces.total();
                //在人臉上畫一個紅色的矩型
                for (int i = 0; i < total; i++) {
                    CvRect r = new CvRect(cvGetSeqElem(faces, i));
                    int x = r.x(), y = r.y(), w = r.width(), h = r.height();
                    cvRectangle(img, cvPoint(x, y), cvPoint(x + w, y + h), CvScalar.RED, 1, CV_AA, 0);
                }
                //顯示圖片
                canvas.showImage(img);
                
            }
        }
        catch(Exception e)
        {
            
        }
        

    }
}




至於主要用來偵測的cvHaarDetectObjects 用法如下 -資料來源

cvHaarDetectObjects( const CvArr* image, CvHaarClassifierCascade* cascade,
                            CvMemStorage* storage, double scale_factor=1.1,
                            int min_neighbors=3, int flags=0,
                            CvSize min_size=cvSize(0,0) );


image
被檢圖像
cascade
harr 分類器級聯的內部標識形式
storage
用來存儲檢測到的一序列候選目標矩形框的記憶體區域。
scale_factor
在前後兩次相繼的掃描中,搜索視窗的比例繫數。例如1.1指將搜索視窗依次擴大10%。
min_neighbors
構成檢測目標的相鄰矩形的最小個數(預設-1)。如果組成檢測目標的小矩形的個數和小於min_neighbors-1 都會被排除。如果min_neighbors 為 0, 則函數不做任何操作就返回所有的被檢候選矩形框,這種設定值一般用在用戶自定義對檢測結果的組合程式上。
flags
操作方式。當前唯一可以定義的操作方式是 CV_HAAR_DO_CANNY_PRUNING。如果被設定,函數利用Canny邊緣檢測器來排除一些邊緣很少或者很多的圖像區域,因為這樣的區域一般不含被檢目標。人臉檢測中通過設定閾值使用了這種方法,並因此提高了檢測速度。
min_size
檢測視窗的最小尺寸。預設的情況下被設為分類器訓練時採用的樣本尺寸(人臉檢測中預設大小是~20×20)。


接下來我們把程式中的
  //從網路上取得訓練好的檔案(不太建議用2.4版本的會有問題)
            URL url = new URL("https://raw.github.com/Itseez/opencv/2.2/data/haarcascades/haarcascade_frontalface_alt.xml");

換成

  //從網路上取得訓練好的檔案(不太建議用2.4版本的會有問題)
URL url = new URL("https://raw.githubusercontent.com/Itseez/opencv/2.2/data/haarcascades/haarcascade_eye_tree_eyeglasses.xml");



網路上也有一些訓練好的檔案的資料可以使用,不限於只有人臉或雙眼,參考下列網址 https://github.com/Itseez/opencv/tree/master/data/haarcascades

2015年1月27日 星期二

[Java]JavaCV 開啟webcam

用JavaCV開啟WebCam 感覺也很直覺,不多說,插上WebCam直Run,

程式碼來源


專案開發工具為 Netbeans IDE 8.0.1 ,先來看看整個專案。














很簡單,就只有一個Java程式,以及引入了3個JavaCV內的JAR檔。

接下來我們看程式碼,俺己經把註解中文化了。



package javacv2;
import org.bytedeco.javacpp.opencv_core.IplImage;
import static org.bytedeco.javacpp.opencv_core.cvFlip;
import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.OpenCVFrameGrabber;

public class JavaCV2 {

    public static void main(String args[]) {
        //New 一個CanvasFrame ,就把它當作是一個JFrame用。
        CanvasFrame canvas = new CanvasFrame("Webcam");
        //設定這一個JFrame關閉時順便把程式結束。
        canvas.setDefaultCloseOperation(
                javax.swing.JFrame.EXIT_ON_CLOSE);
        //用 FrameGrabber 取得 得webcam
        FrameGrabber grabber = new OpenCVFrameGrabber("");

        try {
            //開始取得畫面
            grabber.start();

            //定義一個IplImage 存放取出來的影像
            IplImage img;

            while (true) {

                //把影像放入IplImage
                img = grabber.grab();

                //設定顯示用的CanvasFrame為取出的影像大小
                canvas.setCanvasSize(grabber.getImageWidth(), 
                        grabber.getImageHeight());

                if (img != null) {
                    //水平翻轉圖片,直接取進來的圖片(可能)會鏡向。
                    cvFlip(img, img, 1);
                    //顯示圖片
                    canvas.showImage(img);
                }
            }
        } catch (Exception e) {
        }
    }

}



如果對CanvasFrame 有興趣的,可以參考這個網頁

執行結果



















執行結果 cvFlip(img, img, 1);




















其實門應該在我的右手邊,所以其實我並不需要加cvFlip(img, img, 1);  ,但各家的

WebCam硬體設計不同,可能還是要試試看,我使用的是羅技C 170。而方向的定義是要由

webcam定義,或是自己對面的方向,可能視情況而定。

最後,你會發現一件事,影像怎麼好像都很雪白,有一個方式可以修正一下Gamma值。

程式只要改2行





package javacv2;
import org.bytedeco.javacpp.opencv_core.IplImage;
import static org.bytedeco.javacpp.opencv_core.cvFlip;
import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.OpenCVFrameGrabber;

public class JavaCV2 {

    public static void main(String args[]) {
        
         //用 FrameGrabber 取得 得webcam
        FrameGrabber grabber = new OpenCVFrameGrabber("");
        
        //宣告一個CanvasFrame ,就把它當作是一個JFrame用。
        CanvasFrame canvas = new CanvasFrame("Webcam",CanvasFrame.getDefaultGamma()/grabber.getGamma());
        //設定這一個JFrame關閉時順便把程式結束。
        canvas.setDefaultCloseOperation(
                javax.swing.JFrame.EXIT_ON_CLOSE);
       

        try {
            //開始取得畫面
            grabber.start();

            //定義一個IplImage 存放取出來的影像
            IplImage img;

            while (true) {

                //把影像放入IplImage
                img = grabber.grab();

                //設定顯示用的CanvasFrame為取出的影像大小
                canvas.setCanvasSize(grabber.getImageWidth(), 
                        grabber.getImageHeight());

                if (img != null) {
                    //水平翻轉圖片,直接取進來的圖片(可能)會鏡向。
                    cvFlip(img, img, 1);
                    //顯示圖片
                    canvas.showImage(img);
                }
            }
        } catch (Exception e) {
        }
    }

}


執行結果 ,其實我的膚色比較接近黑色~_~。

[C#]DataGridView 輸入小寫自動轉大寫

如果在DataGridView中某些欄位需要強制轉成大寫處理時,可以參考這一個方法。


一、先拉出所需要的DataGridView。























二、在DataGridView的屬性中的EditingControlShowing點二下產生出一個事件方法。






























三、在方法中寫下這樣的程式碼


1:  //假設我只要第0個Column自動轉大寫  
2:  if (dataGridView1.CurrentCell.ColumnIndex == 0)  
3:  {  
4:    DataGridView dgv = (DataGridView)sender;  
5:    if (e.Control is DataGridViewTextBoxEditingControl)  
6:    {  
7:      DataGridViewTextBoxEditingControl editiongControl = (DataGridViewTextBoxEditingControl)e.Control;  
8:      editiongControl.CharacterCasing = CharacterCasing.Upper;  
9:    }  
10:  }  
11:  //非第一個Column (不需要強制大寫的部份)  
12:  else  
13:  {  
14:    DataGridViewTextBoxEditingControl editiongControl = (DataGridViewTextBoxEditingControl)e.Control;  
15:    editiongControl.CharacterCasing = CharacterCasing.Normal;  
16:  }  


執行畫面,無論在第1欄位輸入時是大寫或是小寫,欄位中顯示的都是大寫的英文。



[Java] JavaCV初體驗筆記-Smooth

Java要使用OpenCV有二種方式: (1) 透過JNI去呼叫OpenCV的C。(2)使用JavaCV。



javaCV 的簡介 - 資料來源  (翻成繁中)


JavaCV是對各種常用電腦視覺函式庫的封裝後的一組JAR包,其中封裝了OpenCV、

libdc1394、OpenKinect、videoInput和ARToolKitPlus等電腦視覺程式設計人員常用函式

庫的接口,可以通過其中的utility類方便的在包括Android在內的Java平台上調用這些接口。

另外JavaCV還帶有硬件加速的全螢幕圖像顯示(CanvasFrame),易於在多核心中執行

並行代碼,用戶友好的幾何和色彩的相機和投影儀校准(GeometricCalibrator,

ProCamGeometricCalibrator,ProCamColorCalibrator ),檢測和特徵點

(ObjectFinder),一類是實現投影,攝像系統(直接圖像對齊設置匹配主要

GNImageAligner,ProjectiveTransformer,ProjectiveGainBiasTransformer,

ProCamTransformer和ReflectanceInitializer),以及在JavaCV類雜項功能。



JavaCV安裝

https://github.com/bytedeco/javacv

到這裡下載avaCV 0.10 binary archive javacv-0.10-bin.zip (136 MB)

網頁中有教各種IDE的使用方法,小弟我使用Netbeans 嘗試了Smooth範例,確認是可以執

行的。為了方便筆記Demo ,自己有小修改了一下。

裝JavaCV(0.10版本)之前,不必先安裝OpenCV 。


範例圖片在這裡

http://www.cs.cmu.edu/~chuck/lennapg/lena_std.tif


這個範例只需要引入一個openCV.jar 即可












程式碼如下


package javacv;

import  org.bytedeco.javacpp.opencv_core.IplImage;
import static org.bytedeco.javacpp.opencv_core.cvReleaseImage;
import static org.bytedeco.javacpp.opencv_highgui.cvLoadImage;
import static org.bytedeco.javacpp.opencv_highgui.cvSaveImage;
import static org.bytedeco.javacpp.opencv_highgui.cvShowImage;
import static org.bytedeco.javacpp.opencv_highgui.cvDestroyWindow;
import static org.bytedeco.javacpp.opencv_highgui.cvWaitKey;
import static org.bytedeco.javacpp.opencv_imgproc.cvSmooth;

public class Javacv {

     public  void smooth(String filename ,String savefilename) { 
        //讀取來源檔案
        IplImage image = cvLoadImage(filename);
        //覆製1個來源檔做為輸出
        IplImage image2=image.clone() ;
        if (image != null) {
            //對image做平滑處理,結果存到image2
            cvSmooth(image,image2);
            //顯示來源檔案
            cvShowImage("Source",image);
            //顯示平滑後的檔案
            cvShowImage("Smooth",image2);
            //等待20秒,不然一顯示完就關掉了。
            cvWaitKey(20000);
            //儲存結果
            cvSaveImage(savefilename, image2);
            //把視窗資源釋放
            cvDestroyWindow("Source");
            cvDestroyWindow("Smooth");
            
            //cvReleaseImage 有點怪,不能使用,原因還在查。
            //cvReleaseImage(image);
            //cvReleaseImage(image2);
        }
    }
     
    public static void main(String args[])
    {
        //來源路徑,結果儲存路徑
        new Javacv().smooth("/Users/flowercatswets/Downloads/lena_std.tif" ,"/Users/flowercatswets/Downloads/lena_smooth.tif" );
    }
    
}



值得注意一件事,程式碼中的import 前3行做個比較
import  org.bytedeco.javacpp.opencv_core.IplImage;
import static org.bytedeco.javacpp.opencv_core.cvReleaseImage;
import static org.bytedeco.javacpp.opencv_highgui.cvLoadImage;

你會發現第2及3行import 後面有多一個static,因為cvReleaseImage 以及 cvLoadImage 都是函式。



左邊是原始圖片,右邊是經過smooth圖片 ,可以明顯發現,左圖明顯較稅利。



2015年1月24日 星期六

[Java]Big5 遇到「恒」

今天朋友遇到一個需要用Big5讀取中文的Project,遇到『恒』這個字怎麼讀都會出現亂碼,

上網查詢,原來Big5在標準中是沒有以下幾個字 碁、銹、恒、裏、墻、粧、嫺 , 這些是在

倚天Big5延伸  才有加入。─資料來源wiki



以下是一個含有上述字的檔案

 <html>  
 <head>  
 <meta http-equiv="Content-Type" content="text/html; charset=MS950">  
 <title>  
 big5中文測試  
 </title>  
 <link href="fidbweb_style.css" rel="stylesheet" type="text/css" />  
 </head>  
 <body topmargin="0" leftmargin="0">  
 碁、銹、恒、裏、墻、粧、嫺  
 </font></b> <font color="#333399" size="2">big5中文測試</font></td>  
 </body>  
 </html>  

如果我們用以下程式讀取這個檔案
URL url = new URL(factoryUrl);

BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream(), "BIG5"));          

String str;
while ((str = br.readLine()) != null) {
    System.out.println(str);
}

結果將會如下

爬文之後,找到一個解法,只要修改一行程式, 改用香港增補字符集(Hong Kong Supplementary Character Set,簡稱HKSCS)
//BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream(), "BIG5"));
BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream(), "Big5_HKSCS"));
執行結果如下







如果還有遇到其他的解法,請告訴我。

2015年1月21日 星期三

[Raspberry Pi] DIY 一個Raspberry Pi 上的webcam 影像分享

我自己弄了一個可以透過區網傳輸Raspberry Pi 的webcam影像觀看程式,不計較效能

以及流量問題 ,我只希望能夠用網頁觀看,在多個不同的裝置(PC ,平板,手機)。當然

也會有些許的延遲(幾秒鐘),接下來也會繼續嘗試用其他的方式,讓影像不要Delay那麼嚴

重,在此先做個筆記。


一、環境說明

(一)Raspberry Pi  B+

           os 為 wheezy ,使用python 2.7 搭配OpenCV 2.4.10 。

          網卡 Edimax EW-7811Un 

(二)WebCam 為Logitech C170

  (三)WebSocket Server 由 GlassFish 4.1 +  Java 實作。

  (四)觀看端由 Html + JavaScript 實作。


二、整體架構圖




三、架構說明:

(一) 輸入端由OpenCV開啟Webcam取得影像 ,以Jpeg作為壓縮格式後,轉成

       Base64字串,由WebSocket client端發送(為了節省頻寬,目前品質壓到30%)。

(二) websocket 由python 的websocket-client package ,安裝方式,請參考      

[Python] 用Python 做 WebSocket Client


(三)WebSocket Server在onMessage (收到圖片時)會傳給所有連線中的Client,
 除了發送圖片的Raspberry Pi


(四) 觀看端在網頁載入完成後,會連線到WebSocket Server,等待接收訊息。當觀看端的onMessage事件發生時,會解碼收到的圖片訊息,並且顯示在網頁上,並更新時間。


四、程式碼

(一) Raspberry Pi 上的發送圖片程式 Webcam.py

import sys
import cv
import cv2
import numpy
import base64
from websocket import create_connection
#connection to websocket server
ws = create_connection('ws://192.168.0.101:8080/DemoEchoServer/echo')
#JPEG encode_param
encode_param=[int(cv2.IMWRITE_JPEG_QUALITY),30]
#select first VideoCapture 
capture = cv2.VideoCapture(0)
#set WebCame Frame Width
capture.set(3,640)
#set WebCam Frame Height
capture.set(4,480)
#defind function
def repeat():
    # Capture frame-by-frame
    ret, frame = capture.read()
    #encode to jpg
    if (type(ret)!=type(None)):
        result,imgencode=cv2.imencode('.jpg',frame,encode_param )
    # to numpy array
        data = numpy.array(imgencode)
    # tostring
        stringData = data.tostring()
    #encode to base64
        encoded = base64.b64encode(stringData)
    #send
        ws.send(encoded)
    #sleep 60millisecond
        cv2.waitKey(60)
while True:
    repeat()


(二)WebSocket Server EchoServer.java
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/echo")
public class EchoServer {
  
  //用來存放Session的集合
  private static final Set sessions = Collections
                     .synchronizedSet(new HashSet());  
 
    @OnOpen
    public void onOpen(Session session,EndpointConfig config) {        
        session.setMaxBinaryMessageBufferSize(1024*1024);
        session.setMaxTextMessageBufferSize(1024*1024);
        System.out.println(session.getId()+" open");
       //把session加入集合中  
       sessions.add(session);
    }   

    @OnClose
    public void onClose(Session session) {
        System.out.println(session.getId()+" close");
        //把session從集合中移除
         sessions.remove(session);
    }

    @OnMessage    
   public void onMessage(String message , Session session) throws IOException {       
      
       try
       {
         //sent Image 
        for(Session session2 : sessions)
       {
           if (!session2.getId().equals(session.getId()))
           {
            session2.getAsyncRemote().sendText(message);
           }
            //session2.getBasicRemote().sendText(message);
          
        }
       catch (Exception e)
        {
           e.printStackTrace();;
        }      
    }
   
    @OnError
    public void onError(Throwable t) {
        t.printStackTrace();
    }
}

(三)觀看端 display.html
1:  <html>  
2:    <head>  
3:      <title>TODO supply a title</title>  
4:      <meta charset="UTF-8">  
5:      <meta name="viewport" content="width=device-width, initial-scale=1.0">  
6:       <script language="javascript" type="text/javascript">   
7:      //echo server的網址   
8:      var wsUri = "ws://192.168.0.101:8080/DemoEchoServer/echo";   
9:      //定義元件   
10:      var outputElement;   
11:      //初始化function    
12:      function init()   
13:      {   
14:       outputElement = document.getElementById("output");   
15:       live();   
16:      }   
17:      //執行websocket
18:      function live() {   
19:       //連線到echo server   
20:       websocket = new WebSocket(wsUri);   
21:       //連線成功要執行的function   
22:       websocket.onopen = function (evt) {   
23:        onOpen(evt)   
24:       };   
25:       //連結結速要執行的function   
26:       websocket.onclose = function (evt) {   
27:        onClose(evt)   
28:       };   
29:       //收到echo server傳來的訊息要做的function   
30:       websocket.onmessage = function (evt) {   
31:        onMessage(evt)   
32:       };   
33:       //當發生錯誤時要執行的function   
34:       websocket.onerror = function (evt) {   
35:        onError(evt)   
36:       };   
37:      }   
38:      //連線成功後,在output Element顯示時間  
39:      function onOpen(evt) {   
40:        var currentdate = new Date();   
41:        var datetime = "Last Sync: " + currentdate.getDate() + "/"  
42:          + (currentdate.getMonth()+1) + "/"   
43:          + currentdate.getFullYear() + " @ "   
44:          + currentdate.getHours() + ":"   
45:          + currentdate.getMinutes() + ":"   
46:          + currentdate.getSeconds();  
47:       writeToScreen(datetime+" onOpen")  
48:      }   
49:      //當中斷連線時輸出訊息在outputElement上      
50:      function onClose(evt) {   
51:        var currentdate = new Date();   
52:        var datetime = "Last Sync: " + currentdate.getDate() + "/"  
53:          + (currentdate.getMonth()+1) + "/"   
54:          + currentdate.getFullYear() + " @ "   
55:          + currentdate.getHours() + ":"   
56:          + currentdate.getMinutes() + ":"   
57:          + currentdate.getSeconds();  
58:       writeToScreen(datetime+" onClose")  
59:      }   
60:      //收到訊息時顯示在螢幕上, 並且解密base64圖片資料   
61:      function onMessage(evt) {   
62:        var currentdate = new Date();   
63:        var datetime = "Last Sync: " + currentdate.getDate() + "/"  
64:          + (currentdate.getMonth()+1) + "/"   
65:          + currentdate.getFullYear() + " @ "   
66:          + currentdate.getHours() + ":"   
67:          + currentdate.getMinutes() + ":"   
68:          + currentdate.getSeconds()+" "  
69:          + currentdate.getTime();  
70:       writeToScreen(datetime+" onMessage")  
71:      document.getElementById("ItemPreview").src = "data:image/png;base64," + evt.data;   
72:      }   
73:      //發生錯誤時顯示訊息在outputElement上   
74:      function onError(evt) {     
75:         var currentdate = new Date();   
76:        var datetime = "Last Sync: " + currentdate.getDate() + "/"  
77:          + (currentdate.getMonth()+1) + "/"   
78:          + currentdate.getFullYear() + " @ "   
79:          + currentdate.getHours() + ":"   
80:          + currentdate.getMinutes() + ":"   
81:          + currentdate.getSeconds();  
82:       writeToScreen(datetime+" onError")  
83:      }   
84:      //發送訊息   
85:      function doSend(message) {   
86:       writeToScreen("己傳送 " + message);   
87:       websocket.send(message);   
88:      }   
89:      //輸出訊息在outputElement上   
90:      function writeToScreen(message) {   
91:       var pre = document.getElementById("myp");   
92:       pre.style.wordWrap = "break-word";   
93:       pre.innerHTML = message;   
94:       output.appendChild(pre);   
95:      }   
96:      //加入事件,當載入完成後執行init()   
97:      window.addEventListener("load", init, false);   
98:     </script>   
99:    </head>   
100:    <body>  
101:      <div id="output"> <p id="myp"></div>  
102:      <div>  
103:        <img id="ItemPreview" src="" />  
104:      </div>  
105:    </body>  
106:  </html>  

五、執行程式
 (一)先開啟WebSocket Server。
 (二)在Raspberry Pi上輸入 python Webcam.py
 (三)開啟display.html觀看。

 六、執行結果



七、待解決問題

 (一) 畫面延遲問題, 以目前看來至少會慢個約5秒,慢的主要原因是資料量,每一次
  都發送一張完整的圖片 (640 *480)  ,樹梅派只有單核心, 要一直取影像再壓成JPEG傳送,
可能會有點吃力。

(二) 透過websocket Server 再做一次分派,好處是可以讓多個裝置同時間做觀看。雖然每一個之間還是會有Delay。把傳送影像用的session2.getBasicRemote().sendText(message); 改成用session2.getAsyncRemote().sendText(message); 效能看起來些許的提昇。



2015年1月15日 星期四

[Python] 用Python 做 WebSocket Client

程式碼都來自網路上的範例,資料來源如下:

https://pypi.python.org/pypi/websocket-client/0.7.0

http://blog.liris.org/2011/01/pythonwebsocket.html


以下二個程式碼都經過測試可用,如果使用pip 出現

bash: pip: command not found


請參考這一篇可解




1.安裝 websocket-client

sudo pip install websocket-client

2.寫以下程式


import websocket
import thread
import time

def on_message(ws, message):
    print message

def on_error(ws, error):
    print error

def on_close(ws):
    print "### closed ###"

def on_open(ws):
    def run(*args):
        for i in range(3):
            time.sleep(1)
            ws.send("Hello %d" % i)
        time.sleep(1)
        ws.close()
        print "thread terminating..."
    thread.start_new_thread(run, ())


if __name__ == "__main__":
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp("ws://localhost:5000/chat",
                                on_message = on_message,
                                on_error = on_error,
                                on_close = on_close)
    ws.on_open = on_open
    
    ws.run_forever()



會得到以下輸出

Sending 'Hello, World'...
Sent
Reeiving...
Received 'Hello, World'

3. 或是你可以寫成以下javascripti-like 風格 ,這個程式值得學習,

   會印出詳細的head內容。

import websocket
import thread
import time

def on_message(ws, message):
    print message

def on_error(ws, error):
    print error

def on_close(ws):
    print "### closed ###"

def on_open(ws):
    def run(*args):
        for i in range(3):
            time.sleep(1)
            ws.send("Hello %d" % i)
        time.sleep(1)
        ws.close()
        print "thread terminating..."
    thread.start_new_thread(run, ())


if __name__ == "__main__":
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp("ws://localhost:5000/chat",
                                on_message = on_message,
                                on_error = on_error,
                                on_close = on_close)
    ws.on_open = on_open
    
    ws.run_forever()


輸出會是

--- request header ---
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: echo.websocket.org
Origin: http://echo.websocket.org
Sec-WebSocket-Key: 9QLjYJ8TT9qA+9/nJMRuOQ==
Sec-WebSocket-Version: 13


-----------------------
--- response header ---
HTTP/1.1 101 Web Socket Protocol Handshake
Connection: Upgrade
Date: Sat, 10 Jan 2015 04:40:23 GMT
Sec-WebSocket-Accept: dd1ebjFbrPUd0jg9XP/v0MYaSUE=
Server: Kaazing Gateway
Upgrade: websocket
-----------------------
send: '\x81\x872\xech2z\x89\x04^]\xccX'
Hello 0
send: '\x81\x87\x86\xe2\xc6\x94\xce\x87\xaa\xf8\xe9\xc2\xf7'
Hello 1
send: '\x81\x87\x99aD\xd2\xd1\x04(\xbe\xf6Av'
Hello 2
send: '\x88\x82\x85\xa6\x00\xcc\x86N'
thread terminating...

### closed ###


[分享] Gigabyte J1900n-D2H 安裝win7 x86 經驗 (套裝機)

最近遇到一款套裝電腦,使用技嘉 J1900n-D2H版子,無法順利安裝Win7 x86版本。

只要放x86 win7 就無法在BIOS中選用光碟作為開機。












經過確認,此BIOS的版本為F2 ,但官網只有一個F3 唯一版本。

接下來我們要來解除限制了 ,不必刷BIOS ,靠設定決勝。


Step 1  Advanced - >CSM Configuration























Step2  CSM Support  - > Enabled , 把底下的 Network ,Starage等等都變成

Legacy only
























Step 3 Secure  boot -> Disabled 這部份很重要,感謝強者高人幫忙。

















接下就就可以安心的放入win7 x86重灌了。






[分享] MSI J1900i 安裝WIN7 USB 問題

最近遇上MSI J1900I 這塊版子 in 套裝的電腦,原廠出來是配WINDOWS 8.1 ,

 若要安裝WIN 7 會發生進入WIN 7 安裝程式後 , USB 裝置完全失效的問題

(也許可能是套裝廠商有客制過,開機有大大的廠商LOGO)。

 以下圖片取自官網,BIOS 版本以及更新內容

















來一張套裝出廠BIOS 版本截圖,看起來不是原廠公開的BIOS











1.接下來,選擇M-Flash 中的Select one file to update BIOS























2.將下載來的BIOS解壓縮後放在USB隨身碟的根目錄下,並插入USB。

3。按下Enter, BIOS會偵測隨身碟。


















4.再按下Enter,會讀取BIOS更新檔版本號















5.按下Eneter開始更新,並且有進度條













6.更新完畢後會自己重開機,LOGO變成MSI的。













7.按DEL進入BIOS確認一下版本號 ,V1.4 更新成功。











接下來就可以安心的安裝Win7,不必擔心USB會GG。

2015年1月11日 星期日

[OpenCV + Python] ImportError: No module named cv

最近在使用python上調用OpenCV

import cv
import cv2

遇到了一個問題

Traceback (most recent call last):
  File "web2.py", line 3, in <module>
    import cv
ImportError: No module named cv
到網路上爬文後得知解決方式,在此紀錄一下。 找一下以下檔案的位置

cv2.so

我的檔案是放在

/usr/local/lib/python2.7/site-packages/


我就在每一個用到OpenCV的python 最上方加上二行
import sys
sys.path.append('/usr/local/lib/python2.7/site-packages')

2015年1月10日 星期六

[OpenCV] 在Mac上以Cmake編譯OpenCV C 程式。

今天假設我們有一個開啟WebCam程式(WebCam.cpp)如下, 程式碼來源
//Created by vince 
//Copyright (c) 2013年 vince. All rights reserved.

#include "opencv2/highgui/highgui.hpp"

using namespace cv;

int main()
{
    Mat image;    
    VideoCapture cap;      //capture的宣告
    cap.open(0);           //0 為預設camera
    
    while(cap.isOpened())  //確認camera能開啓
    {
        cap>>image;        //截取影像到image裡方法1
        //cap.read(image); //截取影像到image裡方法2
        //以上兩種方法都可以用,實測過沒問題!
        
        imshow("Webcam live", image);
        
        waitKey(33);//避免CPU負荷,給點delay時間
                    //實際上一般webcam的framerate差不多33ms
    }
    
    return 0;
}
然候我們要建立一個CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project( WebCam )
find_package( OpenCV REQUIRED )
add_executable( WebCam WebCam.cpp )
target_link_libraries( WebCam ${OpenCV_LIBS} )
接下來以終端機KEY
cmake .
如果出現
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/xxx 
/Users/xxx 表示CMakeLists.txt 所在位置 接下來輸入
make
如果程式碼沒有錯誤應該會出現
[100%] Built target WebCam
執行程式
./WebCam 

執行結果。

2015年1月9日 星期五

[HTML5] WebSocket 筆記 (2) - 實做echo server - Java with GlassFish.

在上一篇[HTML5] WebSocket 筆記 (1) -在網頁中使用websocket後,去爬了一下文要怎麼快速建立

一個像Echo Server一樣的功能,查到一個用Web Applaction實做。


環境如下


Web Application  
GlassFish 4.1
SDK                    
JDK 8
IDE                        
Netbean 8.0.1




WebSocket Server Code  (EchoServer.java)

 import java.io.IOException;  
 import java.util.Collections;  
 import java.util.HashSet;  
 import java.util.Set;  
 import javax.websocket.OnClose;  
 import javax.websocket.OnError;  
 import javax.websocket.OnMessage;  
 import javax.websocket.OnOpen;  
 import javax.websocket.Session;  
 import javax.websocket.server.ServerEndpoint;  
 @ServerEndpoint("/echo")  
 public class EchoServer {  
   @OnOpen  
   public void onOpen(Session session) {  
     session.setMaxBinaryMessageBufferSize(1024 * 512);  
     System.out.println(session.getId()+" open");  
   }    
   @OnClose  
   public void onClose(Session session) {  
     System.out.println(session.getId()+" close");  
   }  
   @OnMessage  
   public void onMessage(Session session, String message) throws IOException {  
     session.getBasicRemote().sendText(message);  
     System.out.println(session.getId()+" message: "+message);  
   }  
   @OnError  
   public void onError(Throwable t) {  
     t.printStackTrace();  
   }  
 }  



Web Socect Client  (echoTest.html)

 <!DOCTYPE html>  
 <html>  
   <head>  
     <title>WebSocket Echo Test</title>  
     <meta charset="UTF-8">  
     <meta name="viewport" content="width=device-width, initial-scale=1.0">  
     <script language="javascript" type="text/javascript">  
       //echo server的網址  
       var wsUri = "ws://localhost:8080/DemoEchoServer/echo";  
       //定義元件  
       var outputElement;  
       //初始化function   
       function init()  
       {  
         outputElement = document.getElementById("output");  
         testWebSocket();  
       }  
       //執行websocket測試  
       function testWebSocket() {  
         //連線到echo server  
         websocket = new WebSocket(wsUri);  
         //連線成功要執行的function  
         websocket.onopen = function (evt) {  
           onOpen(evt)  
         };  
         //連結結速要執行的function  
         websocket.onclose = function (evt) {  
           onClose(evt)  
         };  
         //收到echo server傳來的訊息要做的function  
         websocket.onmessage = function (evt) {  
           onMessage(evt)  
         };  
         //當發生錯誤時要執行的function  
         websocket.onerror = function (evt) {  
           onError(evt)  
         };  
       }  
       //連線成功後,在outputElement顯示 ,並傳送一個測試訊息  
       function onOpen(evt) {  
         writeToScreen("連線成功");  
         doSend("hello blogger");  
       }  
       //當中斷連線時輸出訊息在outputElement上        
       function onClose(evt) {  
         writeToScreen("中斷連線");  
       }  
       //收到訊息時顯示在螢幕上  
       function onMessage(evt) {  
         writeToScreen('<span style="color: blue;">接收到: ' + evt.data + '</span>');  
         websocket.close();  
       }  
       //發生錯誤時顯示訊息在outputElement上  
       function onError(evt) {  
         writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);  
       }  
       //發送訊息  
       function doSend(message) {  
         writeToScreen("己傳送 " + message);  
         websocket.send(message);  
       }  
       //輸出訊息在outputElement上  
       function writeToScreen(message) {  
         var pre = document.createElement("p");  
         pre.style.wordWrap = "break-word";  
         pre.innerHTML = message;  
         output.appendChild(pre);  
       }  
       //加入事件,當載入完成後執行init()  
       window.addEventListener("load", init, false);  
     </script>  
   </head>  
   <body>  
     <div id="output"></div>  
   </body>  
 </html>  


執行結果 - Client


















執行結果 -Server




參考資料

https://tyrus.java.net/documentation/1.9/index/websocket-api.html#d0e645

http://javawebsocketsvideo.blogspot.tw/

2015年1月7日 星期三

[HTML5] WebSocket 筆記 (1) -在網頁中使用websocket

WebSocket

WebSocketHTML5開始提供的一種在單個 TCP 連線上進行全雙工通訊的協定。WebSocket通訊協定於2011年被IETF定為標準RFC 6455WebSocketAPIW3C定為標準。
在WebSocket API中,瀏覽器和伺服器只需要做一個握手的動作,然後,瀏覽器和伺服器之間就形成了一條快速通道。兩者之間就直接可以資料互相傳送。

 WebSocket協議定義了WS://和WSS://前綴來表示的WebSocket和WebSocket的安全連接。

資料來源- 維基百科


WebSocket 用起來很簡單,主要只有4個function,這四個function是選擇性的 ,並非全都要用

onopen()

當與server連線成功後會觸發的事件。

onclose()

當結束連線後會觸發的事件 。

onmessage()

收到Server傳送來的訊息時。

onerror()

發生錯誤時會觸發的事件。

以上四個都是事件觸發型的function , 不必用while 來輪詢 ,

有事件發生時自然就會執行這些函式。




以下用一個很簡單的例子來做WebSocket的Client端 與WebSocket Echo Server

做一個連線並發送訊息,Echo Server會回傳我們送給它的訊息。















想了解關於Echo Server,請點這裡  , 程式碼來源請點此 ,我加了一些註解幫助記憶。



 <!DOCTYPE html>  
 <html>  
   <head>  
     <title>WebSocket Echo Test</title>  
     <meta charset="UTF-8">  
     <meta name="viewport" content="width=device-width, initial-scale=1.0">  
     <script language="javascript" type="text/javascript">  
       //echo server的網址  
       var wsUri = "ws://echo.websocket.org/";  
       //定義元件  
       var outputElement;  
       //初始化function   
       function init()  
       {  
         outputElement = document.getElementById("output");  
         testWebSocket();  
       }  
       //執行websocket測試  
       function testWebSocket() {  
         //連線到echo server  
         websocket = new WebSocket(wsUri);  
         //連線成功要執行的function  
         websocket.onopen = function (evt) {  
           onOpen(evt)  
         };  
         //連結結速要執行的function  
         websocket.onclose = function (evt) {  
           onClose(evt)  
         };  
         //收到echo server傳來的訊息要做的function  
         websocket.onmessage = function (evt) {  
           onMessage(evt)  
         };  
         //當發生錯誤時要執行的function  
         websocket.onerror = function (evt) {  
           onError(evt)  
         };  
       }  
       //連線成功後,在outputElement顯示 ,並傳送一個測試訊息  
       function onOpen(evt) {  
         writeToScreen("連線成功");  
         doSend("hello blogger");  
       }  
       //當中斷連線時輸出訊息在outputElement上        
       function onClose(evt) {  
         writeToScreen("中斷連線");  
       }  
       //收到訊息時顯示在螢幕上  
       function onMessage(evt) {  
         writeToScreen('<span style="color: blue;">接收到: ' + evt.data + '</span>');  
         websocket.close();  
       }  
       //發生錯誤時顯示訊息在outputElement上  
       function onError(evt) {  
         writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);  
       }  
       //發送訊息  
       function doSend(message) {  
         writeToScreen("己傳送 " + message);  
         websocket.send(message);  
       }  
       //輸出訊息在outputElement上  
       function writeToScreen(message) {  
         var pre = document.createElement("p");  
         pre.style.wordWrap = "break-word";  
         pre.innerHTML = message;  
         output.appendChild(pre);  
       }  
       //加入事件,當載入完成後執行init()  
       window.addEventListener("load", init, false);  
     </script>  
   </head>  
   <body>  
     <div id="output"></div>  
   </body>  
 </html>  


執行結果


2015年1月4日 星期日

[C#] C# 語取健保卡基本資料─晶片讀卡機

在網路上看到的原始碼,紀錄下來, 資料來源 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ReadNHICard
{
    class Program
    {
        public struct SCARD_IO_REQUEST
        {
            public int dwProtocol;
            public int cbPciLength;
        }

        //引用 PC/SC(Personal Computer/Smart Card) API WinScard.dll
        [DllImport("WinScard.dll")]
        public static extern int SCardEstablishContext([In]Int32 dwScope,
            [In]int nNotUsed1, [In]int nNotUsed2, [In, Out]ref int phContext);
        [DllImport("WinScard.dll")]
        public static extern int SCardReleaseContext(int phContext);
        [DllImport("WinScard.dll")]
        public static extern int SCardConnect(int hContext, string cReaderName,
            uint dwShareMode, uint dwPrefProtocol, ref int phCard, ref int ActiveProtocol);
        [DllImport("WinScard.dll")]
        public static extern int SCardDisconnect(int hCard, int Disposition);
        [DllImport("WinScard.dll")]
        public static extern int SCardListReaders(int hContext, string cGroups,
            ref string cReaderLists, ref int nReaderCount);
        [DllImport("WinScard.dll")]
        public static extern int SCardTransmit(int hCard,
            ref SCARD_IO_REQUEST pioSendPci, byte[] pbSendBuffer, int cbSendLength,
            ref SCARD_IO_REQUEST pioRecvPci, ref byte pbRecvBuffer, ref int pcbRecvLength);
 

        static void Main(string[] args)
        {
            int ContextHandle = 0;
            int CardHandle = 0;
            int ActiveProtocol = 0;
            int ReaderCount = -1;
            string ReaderList = string.Empty; //讀卡機名稱列表
            SCARD_IO_REQUEST SendPci, RecvPci;
            byte[] SelectAPDU = { 0x00, 0xA4, 0x04, 0x00, 0x10, 0xD1, 0x58, 0x00, 0x00, 0x01, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00 };
            byte[] ReadProfileAPDU = { 0x00, 0xca, 0x11, 0x00, 0x02, 0x00, 0x00 };
            byte[] SelectRecvBytes = new byte[2]; //應回 90 00
            int SelectRecvLength = 2;
            byte[] ProfileRecvBytes = new byte[59]; //接收Profile的 Byte Array
            int ProfileRecvLength = 59;
           

            //建立 Smart Card API
            if (SCardEstablishContext(0, 0, 0, ref ContextHandle) == 0)
                //列出可用的 Smart Card 讀卡機
                if (SCardListReaders(0, null, ref ReaderList, ref ReaderCount) == 0)
                    //建立 Smart Card 連線
                    if (SCardConnect(ContextHandle, ReaderList, 1, 2, ref CardHandle, ref ActiveProtocol) == 0)
                    {
                        SendPci.dwProtocol = RecvPci.dwProtocol = ActiveProtocol;
                        SendPci.cbPciLength = RecvPci.cbPciLength = 8;
                        //下達 Select Profile 檔的 APDU
                        if (SCardTransmit(CardHandle, ref SendPci, SelectAPDU, SelectAPDU.Length,
                         ref RecvPci, ref SelectRecvBytes[0], ref SelectRecvLength) == 0)
                        //下達讀取Profile指令
                        {
                            if (SCardTransmit(CardHandle, ref SendPci, ReadProfileAPDU, ReadProfileAPDU.Length,
                              ref RecvPci, ref ProfileRecvBytes[0], ref ProfileRecvLength) == 0)
                                Console.WriteLine("健保卡ID:{0}\n姓名:{1}\n身份証字號:{2}\n生日:{3}/{4}/{5}\n姓別:{6}\n發卡日期:{7}/{8}/{9}",
                                  Encoding.Default.GetString(ProfileRecvBytes, 0, 12),
                                  Encoding.Default.GetString(ProfileRecvBytes, 12, 6),
                                  Encoding.Default.GetString(ProfileRecvBytes, 32, 10),
                                  Encoding.Default.GetString(ProfileRecvBytes, 43, 2),
                                  Encoding.Default.GetString(ProfileRecvBytes, 45, 2),
                                  Encoding.Default.GetString(ProfileRecvBytes, 47, 2),
                                  Encoding.Default.GetString(ProfileRecvBytes, 49, 1),
                                  Encoding.Default.GetString(ProfileRecvBytes, 51, 2),
                                  Encoding.Default.GetString(ProfileRecvBytes, 53, 2),
                                  Encoding.Default.GetString(ProfileRecvBytes, 55, 2)
                                  );
                        }
                    }
            Console.ReadKey();
        }
    }
}