前段时间使用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)
这里有两部分代码,所以看的时候可能有点绕,如果有疑问或者哪里有问题可以提一下。帮到你的话小手点个赞哈