前段時間使用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)
這裏有兩部分代碼,所以看的時候可能有點繞,如果有疑問或者哪裏有問題可以提一下。幫到你的話小手點個贊哈