OpenCV 영상통신
파이썬 입문 공부 (문법, threading, PyQT5) 이후 OpenCV를 들여다 보면서 영상통신을 만들어 보기로
Android 단말기와 영상을 주고 받는 구조이고 Android 단말기는 jpg 형태의 압축파일을 전송 하기로 가정한다. jpg로 압축하지 않고 raw 영상을 보내면 PC 측에서 수신하는 Bytes 수가 많아 화면에 표시되는 속도가 느려지는 문제가 발생. jpg 형태로 압축하는 시간도 있기는 하겠지만 네트워크 전송량으로 인한 부하가 발생하는 것보다는 유리 할 것으로 생각.(어떻게 측정할 것인가의 문제도 있지만 jpg 압축 API 도 공부할 겸)
동작은 아래의 순서와 같이
- PC는 통신방식에서 Server 역할을 하고 통신 개시는 Android가 Client로 동작을 하고 연결을 시도한다.
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Socket created')
server_socket.bind((HOST, PORT))
print('Socket bind complete')
server_socket.listen(10)
print('Socket now listening')
- PC는 Client의 연결로 Socket 이 생성된다.
client_socket, addr = server_socket.accept()
print("wait accept to : ", addr[0], ":", str(addr[1]))
print("Accept to : ", addr)
print('wait image')
- Client는 jpg 형태로 압축된 영상을 보내므로 매 전송 시마다 전송하는 Byte 수가 다르므로 이후 얼만큼의 영상을 수신할지 알아야 한다.
bytes_buf = receive_all(client_socket, 4)
- 알아낸 수 만큼 영상 데이터를 수신
수신한 데이터를 OpenCV 포맷으로 변환한다.bytes_length = bytes_to_int(bytes_buf)
print("Rx Length = {} ".format(bytes_length))
byte_data = receive_all(client_socket, int(bytes_length))
# convert jpg image to matix
g_decode_img = np.frombuffer(byte_data, dtype=np.uint8)
g_decode_img = cv2.imdecode(g_decode_img, cv2.COLOR_RGB2BGR)
- OpenCV 포맷으로 변환 한 이미지를 화면에서 표시하고 다시 jgp 형태로 만든다.
화면 상에서 Mouse 버튼을 누르고 이동을 하면 그 영역만큼 사각형을 그린다. 사각형이 포함된 화면이 jpg 형태로 압축된다.cv2.imshow('Client', g_copy_img)
cv2.waitKey(1)
# convert Mat to byte for sending to client
ret, imgencoded = cv2.imencode('.jpg', g_copy_img)
byte_img = np.array(imgencoded)
- 압축된 jpg를 Client로 다시 전송한다.
int_len_byte_img = len(byte_img)
bytes_len_img = int_len_byte_img.to_bytes(4, byteorder='big')
client_socket.send(bytes_len_img)
client_socket.send(byte_img)
알게된 것들
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Socket created')
server_socket.bind((HOST, PORT))
print('Socket bind complete')
server_socket.listen(10)
print('Socket now listening')
client_socket, addr = server_socket.accept()
print("wait accept to : ", addr[0], ":", str(addr[1]))
print("Accept to : ", addr)
print('wait image')
bytes_buf = receive_all(client_socket, 4)
수신한 데이터를 OpenCV 포맷으로 변환한다.
bytes_length = bytes_to_int(bytes_buf)
print("Rx Length = {} ".format(bytes_length))
byte_data = receive_all(client_socket, int(bytes_length))
# convert jpg image to matix
g_decode_img = np.frombuffer(byte_data, dtype=np.uint8)
g_decode_img = cv2.imdecode(g_decode_img, cv2.COLOR_RGB2BGR)
화면 상에서 Mouse 버튼을 누르고 이동을 하면 그 영역만큼 사각형을 그린다. 사각형이 포함된 화면이 jpg 형태로 압축된다.
cv2.imshow('Client', g_copy_img)
cv2.waitKey(1)
# convert Mat to byte for sending to client
ret, imgencoded = cv2.imencode('.jpg', g_copy_img)
byte_img = np.array(imgencoded)
int_len_byte_img = len(byte_img)
bytes_len_img = int_len_byte_img.to_bytes(4, byteorder='big')
client_socket.send(bytes_len_img)
client_socket.send(byte_img)
OpenCV는 마우스 이벤트도 지원한다.
OpenCV 화면 색상은 R G B 순서가 아닌 B G R 순서이다.
압축을 하긴 했지만 1280 * 720 화소수는 통신을 하더라도 영상 표현이 꽤나 느리다.
? 어디에 응용하면 좋을까 ?
전체 소스는
import socket
import struct
import threading
import time
from _thread import *
import numpy as np
import cv2
mouse_rectangle = False
def receive_all(sock, count):
buf = bytearray(b'')
while count:
newbuff = sock.recv(count)
if not newbuff: return None
buf += newbuff
count -= len(newbuff)
return buf
def bytes_to_int(bytes):
result = 0
for b in bytes:
result = result * 256 + int(b)
return result
def int_to_bytes(value, length):
result = []
for i in range(0, length):
result.append(value >> (i * 8) & 0xff)
result.reverse()
return result
def onMouse(event, x, y, flags, parm):
global mouse_rectangle, col, row, g_copy_img, g_decode_img
if event == cv2.EVENT_LBUTTONDOWN:
mouse_rectangle = True
col, row = x, y
elif event == cv2.EVENT_MOUSEMOVE:
if mouse_rectangle:
cv2.rectangle(g_decode_img, (col, row), (x, y), (0, 255, 0), 2)
elif event == cv2.EVENT_LBUTTONUP:
mouse_rectangle = False
def run_server_cv():
global mouse_rectangle, g_copy_img, g_decode_img
HOST = ''
PORT = 20001
cv2.namedWindow('Client') # should create window object first
cv2.setMouseCallback('Client', onMouse, 0)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Socket created')
server_socket.bind((HOST, PORT))
print('Socket bind complete')
server_socket.listen(10)
print('Socket now listening')
client_socket, addr = server_socket.accept()
# print("wait accept to : ", addr[0], ":", str(addr[1]))
print("Accept to : ", addr)
print('wait image')
while True:
try:
if mouse_rectangle is True:
bytes_buf_null = receive_all(client_socket, 4)
if bytes_buf_null is not None:
bytes_length_null = bytes_to_int(bytes_buf_null)
print("Clr Length = {} ".format(bytes_length_null))
byte_data_null = receive_all(client_socket, int(bytes_length_null))
else:
bytes_buf = receive_all(client_socket, 4)
if bytes_buf is not None:
bytes_length = bytes_to_int(bytes_buf)
print("Rx Length = {} ".format(bytes_length))
byte_data = receive_all(client_socket, int(bytes_length))
# convert jpg image to matix
g_decode_img = np.frombuffer(byte_data, dtype=np.uint8)
g_decode_img = cv2.imdecode(g_decode_img, cv2.COLOR_RGB2BGR)
g_copy_img = np.copy(g_decode_img)
cv2.imshow('Client', g_copy_img)
cv2.waitKey(1)
# convert Mat to byte for sending to client
ret, imgencoded = cv2.imencode('.jpg', g_copy_img)
byte_img = np.array(imgencoded)
int_len_byte_img = len(byte_img)
bytes_len_img = int_len_byte_img.to_bytes(4, byteorder='big')
client_socket.send(bytes_len_img)
client_socket.send(byte_img)
except IOError:
client_socket.close()
print("wait accept")
client_socket, addr = server_socket.accept()
print("accept to : ", addr[0], ":", str(addr[1]))
print('wait image')
server_socket.close()
if __name__ == "__main__":
run_server_cv()
뭔가 좀 부족한데 뭘까 ?
Author And Source
이 문제에 관하여(OpenCV 영상통신), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@zhemdrawer/OpenCV-영상통신저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)