2016년 5월 19일 목요일

[Python] Python을 이용한 OpenCV에서 TCP socket을 통해서 Image 전송하기.

Python을 이용한 OpenCV에서 TCP socket을 통해서 Image 전송하기.

TCP통신만 보면 일반적인 Python의 TCP통신 기법을 이용한다.
python의 tcp socket에서는 문자열을 보내고 받을 수 있는데, 이를 따르기 위해서 OpenCV에서는 Image를 문자열(string)으로 변환할 수 있다.
즉, 이미지 송신단에서는 OpenCV를 이용해서 캡처한 Image를 문자열로 변환한 뒤 TCP Socket으로 전송(send)한다.
이미지 수신단에서는 TCP Socket으로 수신한 문자열을 OpenCV를 이용해서 Image로 변환한다.

(출처 : http://stackoverflow.com/questions/20820602/image-send-via-tcp)

client.py (송신단)

#!/usr/bin/python
import socket
import cv2
import numpy

#연결할 서버(수신단)의 ip주소와 port번호
TCP_IP = 'localhost'
TCP_PORT = 5001

#송신을 위한 socket 준비
sock = socket.socket()
sock.connect((TCP_IP, TCP_PORT))

#OpenCV를 이용해서 webcam으로 부터 이미지 추출
capture = cv2.VideoCapture(0)
ret, frame = capture.read()

#추출한 이미지를 String 형태로 변환(인코딩)시키는 과정
encode_param=[int(cv2.IMWRITE_JPEG_QUALITY),90]
result, imgencode = cv2.imencode('.jpg', frame, encode_param)
data = numpy.array(imgencode)
stringData = data.tostring()

#String 형태로 변환한 이미지를 socket을 통해서 전송
sock.send( str(len(stringData)).ljust(16));
sock.send( stringData );
sock.close()

#다시 이미지로 디코딩해서 화면에 출력. 그리고 종료
decimg=cv2.imdecode(data,1)
cv2.imshow('CLIENT',decimg)
cv2.waitKey(0)
cv2.destroyAllWindows() 

server.py (수신단)

#!/usr/bin/python
import socket
import cv2
import numpy

#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

#수신에 사용될 내 ip와 내 port번호
TCP_IP = 'localhost'
TCP_PORT = 5001

#TCP소켓 열고 수신 대기
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(True)
conn, addr = s.accept()

#String형의 이미지를 수신받아서 이미지로 변환 하고 화면에 출력
length = recvall(conn,16) #길이 16의 데이터를 먼저 수신하는 것은 여기에 이미지의 길이를 먼저 받아서 이미지를 받을 때 편리하려고 하는 것이다.
stringData = recvall(conn, int(length))
data = numpy.fromstring(stringData, dtype='uint8')
s.close()
decimg=cv2.imdecode(data,1)
cv2.imshow('SERVER',decimg)
cv2.waitKey(0)
cv2.destroyAllWindows() 

댓글 11개:

  1. client로 webcam을 이용하여 동영상을 촬영하고 server로 영상을 전송하고 싶은데 어떻게 해야할까요?

    답글삭제
    답글
    1. 위의 예제는 클라이언트가 webcam으로 입력받은 이미지 한장을 서버로 보내는 것인데, 동영상은 연속된 이미지의 출력이라고 할 수 있으니, 위의 예제에서 이미지를 보내고 받는 과정을 반복문으로 묶어주시면 될것 같습니다.

      삭제
  2. result, imgencode = cv2.imencode('.jpg', frame, enocode_param) 부분에서
    raw image encoder error empty jpeg image (dnl not supported) in function throwOnEror라는 에러메시지가 출력되는데 검색을 해봐도 어떻게 손을 대야할지 모르겠습니다 혹시 아시는지 답변 부탁드립니다.

    답글삭제
    답글
    1. 답변이 너무 늦어서 죄송합니다. 음...해당 에러는 저도 본적이 없어서 모르겠는데 우선 이미지를 정상적으로 캡처 했는지 먼저 확인해 보시는건 어떤가요? 간단하게 캡처한 이미지를 창으로 띄워서 이미지가 나오는지 확인해보시는게 좋을 것 같습니다.

      삭제
  3. 작성자가 댓글을 삭제했습니다.

    답글삭제
  4. 파이썬 3 버전에서는 안되는건가요?
    stringData = recvall(conn, int(length))
    ValueError: invalid literal for int() with base 10: b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01'

    라고 뜨네요.

    검색해도 안나오고 ㅠㅠ

    답글삭제
    답글
    1. 제가 작성할때도 opencv관련해서는 파이썬3에 대한 레퍼런스를 잘 찾을수가 없어서 파이썬2.x 로 했었어요 ㅠㅠ 도움이 되지 못해서 송구스럽습니다..

      삭제
  5. 작성자가 댓글을 삭제했습니다.

    답글삭제
  6. 작성자가 댓글을 삭제했습니다.

    답글삭제
  7. 파이썬에서 인코드해서 윈도우에서 디코드하는데, 인코드된 데이터를 받는 거 까진 잘 됬는데, 윈도우에서 cv::imdecode 를 하면 결과값이 0x0 이네요 왜 그렇죠?

    답글삭제