使用 python 3.4 opencv 3.2 使用 usbcam 进行套接字编程

Socket programming with usbcam using python 3.4 opencv 3.2

我正在做一个项目,需要在服务器端使用 USB 网络摄像头 在客户端直播视频。

我正在使用 (Opencv 3.2.0 + python 3.4.3).

下面给出的代码工作正常,我想知道这段代码实际如何工作以及它如何将帧传输到客户端。

此代码存在延迟,以及如何克服该延迟。我试图设置分辨率,但它在客户端给出错误,如([错误]:新数组的总大小必须不变)。我将它设置为默认分辨率(即640*480)它工作正常。

Help me 
    1. to set the resolution. -answered
    2. why dtype uint8 is used? -answered
    3. what is role fileDescriptor? -answered

更新问题:

  1. 在服务器端 - 我遇到类似的问题(需要按两次 ctrl+c 才能停止服务器 - 为什么会这样) - new
  2. 服务器或者运行成功(即,对于第一个 未连接第二 连接第三时间越来越停止第四时间运行-为什么它发生了吗? - new
  3. 如何减少延迟? -

让我们看看谁会回答所有这些问题!!!

服务器:

import cv2
import time
import json
import socket
import base64
import numpy as np
from threading import Thread

SERVER_IP = "x.x.x.x"
SERVER_PORT = xxxx
MAX_NUM_CONNECTIONS = 20
DEVICE_NUMBER = 0

class ConnectionPool(Thread):

    def __init__(self, ip_, port_, conn_, device_):
        Thread.__init__(self)
        self.ip = ip_
        self.port = port_
        self.conn = conn_
        self.device = device_
        print("[+] New server socket thread started for " + self.ip + ":" +str(self.port))

    def run(self):
        try:
            while True:
                ret, frame = self.device.read()
                a = b'\r\n'
                data = frame.tostring()
                da = base64.b64encode(data)
                self.conn.sendall(da + a)

        except Exception as e:
            print("Connection lost with " + self.ip + ":" + str(self.port) +"\r\n[Error] " + str(e.message))
        self.conn.close()

if __name__ == '__main__':
    cap = cv2.VideoCapture(DEVICE_NUMBER)
    print("Waiting connections...")
    connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    connection.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    connection.bind((SERVER_IP, SERVER_PORT))
    connection.listen(MAX_NUM_CONNECTIONS)
    while True:
        (conn, (ip, port)) = connection.accept()
        thread = ConnectionPool(ip, port, conn, cap)
        thread.start()
    connection.close()
    cap.release()

客户:

import cv2
import socket
import base64
import numpy as np

IP_SERVER = "x.x.x.x"
PORT_SERVER = xxxx
TIMEOUT_SOCKET = 10
SIZE_PACKAGE = 4096


IMAGE_HEIGHT = 480
IMAGE_WIDTH = 640
COLOR_PIXEL = 3  # RGB


if __name__ == '__main__':
    connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    connection.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    connection.settimeout(TIMEOUT_SOCKET)
    connection.connect((IP_SERVER, PORT_SERVER))

    while True:
        try:
            fileDescriptor = connection.makefile(mode='rb')
            result = fileDescriptor.readline()
            fileDescriptor.close()
            result = base64.b64decode(result)
            frame = np.fromstring(result, dtype=np.uint8)
            frame_matrix = np.array(frame)
            frame_matrix = np.reshape(frame_matrix, (IMAGE_HEIGHT, IMAGE_WIDTH,COLOR_PIXEL))
            cv2.imshow('Window title', frame_matrix)

            if cv2.waitKey(1) & 0xFF == ord('q'):
                break

        except Exception as e:
            print("[Error] " + str(e))

    connection.close()
  1. to set the resolution.

您必须在服务器端和客户端这两个地方进行更改。您遇到的错误很可能来自 reshape 函数。此函数将从图像中获取数据并对其进行整形,这意味着数据将保持不变,只有大小会发生变化......在这种情况下,它用于将一维数据数组更改为二维矩阵 3 通道矩阵(但是数据顺序不变)。怎么改,得先在server部分改。

它说的地方

ret, frame = self.device.read()

之后可以添加OpenCV的resize功能:

frame = cv2.resize(frame ,(width/2, height/2), interpolation = cv2.INTER_LINEAR )

这将减半。现在在客户端你可以减少到:

IMAGE_HEIGHT = 480 / 2
IMAGE_WIDTH = 640 / 2
  1. why dtype uint8 is used?

这来自OpenCV (BGR) 默认使用的图像表示,这意味着每个像素颜色由 3 个通道表示,蓝绿色和红色。每个通道的值都在 0-255 之间,这意味着它可以用 8 位表示,这就是 dtype uint8 的原因。稍后函数 reshape 将从 3 个连续值(COLOR_PIXEL 值)创建像素。

在这部分中,代码读取一行文本,这是图像数据并将其放入一维数组中。这将表明该行的每个 8 位都是一个值,应该被视为一个整数。

  1. what is role fileDescriptor?

这是一种从套接字读取数据的方法。参见documentation。这样你就可以使用 readline,并获得由换行符限制的数据块。在你的情况下 '\r\n'。查看行:

a = b'\r\n'
data = frame.tostring()
da = base64.b64encode(data)
self.conn.sendall(da + a)

a是return字符,在整个图像数据以字符串表示并用base 64编码后发送。