반응형





파이썬의 TCP 소켓을 사용하여 웹캠에서 캡쳐한 이미지를 전송하는 서버와 클라이언트를 간단히 만들었습니다. 

웹캠으로부터 이미지 캡쳐는 OpenCV를 사용하였습니다.


서버에는 두 종류의 쓰레드를 생성합니다. 

웹캠으로부터 캡처한 이미지를  큐에 삽입하는 쓰레드와 클라이언트가 접속하면 큐에서 이미지를 꺼내어 클라이언트에 전송하는 쓰레드입니다. 



서버에서 이미지를 전송하기 전에 넘파이 배열을 압축한 후, 최종적으로   String으로 변환해야 하고

클라이언트에서는 수신된 String 데이터를 넘파이 배열로  변환하여 화면에 보여줍니다. 



서버 프로그램을 실행 후, 웹캠 영상이 화면에 보여지면

클라이언트 프로그램을 실행하세요.

여러 개 실행가능한데 몇 개 까지 가능한지 확인 안해봤습니다. 



파이썬에서 소켓 사용하는 방법에 대해서는 다음 포스트를 참고하세요.


파이썬 소켓 프로그래밍 - 클라이언트 / 서버 예제

https://webnautes.tistory.com/1381 





image-server.py


파이썬의 recv 함수는 수신될 데이터의 크기를 미리 알아야 하기 때문에 서버에서 전송할 이미지의 크기를 보내서 클라이언트에서 수신받을 준비를 하게 해놓고 이미지를 전송합니다. 


import socket
import cv2
import numpy
from queue import Queue
from _thread import *


enclosure_queue = Queue()


# 쓰레드 함수
def threaded(client_socket, addr, queue):

    print('Connected by :', addr[0], ':', addr[1])

    while True:

        try:
            data = client_socket.recv(1024)

            if not data:
                print('Disconnected by ' + addr[0],':',addr[1])
                break

            stringData = queue.get()
            client_socket.send(str(len(stringData)).ljust(16).encode())
            client_socket.send(stringData)

        except ConnectionResetError as e:

            print('Disconnected by ' + addr[0],':',addr[1])
            break
           
    client_socket.close()


def webcam(queue):


    capture = cv2.VideoCapture(0)

    while True:
        ret, frame = capture.read()

        if ret == False:
            continue


        encode_param=[int(cv2.IMWRITE_JPEG_QUALITY),90]
        result, imgencode = cv2.imencode('.jpg', frame, encode_param)

        data = numpy.array(imgencode)
        stringData = data.tostring()

        queue.put(stringData)

        cv2.imshow('image', frame)
       
        key = cv2.waitKey(1)
        if key == 27:
            break


HOST = '127.0.0.1'
PORT = 9999

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen()

print('server start')

start_new_thread(webcam, (enclosure_queue,))


while True:

    print('wait')


    client_socket, addr = server_socket.accept()
    start_new_thread(threaded, (client_socket, addr, enclosure_queue,))

server_socket.close()




image-client.py



import socket
import numpy as np
import cv2


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 = '127.0.0.1'
PORT = 9999

client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

client_socket.connect((HOST, PORT))


while True:

    message = '1'
    client_socket.send(message.encode())
 
    length = recvall(client_socket,16)
    stringData = recvall(client_socket, int(length))
    data = np.frombuffer(stringData, dtype='uint8')

    decimg=cv2.imdecode(data,1)
    cv2.imshow('Image',decimg)
   
    key = cv2.waitKey(1)
    if key == 27:
        break


client_socket.close()




참고

https://stackoverflow.com/questions/20820602/image-send-via-tcp


https://pymotw.com/3/queue/index.html




  

반응형

포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

여러분의 응원으로 좋은 컨텐츠가 만들어집니다.
지금 본 내용이 도움이 되었다면 유튜브 구독 부탁드립니다. 감사합니다 : )

