본문 바로가기

머신러닝&딥러닝/YOLO

6. (Python) 라즈베리파이3 에서 Ubuntu로 webcam 화면 TCP socket 통신

이번글은 Raspberry pi에서 촬영하는 Webcam 영상을 TCP socket을 통해 Ubuntu로 통신하는 법을 살펴보겠습니다.


참조 : 

https://stackoverflow.com/questions/20820602/image-send-via-tcp ((python) webcam 이미지를 TCP 소켓으로 전달하는 내용)

https://zzsza.github.io/data/2018/01/23/opencv-1/ (OpenCV - 이미지/비디오 읽기 내용)


개발환경

Raspberry Pi 3 b+ (Raspbian)

Ubuntu 18.04

Webcam (logitech c920)

Python 3.6

OpenCV 3.4.0

설명

Client와 Server의 통신을 위해서 TCP Socket을 사용했다.

client.py

Client는 Raspberry pi로 Webcam으로 실시간으로 영상을 촬영한다.
촬영한 영상을 frame으로 캡처해서 문자열로 변환(인코딩)하여 frame의 크기와 함께 서버로 전송한다.

server.py

Server는 Ubuntu로 Client로 부터 데이터를 수신한다.
수신한 문자열을 디코딩하여 OpenCV를 통해 이미지로 변환하여 Webcam 영상을 보여준다.

client.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# -*- coding: utf8 -*-
import cv2
import socket
import numpy as np
 
## TCP 사용
= socket.socket(socket.AF_INET, socket.SOCK_STREAM)
## server ip, port
s.connect(('192.168.1.83'8485))
 
 
## webcam 이미지 capture
cam = cv2.VideoCapture(0)
 
## 이미지 속성 변경 3 = width, 4 = height
cam.set(3320);
cam.set(4240);
 
## 0~100에서 90의 이미지 품질로 설정 (default = 95)
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
 
while True:
    # 비디오의 한 프레임씩 읽는다.
    # 제대로 읽으면 ret = True, 실패면 ret = False, frame에는 읽은 프레임
    ret, frame = cam.read()
    # cv2. imencode(ext, img [, params])
    # encode_param의 형식으로 frame을 jpg로 이미지를 인코딩한다.
    result, frame = cv2.imencode('.jpg', frame, encode_param)
    # frame을 String 형태로 변환
    data = numpy.array(frame)
    stringData = data.tostring()
 
    #서버에 데이터 전송
    #(str(len(stringData))).encode().ljust(16)
    s.sendall((str(len(stringData))).encode().ljust(16+ stringData)
 
cam.release()
cs

server.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import socket
import cv2
import numpy as np
 
#socket에서 수신한 버퍼를 반환하는 함수
def recvall(sock, count):
    # 바이트 문자열
    buf = b''
    while count:
        newbuf = sock.recv(count)
        if not newbuf: return None
        buf += newbuf
        count -= len(newbuf)
    return buf
 
HOST=''
PORT=8485
 
#TCP 사용
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print('Socket created')
 
#서버의 아이피와 포트번호 지정
s.bind((HOST,PORT))
print('Socket bind complete')
# 클라이언트의 접속을 기다린다. (클라이언트 연결을 10개까지 받는다)
s.listen(10)
print('Socket now listening')
 
#연결, conn에는 소켓 객체, addr은 소켓에 바인드 된 주소
conn,addr=s.accept()
 
while True:
    # client에서 받은 stringData의 크기 (==(str(len(stringData))).encode().ljust(16))
    length = recvall(conn, 16)
    stringData = recvall(conn, int(length))
    data = np.fromstring(stringData, dtype = 'uint8')
    
    #data를 디코딩한다.
    frame = cv2.imdecode(data, cv2.IMREAD_COLOR)
    cv2.imshow('ImageWindow',frame)
    cv2.waitKey(1)
 
cs