EV3(leJOS)でカメラの映像をPCに送って顔認識をする②

# EV3から送られてきた画像をPCに表示する
## PC側のプログラム
```java:CameraFrame.java
public class CameraFrame {
	private static final int WIDTH = 160;
	private static final int HEIGHT = 120;
	private static final int NUM_PIXELS = WIDTH * HEIGHT;
	private static final int BUFFER_SIZE = NUM_PIXELS * 2;
	private static final int PORT = 55555;

	private ServerSocket ss;
	private Socket sock;
	private byte[] buffer = new byte[BUFFER_SIZE];
	private BufferedInputStream bis;
	private BufferedImage image;
	private CameraPanel panel = new CameraPanel();
	private JFrame frame;

　　　　  //ServerSocket,Socket,BufferedInputStreamの準備
        public CameraFrame() {
            try {
                ss = new ServerSocket(PORT);
                sock = ss.accept();
                bis = new BufferedInputStream(sock.getInputStream());
            } catch (Exception e) {
                System.err.println("Failed to connect: " + e);
                System.exit(1);
            }
            image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
	}
        
        //フレームを作成
        public void createAndShowGUI() {
            frame = new JFrame("EV3 Camera View");//JFrameのオブジェクトを作成しタイトルを設定する
            frame.getContentPane().add(panel);//送られてきた画像を描くpanelをframeに追加する．
            frame.setPreferredSize(new Dimension(WIDTH, HEIGHT));//フレームサイズの指定
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//フレームを閉じるときの動作の指定
            //windowをクローズ処理中のときの動作
            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {    
                    close();//詳細は下のcloseメソッドを参照
                }
            });
            frame.pack();//frameのサイズをフレーム中のコンポーネントに合わせて調節してくれる
            frame.setVisible(true);//フレームを表示する
        }

        //openしたものをすべてcloseする
        public void close() {
            try {
                if (bis != null)
                    bis.close();
                if (sock != null)
                    sock.close();
                if (ss != null)
                    ss.close();
            } catch (Exception e1) {
                System.err.println("Exception closing window: " + e1);
            }
        }

        //YUVフォーマットをRGBフォーマットへ変換
        private int convertYUVtoARGB(int y, int u, int v) {
            int c = y - 16;
            int d = u - 128;
            int e = v - 128;
            int r = (298 * c + 409 * e + 128) / 256;
            int g = (298 * c - 100 * d - 208 * e + 128) / 256;
            int b = (298 * c + 516 * d + 128) / 256;
            r = r > 255 ? 255 : r < 0 ? 0 : r;
            g = g > 255 ? 255 : g < 0 ? 0 : g;
            b = b > 255 ? 255 : b < 0 ? 0 : b;
            return 0xff000000 | (r << 16) | (g << 8) | b;
        }

        //BufferedInputStreamから１フレーム分のデータを読み取り，imageにRGB形式で格納する．
        public void run() throws IOException {
           while (true) {
               synchronized (this) {
                   try {
                       //bisからデータを読み込む.読み取るデータがまだ入力ストリームに残っているかもしれないのでwhile文を回す．
                       int offset = 0;
                       while (offset < BUFFER_SIZE) {
                           offset += bis.read(buffer, offset, BUFFER_SIZE - offset);
                       }

                       //各ピクセルのyuvフォーマットからrgbに変換してimageへセットする．
                       for (int i = 0; i < BUFFER_SIZE; i += 4) {
                           int y1 = buffer[i] & 0xFF;
                           int y2 = buffer[i + 2] & 0xFF;
                           int u = buffer[i + 1] & 0xFF;
                           int v = buffer[i + 3] & 0xFF;
                           int rgb1 = convertYUVtoARGB(y1, u, v);
                           int rgb2 = convertYUVtoARGB(y2, u, v);
                           image.setRGB((i % (WIDTH * 2)) / 2, i / (WIDTH * 2), rgb1);
                           image.setRGB((i % (WIDTH * 2)) / 2 + 1, i / (WIDTH * 2), rgb2);
                       }
                   } catch (Exception e) {
                       break;
                   }
               }
               //panelの再描画（内部的にCameraPanel#paintComponent()が呼び出される）
               panel.repaint(1);
           }
        }

        //カメラのフレームを描画するJPanelの定義
        class CameraPanel extends JPanel {
            private static final long serialVersionUID = 1L;
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                // imageが更新されている間はpanelに描画さないようにする
                synchronized (CameraFrame.this) {
                    g.drawImage(image, 0, 0, null);
                }
            }
        }

        public static void main(String[] args) throws IOException {
            // コンスタントラクタ
            final CameraFrame cameraFrame = new CameraFrame();
            
            // 
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    cameraFrame.createAndShowGUI();
                }
            });
            cameraFrame.run();
        }
}

```