首页 > 解决方案 > cv2 网络摄像头流仅显示前几行图像

问题描述

嘿,所以我编写了一个 Python 脚本来通过 UDP 将网络摄像头流式传输到其他设备。但是当我启动流时,只显示图像的前几行。即使我使用相同的变量将文件写入磁盘并显示它,我也会得到不同的结果。因为在保存的图像中颜色是正常的,但在实时图片中颜色是(我认为)反转的。我已经尝试过的:

服务器代码:

import numpy as np
from cv2 import cv2
import socket,json
MESSAGE = [0,0,0]
cap = cv2.VideoCapture(0)
a = 0
class NumpyEncoder(json.JSONEncoder):
    def default(self,obj):
        if isinstance(obj,np.ndarray):
            return obj.tolist()
        return json.JSONEncoder.default(self,obj)
while(True):
    ret, frame = cap.read()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    cv2.imshow('frame',frame)
    cv2.imwrite("test.jpg",frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
    UDP_IP = "192.168.1.147"
    UDP_PORT = 5005
    MESSAGE = json.dumps({"a" : frame[0], "b" : frame[1],"c" : frame[2]}, cls = NumpyEncoder)
    with open("test.txt","w") as f:
        f.write(MESSAGE)
        
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 16384)
    sock = socket.socket(socket.AF_INET, # Internet
                         socket.SOCK_DGRAM) # UDP
    sock.sendto(MESSAGE.encode(),(UDP_IP,UDP_PORT))
# When everything done, release the capture
cap.release()

客户:

import socket,json
from cv2 import cv2
import numpy as np
framecounter = 0
class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        return json.JSONEncoder.default(self, obj)
UDP_IP = "192.168.1.147"
UDP_PORT = 5005

sock = socket.socket(socket.AF_INET, # Internet
                     socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
    json_dump, addr = sock.recvfrom(65535)
    json_load = json.loads(json_dump.decode())
    new_rgb = np.asarray(json_load["a"]),np.asarray(json_load["b"]),np.asarray(json_load["c"])
    new_rgb = np.float32(new_rgb)
    cv2.imwrite("test.jpg",new_rgb)
    cv2.imshow("frame",new_rgb)
    cv2.resizeWindow("frame",(640,480))
    framecounter = framecounter + 1
    print("frame",framecounter)
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

标签: pythonopencvsockets

解决方案


cap.read() 的帧返回值只是流中的一个图像,它是一个大小矩阵(高度、宽度、通道),所以当你执行 frame[0] 时,你只会得到第一行矩阵。其次,您的编码效率低下,如果您想一次发送一个图像(帧),您可以将图像文件转储到套接字中。

这是我的实现,请注意,由于接收器是单线程的,如果它开始执行缓慢的操作(例如写入磁盘,计算机视觉),它可能会丢失几个数据包。在这种情况下,您应该创建另一个仅侦听该端口并写入队列的线程。

接收.py

import socket
import cv2
import io
import numpy as np
import traceback

DATAGRAM_SIZE = 1400 #bytes
PORT = 44000
end_bytes = bytes(17)
framecounter = 0

listening_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
listening_socket.bind(('', PORT))
while True:
    image_buffer = io.BytesIO() # faster than writing to file
    data, address = listening_socket.recvfrom(DATAGRAM_SIZE)
    while data != end_bytes:
        image_buffer.write(data)
        data, address = listening_socket.recvfrom(DATAGRAM_SIZE)
    image_buffer.seek(0)
    try: # image may be corrupted by loss of UDP packets
        img = cv2.imdecode(np.asarray(bytearray(image_buffer.read()), dtype=np.uint8), cv2.IMREAD_COLOR)
        cv2.imshow("received", img) # If the code gets slow here you may loose packets
    except Exception:
        traceback.print_exc()
    framecounter += 1
    print(framecounter)
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

listening_socket.close()

发件人.py

import socket
import cv2
import numpy
import time

DATAGRAM_SIZE = 1400
PORT = 44000
IP = "127.0.0.1"
end_bytes = bytes(17)

cap = cv2.VideoCapture(0)
sending_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while(True):
    ret, frame = cap.read()
    cv2.imshow("sent",frame)
    cv2.imwrite("img_to_send.jpg",frame) # You may use BytesIO
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
    with open("img_to_send.jpg", "rb") as f:
        data = f.read(DATAGRAM_SIZE)
        while data:
            sending_socket.sendto(data, (IP, PORT))
            data = f.read(DATAGRAM_SIZE)
        sending_socket.sendto(end_bytes, (IP, PORT))

sending_socket.close()
cap.release()

推荐阅读