實(shí)現(xiàn)了從硬件udp推送照片到服務(wù)器,其他設(shè)備訪問(wèn)http://127.0.0.1:8080/1.mjpeg
查看圖片流的效果
學(xué)習(xí)方案
esp32cam 服務(wù)端遠(yuǎn)程視頻方案
米爾行車記錄儀 代碼
python引用庫(kù)
pillow
opencv
numpy
展示圖片推流
import cv2
import requests
import numpy as np
from io import BytesIO
from PIL import Image
res = requests.get('http://127.0.0.1:8080/1.mjpeg', stream=True)
print(res.status_code)
imageBytes = bytes()
for data in res.iter_content(chunk_size=300):
# 輸出data 查看每一張圖片的開(kāi)始與結(jié)尾审编,查找圖片的頭與尾截取jpg歧匈。并把剩余部分imageBytes做保存
imageBytes += data
a = imageBytes.find(b'\xff\xd8')
b = imageBytes.find(b'\xff\xd9')
if a != -1 and b != -1:
jpg = imageBytes[a:b+2]
imageBytes = imageBytes[b+2:]
bytes_stream = BytesIO(jpg)
img = Image.open(bytes_stream)
img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
cv2.imshow('img', img)
if cv2.waitKey(10) & 0XFF == ord('q'):
break
cv2.destroyAllWindows()
對(duì)視頻切片件炉,模擬硬件設(shè)備拍照獲取圖片
import cv2
import os
import threading
def video_to_frames(video_path, outPutDirName):
times = 0
# 提取視頻的頻率,每1幀提取一個(gè)
frame_frequency = 1
# 如果文件目錄不存在則創(chuàng)建目錄
if not os.path.exists(outPutDirName):
os.makedirs(outPutDirName)
# 讀取視頻幀
camera = cv2.VideoCapture(video_path)
while True:
times = times + 1
res, image = camera.read()
if not res:
print('not res , not image')
break
if times % frame_frequency == 0:
cv2.imwrite(outPutDirName + '\\' + str(times) + '.jpg', image)
print('圖片提取結(jié)束')
camera.release()
if __name__ == "__main__":
input_dir = r'D:\video' # 輸入的video文件夾位置
save_dir = r'D:\video\img' # 輸出圖片到當(dāng)前目錄video文件夾下
count = 0 # 視頻數(shù)
for video_name in os.listdir(input_dir):
video_path = os.path.join(input_dir, video_name)
outPutDirName = os.path.join(save_dir, video_name[:-4])
threading.Thread(target=video_to_frames, args=(video_path, outPutDirName)).start()
count = count + 1
print("%s th video has been finished!" % count)
模擬硬件設(shè)備udp圖片推流到服務(wù)器
import socket
import os
import sys
# 服務(wù)器的地址
server_address = ('127.0.0.1', 8000)
def send(dir_name, data_format, file_name):
# 與接收端建立socket通信
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # AF_INET(TCP/IP – IPv4)協(xié)議
sock.connect(server_address)
# 每次通信都帶一個(gè)通信頭,表明數(shù)據(jù)源的類型(紅外還是可見(jiàn)光)走净,要保存數(shù)據(jù)幀的文件夾名file_name
# 你可以不要數(shù)據(jù)格式孤里,這里可以定義成你自己的形式捌袜,也算是一種安全機(jī)制
sock.send('{}|{}'.format(data_format, file_name).encode()) # 默認(rèn)編碼 utf-8,發(fā)送文件長(zhǎng)度和文件名
reply = sock.recv(1024)
# 按照文件名排序炸枣,0.png,1.png
file_list = os.listdir(dir_name)
file_list.sort(key=lambda x: int(x[:-4]))
if 'ok' == reply.decode(): # 確認(rèn)一下服務(wù)器get到文件長(zhǎng)度和文件名數(shù)據(jù)
i = 0
print(len(file_list))
for file_name in file_list:
data = file_deal(os.path.join(dir_name, file_name))
sock.send('{}|{}'.format(len(data), file_name).encode())
sock.recv(1024)
go = 0
total = len(data)
while go < total: # 發(fā)送文件
data_to_send = data[go:go + total // 2]
sock.send(data_to_send)
go += len(data_to_send)
sock.recv(1024).decode()
i += 1
if i < len(file_list):
sock.send(b'continue')
sock.send(b'over')
sock.close()
sys.exit(0)
def file_deal(file_path): # 讀取文件的方法
mes = b''
try:
file = open(file_path, 'rb')
mes = file.read()
except:
print('error{}'.format(file_path))
else:
file.close()
return mes
# D:\video\test 內(nèi)部是命名有序的一組圖片
send(r'D:\video\test', '', 'jpg')
模擬服務(wù)器接收硬件設(shè)備udp圖片推流
import socket
import os
import cv2
import numpy as np
'''
接收udp 推送過(guò)來(lái)的圖片 20221213
'''
LOCAL_IP = '127.0.0.1' # 本機(jī)測(cè)試使用ip,局域網(wǎng)中使用需更換ip
PORT = 8000 # 隨意指定一個(gè)端口
def server():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # socket.AF_INET 指ipv4 socket.SOCK_STREAM 使用tcp協(xié)議
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 設(shè)置端口
sock.bind((LOCAL_IP, PORT)) # 綁定端口
sock.listen(3) # 監(jiān)聽(tīng)端口
while True:
sc, sc_name = sock.accept() # 當(dāng)有請(qǐng)求到指定端口是 accept()會(huì)返回一個(gè)新的socket和對(duì)方主機(jī)的(ip,port)
print('收到{}機(jī)器請(qǐng)求'.format(sc_name))
info = sc.recv(1024) # 接受客戶端發(fā)來(lái)的協(xié)議頭候引,區(qū)分?jǐn)?shù)據(jù)源
# 安全處理:如果不是以這個(gè)協(xié)議頭開(kāi)始澄干,認(rèn)為是非法接入柠傍,就直接斷掉。這里可以自己定義一些安全消息機(jī)制
print(info)
try:
data_format, directory_name = info.decode().split("|")
sc.send(b'ok') # 表示收到文件長(zhǎng)度和文件名
except:
print('協(xié)議頭不對(duì)从媚,自動(dòng)斷開(kāi)連接')
sc.close()
continue
if not os.path.exists(directory_name):
os.mkdir(directory_name)
# 協(xié)議頭正確之后拜效,不斷接收發(fā)來(lái)的數(shù)據(jù)幀
while True:
head_info = sc.recv(1024)
# print(data_info)
length, file_name = head_info.decode().split('|')
sc.send(b'ok')
if length and file_name:
print(file_name)
newfile = open(os.path.join(directory_name, file_name), 'wb') # 這里可以使用從客戶端解析出來(lái)的文件名
file = b''
total = int(length)
get = 0
while get < total: # 接收文件
data = sc.recv(total//2)
file += data
get = get + len(data)
sc.send(b'ok')
print('應(yīng)該接收{(diào)},實(shí)際接收{(diào)}'.format(length, len(file)))
if file:
imgstring = np.array(file).tobytes()
imgstring = np.asarray(bytearray(imgstring), dtype="uint8")
image = cv2.imdecode(imgstring, cv2.IMREAD_COLOR)
# # 展示多個(gè)
# cv2.imshow("mutil_pic", image)
# # 等待關(guān)閉
# cv2.waitKey(0)
print('actually length:{}'.format(len(file)))
newfile.write(file[:])
newfile.close()
reply = sc.recv(1024)
if reply.decode() == "over":
break
server()
模擬服務(wù)器提供mjpeg 圖片推流服務(wù)
# -*- coding: utf-8 -*-
# MJPEG Server for the webcam
"""
mjpeg 推流服務(wù) 20221213
"""
import cgi, time
from os import curdir, sep
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
import cv2 as cv
import re
import sys
import socket
import os
# capture = cv.CaptureFromCAM(0)
# img1 = cv.QueryFrame(capture)
#
# if img1 is None:
# print("No WebCam Found!")
# sys.exit()
import numpy as np
if len(sys.argv) < 2:
print("Usage : webcamserver <quality> <port>")
cameraQuality = 100
port = 8080
else:
cameraQuality = sys.argv[1]
port = int(sys.argv[2])
def file_deal(file_path): # 讀取文件的方法
mes = b''
try:
file = open(file_path, 'rb')
mes = file.read()
except:
print('error{}'.format(file_path))
else:
file.close()
return mes
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
global cameraQuality
try:
self.path = re.sub('[^.a-zA-Z0-9]', "", str(self.path))
if self.path == "" or self.path is None or self.path[:1] == ".":
return
if self.path.endswith(".html"):
f = open(curdir + sep + self.path)
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(f.read())
f.close()
return
if self.path.endswith(".mjpeg"):
self.wfile.write(b"HTTP/1.1 200 OK\r\n")
self.wfile.write(b'Content-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n')
file_list = os.listdir(r'D:\video\test')
file_list.sort(key=lambda x: int(x[:-4]))
for file_name in file_list:
data = file_deal(os.path.join(r'D:\video\test', file_name))
self.wfile.write(b"--frame\r\nContent-Type: image/jpeg\r\n\r\n" + data)
# self.wfile.write(b'--frame\r\n')
# self.wfile.write(b"Content-Type: image/jpeg\r\n\r\n")
# self.wfile.write(data)
time.sleep(0.025)
return
if self.path.endswith(".jpeg"):
f = open(curdir + sep + self.path)
self.send_response(200)
self.send_header('Content-type', 'image/jpeg')
self.end_headers()
self.wfile.write(f.read())
f.close()
return
return
except IOError:
self.send_error(404, 'File Not Found: %s' % self.path)
def do_POST(self):
global rootnode, cameraQuality
try:
ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
if ctype == 'multipart/form-data':
query = cgi.parse_multipart(self.rfile, pdict)
self.send_response(301)
self.end_headers()
upfilecontent = query.get('upfile')
print("filecontent", upfilecontent[0])
value = int(upfilecontent[0])
cameraQuality = max(2, min(99, value))
self.wfile.write("<HTML>POST OK. Camera Set to<BR><BR>");
self.wfile.write(str(cameraQuality));
except:
pass
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
# class ThreadedHTTPServer(HTTPServer):
"""Handle requests in a separate thread."""
myname = socket.getfqdn(socket.gethostname())
myaddr = socket.gethostbyname(myname)
def main():
while 1:
try:
server = ThreadedHTTPServer(('0.0.0.0', port), MyHandler)
print('Starting httpServer...')
print('See <Local IP>:' + str(port) + '/1.mjpeg')
server.serve_forever()
except KeyboardInterrupt:
print('^C received, shutting down server')
server.socket.close()
if __name__ == '__main__':
main()