APICloud+jetson nano+websocket +OpenCV图传APP
Posted 静·无羡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了APICloud+jetson nano+websocket +OpenCV图传APP相关的知识,希望对你有一定的参考价值。
目录
前言
暑假的时候想自己做一个图传APP,也就是把摄像头拍摄到的图像显示在手机上,查阅资料发现APICloud挺好用的,所以就研究了半个月自制了一个简易APP,废话不多说,上源码链接:
APICloud+jetson nano+websocket +OpenCV图传APP.rar
需要的朋友可以下载。
一、APICloud是什么?
APICloud是一个高性能多端开发技术快速开发企业级应用程序的低代码开发平台
一套代码同时生成android、ios、小程序、Web等多端应用,非常实用。
官网下载链接:APICloud Studio3下载
二、设计步骤
APP设计
设计好的页面可以在右侧实时预览,这一点我觉得很不错。
main.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0"/>
<title>title</title>
<link rel="stylesheet" type="text/css" href="../css/api.css"/>
<style>
header{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 80px;
background-color: rgba(132, 134, 252, 0.867);
}
header .left{
position: absolute;
bottom: 0;
left: 0;
width: 60px;
height: 42px;
}
header .left .logo{
position:absolute;
bottom: 0;
left: 0;
width: 60px;
height: 42px;
background-image: url(../image/robot.png);
background-size: 40px*33px;
background-position: center center;
background-repeat: no-repeat;
}
header .left .logo_txt{
position:absolute;
width: 80px;
height: 42px;
padding-left: 60px;
line-height: 45px;
font-size: 20px;
}
header .center{
position:absolute;
width: 100%;
height: 30px;
background-color: #000;
}
framers {
position:absolute;
top: 80px;
left: 0;
width: 100%;
bottom: 0;
background-color: #fff;
text-align: center;
}
framers .Bluetooth_control{
position:absolute;
left: 20px;
top: 20px;
background-color: #66cbff;
padding-left: 120px;
line-height: 45px;
padding-right: 120px;
font-size: 20px;
color: #fff;
}
framers .Wifi_control{
position:absolute;
left: 20px;
top: 85px;
background-color: #66cbff;
padding-left: 125px;
line-height: 45px;
padding-right: 120px;
font-size: 20px;
color: #fff;
}
framers .user_html{
height: 20px;
font-size: 20px;
color: #000;
line-height: 600px;
text-align: center;
}
framers .user_html_1{
height: 20px;
font-size: 20px;
color: #000;
text-align: center;
line-height: 700px;
}
framers .user_txt{
height: 20px;
font-size: 20px;
color: #000;
text-align: center;
line-height: 800px;
}
framers .user_txt_1{
height: 20px;
font-size: 20px;
color: #000;
text-align: center;
line-height: 900px;
}
</style>
</head>
<body>
<header>
<div class="left">
<div class="logo"></div>
<div class="logo_txt">AlphaBot</div>
</div>
<div class="center"></div>
</header>
<framers>
<div class="Bluetooth_control" onclick="Bluetooth_control();">蓝牙控制</div>
<div class="Wifi_control" onclick="Wifi_control();">Wifi控制</div>
<div class="user_html"><u>QQ:3075221401</u></div>
<div class="user_html_1"><u>CSDN@静·无羡</u></div>
<div class="user_txt"><u>AJJFirstAPP</u></div>
<div class="user_txt_1"><s></u>我的APP很大你要忍一下</s></div>
</framers>
<button type="submit" id="btn_submit"> submit </button>
</body>
<script type="text/javascript" src="../script/api.js"></script>
<script type="text/javascript">
apiready = function(){
api.setScreenOrientation({
orientation:'auto_portrait'
});
api.toast({
msg:'请先配置网络连接!'
})
};
function Bluetooth_control(){
api.openWin({
name: 'Bluetooth_control',
url: 'Bluetooth_control.html',
})
};
function Wifi_control(){
api.openWin({
name: 'Wifi_control',
url: 'Wifi_Control.html',
})
};
</script>
</html>
Wifi_Control.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0"/>
<title>title</title>
<link rel="stylesheet" type="text/css" href="../css/api.css"/>
<style>
header{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 80px;
background-color: rgba(132, 134, 252, 0.867);
}
header .left{
position: absolute;
bottom: 0;
left: 0;
width: 60px;
height: 42px;
}
header .left .logo{
position:absolute;
bottom: 0;
left: 0;
width: 60px;
height: 42px;
background-image: url(../image/robot.png);
background-size: 40px*33px;
background-position: center center;
background-repeat: no-repeat;
}
header .left .logo_txt{
position:absolute;
width: 80px;
height: 42px;
padding-left: 60px;
line-height: 45px;
font-size: 20px;
}
header .center{
position:absolute;
width: 100%;
height: 30px;
background-color: #000;
}
framers {
position:absolute;
top: 80px;
left: 0;
width: 100%;
bottom: 0;
background-color: #fff;
}
framers .IP_adrress{
position: absolute;
left: 20px;
line-height: 45px;
font-size: 14px;
color: #000;
}
framers .control_port{
position: absolute;
left: 20px;
line-height: 205px;
font-size: 14px;
color: #000;
}
framers .connection{
position:absolute;
left: 20px;
right: 20px;
top: 200px;
background-color: #66cbff;
padding-left: auto;
line-height: 45px;
padding-right: auto;
font-size: 20px;
text-align: center;
color: #fff;
}
framers .user_html{
height: 20px;
font-size: 20px;
color: #000;
line-height: 600px;
text-align: center;
}
framers .user_html_1{
height: 20px;
font-size: 20px;
color: #000;
text-align: center;
line-height: 700px;
}
framers .user_txt{
height: 20px;
font-size: 20px;
color: #000;
text-align: center;
line-height: 800px;
}
framers .user_txt_1{
height: 20px;
font-size: 20px;
color: #000;
text-align: center;
line-height: 900px;
}
</style>
</head>
<body>
<header>
<div class="left">
<div class="logo"></div>
<div class="logo_txt">AlphaBot</div>
</div>
<div class="center"></div>
</header>
<style type="text/css">
framers .IP_adrress input{
position: absolute;
left: 0px;
top: 40px;
font-size: 14px;
width: 300px;
height: 30px;
}
framers .control_port input{
position: absolute;
left: 0px;
top: 120px;
font-size: 14px;
width: 300px;
height: 30px;
}
</style>
<framers>
<div class="IP_adrress" >IP 地址: <input id="IP" type =“text” value="192.168.0.102" maxlength="13"></div>
<div class="control_port">控制端口: <input id="port" type =“text” value="8080" maxlength="4"></div>
<div class="connection" onclick="Connection(host_value,port_value);">连接</div>
<div class="user_html"><u>QQ:3075221401</u></div>
<div class="user_html_1"><u>CSDN@静·无羡</u></div>
<div class="user_txt"><u>AJJFirstAPP</u></div>
<div class="user_txt_1"><s></u>我的APP很大你要忍一下</s></div>
</framers>
</body>
<script type="text/javascript" src="../script/api.js" src="../html/Car_Control.html"></script>
<script type="text/javascript">
apiready = function(){
api.setScreenOrientation({
orientation:'portrait_up'
});
api.require('socketManager');
};
var host_value=document.getElementById("IP").value;
var port_value=document.getElementById("port").value;
function Connection(host,port)
{
ws = new WebSocket("ws://"+host+":"+port);
ws.onopen = function (msg) {
console.log('webSocket opened');
Send('ok');
api.setGlobalData({key: 'host',value: host});
api.setGlobalData({key: 'port',value: port});
ws.close();
api.openWin({name: 'Car_Control',url: 'Car_Control.html'})
};
ws.onerror = function (error) {
console.log('error :' + error.name + error.number);
api.toast({msg:'连接错误!'})
};
ws.onclose = function () {
console.log('webSocket closed');
api.toast({msg:'连接关闭!'})
};
// ws.onmessage = function (event) {
// let data = JSON.parse(event.data);
// if (data.command == "getplans") {f
// var planData = data.data;//返回的数据
// console.log(planData);
// } else if (data.command == "getscenes") {
// // 其他命令
// }
// }
}
function Send(content){
ws.send(content);
}
// window.onunload = function(){
// ws.close();
// };
</script>
</html>
Car_Control.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0"/>
<title>title</title>
<link rel="stylesheet" type="text/css" href="../css/api.css"/>
<style>
header{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 30px;
background-color: #000;
}
header .car_state{
line-height: 120px;
font-size: 20px;
text-align:center;
color: #66cbff;
}
body {
/* transform: rotate(90deg);
height: 100vw;
width: 100vh;
transform-origin: 0% 100%;
top: -100vw; */
background-color: #fff;
}
lefter{
position: absolute;
top: 0;
left: 0;
width: 30px;
height: 100%;
transform: rotateZ(90);
background-color: #000;
}
control{
position: absolute;
top: 30px;
left: 30px;
bottom: 0px;
width: 345px;
}
control .Forward{
position: absolute;
top: 80px;
left: 120px;
width: 70px;
height: 70px;
background-image: url(../image/106.png);
}
control .Backward{
position: absolute;
top: 220px;
left: 120px;
width: 70px;
height: 70px;
background-image: url(../image/109.png);
}
control .TurnLeft{
position: absolute;
top: 150px;
left: 30px;
width: 70px;
height: 70px;
background-image: url(../image/102.png);
}
control .TurnRight{
position: absolute;
top: 150px;
left: 210px;
width: 70px;
height: 70px;
background-image: url(../image/105.png);
}
control .Up{
position: absolute;
top: 80px;
left: 560px;
width: 70px;
height: 70px;
background-image: url(../image/106.png);
}
control .Down{
position: absolute;
top: 220px;
left: 560px;
width: 70px;
height: 70px;
background-image: url(../image/109.png);
}
control .Left{
position: absolute;
top: 150px;
left: 470px;
width: 70px;
height: 70px;
background-image: url(../image/102.png);
}
control .Right{
position: absolute;
top: 150px;
left: 650px;
width: 70px;
height: 70px;
background-image: url(../image/105.png);
}
</style>
</head>
<body>
<header>
<div class="car_state"id="direction">Stop</div>
<div class="center"></div>
</header>
<lefter></lefter>
<control>
<div class="Forward" id="F"></div>
<div class="Backward" id="B"></div>
<div class="TurnLeft" id="TL"></div>
<div class="TurnRight"id="TR"></div>
<div class="Up" id="U"></div>
<div class="Down" id="D"></div>
<div class="Left" id="L"></div>
<div class="Right"id="R"></div>
<img id="resImg" src="" width="640" height="480"/> <!--图片展示-->
<iframe id="inner1" src="../html/Wifi_Control.html"></iframe>
</control>
</body>
<script type="text/javascript" src="../script/api.js" src="../html/Wifi_Control.html" ></script>
<script type="text/javascript">
apiready = function(){
api.setScreenOrientation({
orientation:'landscape_left'
});
api.toast({
msg:'连接成功!'
})
api.addEventListener({
name:'keyback'
}, function(ret,err){
api.setScreenOrientation({
orientation:'portrait_up'
});
api.closeWin();
});
host = api.getGlobalData({key: 'host'});
port = api.getGlobalData({key: 'port'});
Connection(host,port);
};
var Img = document.getElementById('resImg');
function Connection(host,port)
{
ws = new WebSocket("ws://"+host+":"+port);
ws.onopen = function (msg) {
console.log('webSocket opened');
Send('ok');
};
ws.onerror = function (error) {
console.log('error :' + error.name + error.number);
api.toast({msg:'连接错误!'})
};
ws.onclose = function () {
console.log('webSocket closed');
api.toast({msg:'连接关闭!'})
};
ws.onmessage = function (event) {
Img.src=event.data;
}
}
function Send(content){
ws.send(content);
}
var F = document.getElementById('F');
F.addEventListener("touchstart",function()
{
F.style.backgroundImage='url(../image/107.png)';
Send('Forward');
})
F.addEventListener("touchend",function()
{
F.style.backgroundImage='url(../image/106.png)';
Send('Stop');
}
)
var B = document.getElementById('B');
B.addEventListener("touchstart",function()
{
B.style.backgroundImage='url(../image/108.png)';
Send('Backward');
})
B.addEventListener("touchend",function()
{
B.style.backgroundImage='url(../image/109.png)';
Send('Stop');
}
)
var TL = document.getElementById('TL');
TL.addEventListener("touchstart",function()
{
TL.style.backgroundImage='url(../image/103.png)';
Send('TurnLeft');
})
TL.addEventListener("touchend",function()
{
TL.style.backgroundImage='url(../image/102.png)';
Send('Stop');
}
)
var TR = document.getElementById('TR');
TR.addEventListener("touchstart",function()
{
TR.style.backgroundImage='url(../image/104.png)';
Send('TurnRight');
})
TR.addEventListener("touchend",function()
{
TR.style.backgroundImage='url(../image/105.png)';
Send('Stop');
}
)
var U = document.getElementById('U');
U.addEventListener("touchstart",function()
{
U.style.backgroundImage='url(../image/107.png)';
Send('Up');
})
U.addEventListener("touchend",function()
{
U.style.backgroundImage='url(../image/106.png)';
Send('Stop');
}
)
var D = document.getElementById('D');
D.addEventListener("touchstart",function()
{
D.style.backgroundImage='url(../image/108.png)';
Send('Down');
})
D.addEventListener("touchend",function()
{
D.style.backgroundImage='url(../image/109.png)';
Send('Stop');
}
)
var L = document.getElementById('L');
L.addEventListener("touchstart",function()
{
L.style.backgroundImage='url(../image/103.png)';
Send('Left');
})
L.addEventListener("touchend",function()
{
L.style.backgroundImage='url(../image/102.png)';
Send('Stop');
}
)
var R = document.getElementById('R');
R.addEventListener("touchstart",function()
{
R.style.backgroundImage='url(../image/104.png)';
Send('Right');
})
R.addEventListener("touchend",function()
{
R.style.backgroundImage='url(../image/105.png)';
Send('Stop');
}
)
</script>
</html>
jetson nano Python代码设计
image_socket.py
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
from websocket_server import WebsocketServer
import threading
import cv2
import base64
import time
import subprocess
time.sleep(5)
cmd = "hostname -I | cut -d\\' \\' -f1"
host = subprocess.check_output(cmd,shell = True )
print(host)
# Called for every client connecting (after handshake)
def new_client(client, server):
print("got connection from ",client['address'] )
# 发送给所有的连接
server.send_message_to_all("Hey all, a new client has joined us")
# Called for every client disconnecting
def client_left(client, server):
print("Client disconnected!" )
# Called when a client sends a message
def message_received(client, server, message):
if len(message) > 200:
message = message[:200]+'..'
print("Client(%d) said: %s" % (client['id'], message))
# 发送给所有的连接
#server.send_message_to_all(message)
def vedio_thread2(n):
cap = cv2.VideoCapture(0)
width = 640
height = 480
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
while(True):
ret, img_bgr = cap.read()
if img_bgr is None:
print('lose image_value')
else:
frame = cv2.flip(img_bgr, 1)
image = cv2.imencode('.jpg', frame)[1]
base64_data = base64.b64encode(image)
s = base64_data.decode()
#cv2.imshow("video", frame)
server.send_message_to_all('data:image/jpeg;base64,%s'%s)
cv2.waitKey(50)
time.sleep(0.05)
def vedio_thread1(n):
print('send')
while True:
if len(server.clients)>0:
image = cv2.imencode('.jpg', frame)[1]
base64_data = base64.b64encode(image)
s = base64_data.decode()
#print('data:image/jpeg;base64,%s'%s)
#server.send_message_to_all('data:image/jpeg;base64,%s'%s)
time.sleep(0.05)
def from_camera():
thread1 = threading.Thread(target=vedio_thread1, args=(1,))
thread1.setDaemon(True)
thread1.start()
thread2 = threading.Thread(target=vedio_thread2, args=(1,))
thread2.setDaemon(True)
thread2.start()
print('start')
print('server is running....')
# Server Port
port=8080
# 创建Websocket Server
server = WebsocketServer(port,host)
from_camera()
# 有设备连接上了
server.set_fn_new_client(new_client)
# 断开连接
server.set_fn_client_left(client_left)
# 接收到信息
server.set_fn_message_received(message_received)
# 开始监听
server.run_forever()
运行代码
运行APICloud APP代码
手机下载好AppLoader,官方下载链接:AppLoader,通过数据线连接上电脑并开启调试模式,右击项目点击USB同步
项目编译完成后会显示可连接设备:
点击选择手机设备,手机就会自动打开AppLoader进入APP界面:
确保nano和手机连接同一个网络,在nano上运行image_socket.py:
由图可以看出nano的IP地址为192.168.0.102,代码中端口设置为8080
APP点击WIFI控制,输入IP地址和端口后点击连接,就可以在手机APP上看到nano摄像头采集的图像了。
总结
虽然花了半个月时间才搞定,但是这次也是学习到了不少东西,嘿嘿,源代码已经上传到CSDN了,有钱的捧个钱场哈,当然想白嫖的同学可以在评论区留下邮箱,我有空就会发。
以上是关于APICloud+jetson nano+websocket +OpenCV图传APP的主要内容,如果未能解决你的问题,请参考以下文章