背景
引言:近幾年來,談起發展最火熱的幾個關鍵詞必然是人工智能、大數據以及物聯網的萬物互聯、邊緣計算等等了。而今天,我們就將利用Python實現物聯網下的數據傳輸功能。主要的內容包括:本地視頻傳輸到服務器、視頻傳輸到手機實時顯示、以及文本傳輸等方式
物聯網是新一代信息技術的重要組成部分,也是"信息化"時代的重要發展階段。顧名思義,物聯網就是物物相連的互聯網。這有兩層意思:其一,物聯網的核心和基礎仍然是互聯網,是在互聯網基礎上的延伸和擴展的網絡;其二,其用戶端延伸和擴展到了任何物品與物品之間,進行信息交換和通信,也就是物物相息。物聯網通過智能感知、識別技術與普適計算等通信感知技術,廣泛應用於網絡的融合中,也因此被稱為繼計算機、互聯網之后世界信息產業發展的第三次浪潮。而物聯網最為核心的功能便是數據傳輸功能,利用互聯網實現數據在任何可以接受數據的設備平台上達到傳輸效果,其中設備可以包括:本地PC、服務器、樹莓派、手機、手環等等。
模塊介紹
首先我們使用的Python版本是3.6.5所用到的模塊如下:
-
1.Opencv模塊:在這里我們用來讀取視頻流數據,以及圖片或者是視頻的編碼解碼和數據視頻的顯示;
-
2.Numpy模塊:在這里用來和圖片解碼結合使用進行數據運算;
-
3.Socket模塊:Socket又稱"套接字",應用程序通常通過"套接字"向網絡發出請求或者應答網絡請求,使主機間或者一台計算機上的進程間可以通訊。
-
4.Flask框架:Flask是一個Python編寫的Web 微框架,讓我們可以使用Python語言快速實現一個網站或Web服務。
2.1 視頻傳輸服務器
客戶端通過opencv讀取本地攝像頭數據,然后編碼成數據流格式,利用socket實現向服務端的發送,客戶端代碼如下:
#客戶端代碼
import socket
import threading
import cv2
import numpy as np
#接受服務器返回的數據的函數
def recvlink(client):
while True:
msg=client.recv(1024)
print('Ubuntu say: '+msg.decode('utf-8'))
def main():
#創建ipv4的socket對象,使用TCP協議(SOCK_STREAM)
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#設置服務器ip地址,注意應該是服務器的公網ip
host='ip地址'
#設置要發送到的服務器端口,需要在雲服務器管理界面打開對應端口的防火牆
port=端口
#建立TCP協議連接,這時候服務器就會監聽到到連接請求,並開始等待接受client發送的數據
client.connect((host,port))
#建立連接后,服務器端會返回連接成功消息
start_msg=client.recv(1024)
print(start_msg.decode('utf-8'))
#開啟一個線程用來接受服務器發來的消息
t=threading.Thread(target=recvlink,args=(client,))
t.start()
cap = cv2.VideoCapture(0)
quality = 25 # 圖像的質量
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), quality]
while (cap.isOpened()):
ret, frame = cap.read()
if ret == True:
img_encode = cv2.imencode(".jpg", frame, encode_param)[1]
data_encode = np.array(img_encode)
str_encode = data_encode.tostring()
print(str_encode)
print(len(str_encode))
#輸入要發送的信息
sendmsg="kehu"
#向服務器發送消息
client.send(str_encode)
if sendmsg=='quit':
break
#結束時關閉客戶端
client.close()
if __name__ == '__main__':
main()
服務器端通過設置bufSize防止出現粘包,利用socket接收數據流,然后解碼成為圖片,並實時顯示:
#服務器端
import socket
import threading
import numpy as np
import cv2
#接受客戶端消息函數
def recv_msg(clientsocket):
global temp
while True:
# 接受客戶端消息,設置一次最多接受1024字節的數據
recv_msg = clientsocket.recv(10240)
# 把接收到的東西解碼
msg = np.fromstring(recv_msg, np.uint8)
img_decode = cv2.imdecode(msg, cv2.IMREAD_COLOR)
try:
s=img_decode.shape
img_decode=img_decode
temp=img_decode
except:
img_decode=temp
pass
cv2.imshow('SERVER', img_decode)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
def main():
#創建服務器端socket對象 ipv4 + TCP協議,和客戶端一樣
socket_server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 注意注意注意,我們要綁定監聽的地址和端口。服務器可能有多塊網卡,可以綁定到某一塊網卡的IP地址上,也可以用0.0.0.0綁定到所有的網絡地址
# 還可以用127.0.0.1綁定到本機地址。127.0.0.1是一個特殊的IP地址,表示本機地址,如果綁定到這個地址,客戶端必須同時在本機運行才能連接,也就是說,外部的計算機無法連接進來。
# 這個程序中host使用'0.0.0.0'或服務器內網ip地址都可以,我這里就使用了內網ip地址
#host='0.0.0.0'
host=''
#設置被監聽的端口號,小於1024的端口號不能使用,因為他們是Internet標准服務的端口號
port=
#綁定地址
socket_server.bind((host,port))
#設置最大監聽數,也就是最多可以同時響應幾個客戶端請求,一般配合多線程使用
socket_server.listen(5)
#等待客戶端連接,一旦有了連接就立刻向下執行,否則等待
#accept()函數會返回一個元組,第一個元素是客戶端socket對象,第二個元素是客戶端地址(ip地址+端口號)
clientsocket,addr=socket_server.accept()
# 有了客戶端連接后之后才能執行以下代碼,我們先向客戶端發送連接成功消息
clientsocket.send('你現在已經連接上了服務器啦,我們來聊天吧!'.encode('utf-8'))
# 和客戶端一樣開啟一個線程接受客戶端的信息
t=threading.Thread(target=recv_msg,args=(clientsocket,))
t.start()
'''
# 發送消息
while True:
reply="cer"
clientsocket.send(reply.encode('utf-8'))
clientsocket.close()
'''
if __name__=='__main__':
main()
2.2 視頻傳輸到手機
可以利用opencv讀取視頻或是攝像頭,進行編解碼后傳輸。代碼如下:
from flask import Flask, render_template, Response
import cv2
import time
class VideoCamera(object):
def __init__(self):
# 通過opencv獲取實時視頻流
self.video = cv2.VideoCapture(0)
def __del__(self):
self.video.release()
def get_frame(self):
try:
image=cv2.imread("1.jpg")
ceshi = image.shape
global temp
temp=image
# 因為opencv讀取的圖片並非jpeg格式,因此要用motion JPEG模式需要先將圖片轉碼成jpg格式圖片
ret, jpeg = cv2.imencode('.jpg', image)
except:
image = temp
# 因為opencv讀取的圖片並非jpeg格式,因此要用motion JPEG模式需要先將圖片轉碼成jpg格式圖片
ret, jpeg = cv2.imencode('.jpg', image)
return jpeg.tobytes()
app = Flask(__name__)
@app.route('/') # 主頁
def index():
# jinja2模板,具體格式保存在index.html文件中
return render_template('index.html')
def gen(camera):
while True:
#time.sleep(0.5)
frame = camera.get_frame()
# 使用generator函數輸出視頻流, 每次請求輸出的content類型是image/jpeg
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
@app.route('/video_feed') # 這個地址返回視頻流響應
def video_feed():
return Response(gen(VideoCamera()),
mimetype='multipart/x-mixed-replace; boundary=frame')
圖片形成視頻流傳輸flash
由於手機端不方便運行Python程序,我們可以利用flask搭建視頻傳輸網頁,再利用opencv保存圖片更新圖片,以及flask更新圖片實現視頻傳輸效果。
#!/usr/bin/env python
from importlib import import_module
import os
from flask import Flask, render_template, Response
# import camera driver
if os.environ.get('CAMERA'):
Camera = import_module('camera_' + os.environ['CAMERA']).Camera
else:
from camera import Camera
# Raspberry Pi camera module (requires picamera package)
# from camera_pi import Camera
app = Flask(__name__)
@app.route('/')
def index():
"""Video streaming home page."""
return render_template('index.html')
def gen(camera):
"""Video streaming generator function."""
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
@app.route('/video_feed')
def video_feed():
"""Video streaming route. Put this in the src attribute of an img tag."""
return Response(gen(Camera()),
mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
app.run(host='0.0.0.0', threaded=True)