Reputation: 11
I try to send and receive videos with Raspberry Pi on the computer, and it works well to transmit the video from Raspberry Pi (client) to the computer (server) and store the video on the server
I get a numpy._core error when I send the video from the server to the client, how do I fix it?
I can't erase numpy and reinstall it, and I can't do anything because the pip has an error without knowing what it is, so please tell me a solution
--Server--
import socket
import cv2
import struct
import pickle
import threading
from datetime import datetime
import os
import math
# 최대 클라이언트 수 설정
MAX_CLIENTS = 10
# TCP 서버 설정
host_ip = "0.0.0.0"
port = 9999
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((host_ip, port))
server_socket.listen(MAX_CLIENTS)
server_socket.settimeout(1.0) # Ctrl + C로 종료 가능하게 타임아웃 설정
print("서버 실행 중")
clients = []
# 현재 서버 파일의 디렉토리 경로를 가져옴
server_dir = os.path.dirname(os.path.abspath(__file__))
# 디렉토리 경로 설정 (서버 파일 위치에 'SaveRecord' 디렉토리 생성)
save_directory = os.path.join(server_dir, "SaveRecord")
# 디렉토리가 없으면 생성
if not os.path.exists(save_directory):
os.makedirs(save_directory)
# 클라이언트 관리 클래스
class ClientManager:
def __init__(self):
self.client_ids = {}
def add_client(self, conn, addr):
client_ip = addr[0]
client_id = int(client_ip.split(".")[-1]) # IP의 마지막 숫자를 ID로 사용
self.client_ids[client_id] = conn
return client_id
def remove_client(self, client_id):
if client_id in self.client_ids:
del self.client_ids[client_id]
def get_all_client_ids(self):
return "_".join(map(str, self.client_ids.keys())) # 클라이언트 ID를 "_"로 구분된 문자열로 반환
client_manager = ClientManager()
def get_grid_size(n):
if n <= 1:
return (1, 1)
elif n == 2:
return (1, 2)
elif n <= 4:
return (2, 2)
elif n <= 6:
return (2, 3)
elif n <= 9:
return (3, 3)
elif n <= 12:
return (3, 4)
elif n <= 16:
return (4, 4)
else:
# 세로는 4칸 고정
rows = 4
# 4칸을 기준으로 가로를 늘림
cols = math.ceil(n / rows)
return (rows, cols)
# 클라이언트에게 영상을 송신하는 함수
def send_video_to_clients(frame):
# 프레임 크기 640x480으로 리사이즈
frame = cv2.resize(frame, (640, 480))
for conn in client_manager.client_ids.values():
try:
frame_data = pickle.dumps(frame)
message_size = struct.pack("Q", len(frame_data))
conn.sendall(message_size + frame_data)
except Exception as e:
print(f"클라이언트로 영상을 전송하는 도중 오류 발생: {e}")
def handle_client(conn, addr):
client_id = client_manager.add_client(conn, addr) # 클라이언트 ID 부여
print(f"[새 연결] {addr} (ID: {client_id}) 클라이언트 연결됨")
data = b""
payload_size = struct.calcsize("Q")
# 🔴 비디오 저장 설정 (코덱: XVID, 해상도 1920x1080, FPS: 20)
fourcc = cv2.VideoWriter_fourcc(*"XVID")
# 현재 날짜와 시간 추가 (형식: client_X_YYYYMMDD_HHMMSS.avi)
current_time = datetime.now().strftime("%Y%m%d_%H%M%S")
video_filename = f"{save_directory}/Record_{current_time}.avi"
video_writer = None
frames = {} # 각 클라이언트의 영상 프레임을 저장할 딕셔너리
try:
while True:
while len(data) < payload_size:
packet = conn.recv(8)
if not packet:
raise ConnectionResetError("클라이언트 연결 끊김")
data += packet
packed_msg_size = data[:payload_size]
data = data[payload_size:]
msg_size = struct.unpack("Q", packed_msg_size)[0]
while len(data) < msg_size:
packet = conn.recv(4096)
if not packet:
raise ConnectionResetError("클라이언트 연결 끊김")
data += packet
frame_data = data[:msg_size]
data = data[msg_size:]
frame = pickle.loads(frame_data)
# 🔴 프레임 크기 확인 후 비디오 저장 객체 생성
if video_writer is None:
height, width, _ = frame.shape
rows, cols = get_grid_size(len(client_manager.client_ids))
screen_width = 1920
screen_height = 1080
cell_width = screen_width // cols
cell_height = screen_height // rows
# 전체화면 크기와 맞게 비디오 객체 생성
video_writer = cv2.VideoWriter(video_filename, fourcc, 20.0, (screen_width, screen_height))
# 연결된 클라이언트 ID에 맞는 그리드에 영상 배치
frames[client_id] = cv2.resize(frame, (cell_width, cell_height))
# 그리드에 맞게 모든 클라이언트의 영상을 합침
grid_frame = None
rows, cols = get_grid_size(len(client_manager.client_ids))
for i, frame in frames.items():
row = (i - 1) // cols
col = (i - 1) % cols
# 그리드에서 각 클라이언트의 영상을 합치기 위한 위치 계산
y1, y2 = row * cell_height, (row + 1) * cell_height
x1, x2 = col * cell_width, (col + 1) * cell_width
if grid_frame is None:
grid_frame = frame
else:
grid_frame[y1:y2, x1:x2] = frame
# 영상 저장
video_writer.write(grid_frame)
# 연결된 클라이언트들 영상 화면 표시
cv2.imshow(f"Clients ({client_ids})", grid_frame)
# 모든 클라이언트에게 영상 송신
send_video_to_clients(grid_frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
except (ConnectionResetError, BrokenPipeError):
print(f"[연결 종료] {addr} (ID: {client_id}) 클라이언트 연결 끊김")
finally:
conn.close()
cv2.destroyWindow(f"Clients ({client_ids})")
clients.remove(conn)
# 🔴 비디오 저장 종료
if video_writer is not None:
video_writer.release()
# 클라이언트 정보 제거
client_manager.remove_client(client_id)
# 클라이언트들 상태에 따라 저장된 영상 파일 이름 수정
current_time = datetime.now().strftime("%Y%m%d_%H%M%S")
video_filename = f"{save_directory}/Record_{current_time}.avi"
# 서버 실행
try:
# 카메라에서 영상을 실시간으로 캡처하는 코드 추가
cap = cv2.VideoCapture(0) # 기본 카메라 사용 (0번 카메라)
if not cap.isOpened():
print("카메라를 열 수 없습니다.")
exit()
while True:
try:
conn, addr = server_socket.accept()
except socket.timeout:
continue # timeout 발생하면 다시 accept 시도
# 현재 연결된 클라이언트 수가 최대 클라이언트 수 이상이면 연결 거절
if len(clients) >= MAX_CLIENTS:
print(f"[연결 거부] 클라이언트 수가 최대 {MAX_CLIENTS}명에 도달했습니다. {addr} 연결 거부.")
conn.close()
continue
clients.append(conn)
client_thread = threading.Thread(target=handle_client, args=(conn, addr))
client_thread.start()
# 카메라로부터 프레임 캡처
ret, frame = cap.read()
if not ret:
print("프레임을 읽을 수 없습니다.")
break
# 연결된 모든 클라이언트에게 실시간 영상 송신
send_video_to_clients(frame)
except KeyboardInterrupt:
print("\n[서버 종료] Ctrl+C 입력 감지됨. 모든 연결 닫기...")
for conn in clients:
conn.close()
server_socket.close()
print("[서버 종료 완료]")
--client--
import socket
import cv2
import struct
import pickle
import threading
import time
from picamera2 import Picamera2
# 카메라 초기화
picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration(main={"size": (640, 480)}))
picam2.start()
time.sleep(2) # 카메라 안정화를 위해 약간의 대기 시간 추가
server_ip = "192.168.219.50" # 서버 IP
server_port = 9999 # 서버 포트
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((server_ip, server_port))
def receive_video():
"""서버에서 수신한 영상을 받아서 화면에 출력하는 함수"""
try:
data = b""
payload_size = struct.calcsize("Q")
while True:
# 데이터의 크기만큼 수신되도록 보장
while len(data) < payload_size:
packet = client_socket.recv(4096)
if not packet:
break
data += packet
if len(data) < payload_size:
break
packed_msg_size = data[:payload_size]
data = data[payload_size:]
msg_size = struct.unpack("Q", packed_msg_size)[0]
while len(data) < msg_size:
packet = client_socket.recv(4096)
if not packet:
break
data += packet
frame_data = data[:msg_size]
data = data[msg_size:]
frame = pickle.loads(frame_data)
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
cv2.imshow("Received Video", frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
except Exception as e:
print(f"[오류] 영상 수신 중 문제 발생: {e}")
finally:
cv2.destroyAllWindows()
def send_video():
"""카메라에서 영상을 캡처하여 서버에 송신하는 함수"""
try:
while True:
frame = picam2.capture_array()
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
data = pickle.dumps(frame)
message_size = struct.pack("Q", len(data))
client_socket.sendall(message_size + data)
except Exception as e:
print(f"[오류] 영상 송신 중 문제 발생: {e}")
# 수신 스레드 시작
receive_thread = threading.Thread(target=receive_video, daemon=True)
receive_thread.start()
# 송신 함수 호출
send_video()
The content 'no module named numpy._core' keeps happening, even if you reinstall numpy, it's still like this, even if you try sudo apt update upgrade and reinstall it, please tell me the solution
Upvotes: 0
Views: 43