유튜브 구독하기


제가 쓴 책도 한번 검토해보세요.

  1. 이시영 2019.10.09 16:37

    안녕하세요, 혹시 소켓 통신으로 받은 frame을 저장하는 방법이 없을까요?
    현재
    fcc = cv2.VideoWriter_fourcc('D', 'I', 'V', 'X')
    out = cv2.VideoWriter("output.avi", fcc, 25.0, (640, 480))
    을 미리 선언하고 받는 쪽의 imshow 다음에 out.write(decimg)을 한 상태인데,
    영상이 파일 생성만 되고 frame이 저장이 되진 않습니다.
    혹시 해결할 수 있는 방법이 있을까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.10.09 17:19 신고

      소켓 통신으로 이미지를 전송하는 거라면 다음 포스팅을 참고해보세요.

      TCP 소켓을 사용하여 웹캠의 이미지를 송수신하는 서버/클라이언트 예제
      https://webnautes.tistory.com/1382

    • 이시영 2019.10.09 18:07

      네 해당 글을 보고 문의 드린 내용입니다! 라즈베리파이 상에서 우분투 서버로 프레임을 전송하는 것까지는 성공했지만, 프레임을 동영상으로 저장하는 걸 해보려고 합니다! 해당 글에는 저장 관련 내용은 없어서 저렇게 문의를 드렸습니다!

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.10.09 19:14 신고

      OpenCV에서 동영상 파일 저장하는 방법을 사용하면 됩니다.
      다음 포스트의 2번을 참고하세요

      OpenCV Python 예제 - 동영상 다루기
      https://webnautes.tistory.com/577

  2. 신원민 2020.06.10 17:26

    위코드를 기준으로
    프레임마다 얼굴을 인식한뒤 얼굴부분만을 크롭해서 클라이언트로 보내게끔 수정을 했습니다.

    변수는 위와 동일하게 사용하였습니다.

    수신단쪽의 decimg 를 cv2의 imshow 를 통해 새로운 윈도우에 띄우면 sever 단에서 찍힌 사진과 똑같습니다.
    하지만 수신된 decimg 의 array 값을 pyplot 를 통해 띄우면 색이 달라져 문의드립니다.

    혹시 원인을 알수 있을까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.10 20:14 신고

      혹시 빨간색과 파란색이 바뀌어보이는건 아닌지 확인해보세요.

      BGR 과 RGB 순서가 다르기 때문입니다.

    • 2020.06.11 15:43

      비밀댓글입니다

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.11 18:35 신고

      클라이언트에서 보낸 문자열에 따라 다르게 동작시키면 될듯합니다

    • 2020.06.14 19:28

      비밀댓글입니다

  3. 궁금이 2020.09.08 12:11

    이미지 통신의 경우 이렇게 넘파이배열을 문자열로 압축하는 방식이 가장 빠른 방법인가요?

  4. 서동연 2020.09.08 15:00

    안녕하세요 올려주신 코드와 반대로 client에서 찍은 웹캠을 sever에서 받아서 출력시키는 코드를 수정하여 구현하려고 하고있습니다.

    data 처리를 위해서 recvall 함수를 thread함수 안에 넣어서 imshow를 하려고 했는데 잘 되지 않습니다.

    혹시 어떻게 하면 될까요??

    감사합니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.09.09 22:39 신고

      우선 문자열을 전송하는 것부터 진행해보세요..

      그 다음에 문제 없으면 이미지 전송으로 변환하면 될듯합니다.

    • BlogIcon 서동연 2020.09.11 11:42

      네 전의 글 보고 문자로 전송하는 것은 문제없었는데 이미지 전송시 자꾸 오류가 났었는데 queue를 활용안하고 struct 와 pickle을 활용하여 해결했습니다. 강의해주신 thread부분이 큰도움이 되었습니다 감사합니다

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.09.11 16:47 신고

      다행입니다

+ Recent posts