python中使用flask實現與linux服務器的數據交互

前段時間使用opencv的時候,想在pycharm中顯示服務器端代碼運行處理後的圖片或者視頻,但是報錯"can not connect X server"。之前使用了遠程桌面的方法,直接訪問遠程服務端的桌面,在遠程直接編譯顯示處理後的圖片。
鏈接如下:ubuntu16使用Remmina訪問遠程linux服務器桌面
但是這個方法對於服務器在雲上的程序員來說或許不是很友好,於是在百度後,發現了可以通過flask庫,把我們要運行的代碼設置爲api,通過訪問該api,可以從服務端返回圖片數據到本地,之後本地通過解碼後即可顯示。
話不多說,下面我用ip攝像頭獲取的圖片的代碼說明下如何操作。

本地客戶端中的代碼如下

import requests
import cv2
import base64
import json
import  numpy

#這是我們要訪問的API地址以及端口
url = "http://192.168.zzz.xxx:yyyy" 
#把opencv讀(read)到的圖的像素矩陣轉爲base64編碼
def image_to_base64(img_np):
    #在對像素矩陣進行base64編碼時,需要先把圖片編碼成十六進制數據流
    img_code = cv2.imencode('.jpg', img_np)[1]
    img_code64 = base64.b64encode(img_code)
    return img_code64
    
#base64編碼轉爲opencv可以show的像素矩陣
def base64_to_img(base64code):
    #需要先解碼base64爲十六進制數據流
    img_data = base64.b64decode(base64code)
    #把十六進制轉化爲opencv可以解碼的十進制整型數據流
    img_array = numpy.fromstring(img_data, numpy.uint8)
    #解碼爲mat像素矩陣
    img =cv2.imdecode(img_array, cv2.COLOR_RGB2BGR)
    return img
    
#byte數據轉爲字符串
def byte_to_str(byte):
    str_ = str(byte)[2:]
    return str_
    
#字符串轉爲byte數據
def str_to_byte(str_data):
    byte = bytes(str_data, encoding='utf8')
    return byte
    
#通過post把攝像頭的圖片上傳到服務端
def post_ipcam(img_array):
    #這裏我們使用了json數據,所以要把base64編碼轉化爲字符串
    img_64code = str(image_to_base64(img_array))[2:]
    res = {"image": img_64code} 
    json_res = json.dumps(res)
    result = requests.post(url, data=json_res) #result爲遠程服務端處理後返回的結果
    return result

rtsp = "rtsp://攝像頭賬戶:攝像頭密碼@ip攝像頭的地址和端口/MPEG/ch1/main/av_stream"
camera = cv2.VideoCapture(rtsp)
while True:
    #img_array是opencv讀取到的像素矩陣
    ret_val, img_array = camera.read()
    camera.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter.fourcc('M', 'J', 'P', 'G'))
    #之前使用攝像頭rtsp流遇到斷流的情況,於是現在都留了一手,斷流後再重新建立rtsp流
    if not ret_val: 
        camera = cv2.VideoCapture(rtsp)
        camera.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter.fourcc('M', 'J', 'P', 'G'))
        ret_val, img_array = camera.read()
        continue
    res = post_ipcam(img_array)
    #其中res返回的是處理後的圖像的base64編碼的字符串
    res_img_b64bytes = res._content 
    #把base64編碼解碼爲opencv可以show的像素矩陣
    img = base64_to_img(res_img_b64bytes)   
    #把圖片show出來就可以了,完美解決can not connect to X server
    cv2.imshow('', img)
    cv2.waitKey(1)

服務端中的代碼如下

重點是**@app.route("/", methods=[‘POST’])**下的代碼,這是要操作的主要服務端代碼

from flask import request, Flask
import base64
import json
import cv2
import numpy
app = Flask(__name__)

def image_to_base64(img_np):
    img = cv2.imencode('.jpg', img_np)[1]
    img_code64 = base64.b64encode(img)
    return img_code64

def base64_to_img(base64code):
    img_data = base64.b64decode(base64code)
    img_array = numpy.fromstring(img_data, numpy.uint8)
    img =cv2.imdecode(img_array, cv2.COLOR_RGB2BGR)
    return img

def str_to_byte(str_data):
    byte = bytes(str_data, encoding='utf8')
    return byte

def byte_to_str(byte):
    str_ = str(byte)[2:]
    return str_

class Flag:  #這裏設置了靜態類定義了Flag,用於跳幀處理上傳的圖像,as your will
    process_this_frame = 2
    def changeFlag(self):
        if Flag.process_this_frame != 2:
            Flag.process_this_frame = Flag.process_this_frame +1
        elif Flag.process_this_frame == 2:
            Flag.process_this_frame = 0

class TMP: # 這裏我設置了靜態類來暫時保存數據,as your will
    tmp_res = []
    def set_tmp(self, res):
        TMP.tmp_res = res

@app.route("/", methods=['POST'])
def get_frame():
    flag = Flag()
    tmp = TMP()
    #因爲上傳的是json數據,所以我們使用json.load來加載request中的data。爲什麼是request.data,因爲requests.post(url, **data**=json_res)
    json_data = json.loads(request.data)
    if json_data:
        #json解碼爲opencv可以處理的像素矩陣
        byte =str_to_byte(json_data["image"])
        img = base64_to_img(byte)
        if flag.process_this_frame == 2:
            flag.changeFlag()            
            ###
            一頓操作後,得到了處理後的圖像的像素矩陣img_res
            ###
            base64_img = image_to_base64(img_res)
            #返回的數據流只能是字符串,故要把base64轉換爲string
            res_imgstr = byte_to_str(base64_img)
        elif flag.process_this_frame != 2:
             ###
            一頓操作後,得到了處理後的圖像的像素矩陣img_res
            ###
            base64_img = image_to_base64(img_res)
            res_imgstr = byte_to_str(base64_img)
        #返回字符串到客戶端
        return res_imgstr
    else:
        return 'fail'

if __name__ == "__main__":
	# 本地客戶端中寫的API的地址和端口
    app.run("192.168.zzz.xxx", port=yyyy)

這裏有兩部分代碼,所以看的時候可能有點繞,如果有疑問或者哪裏有問題可以提一下。幫到你的話小手點個贊哈

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章