新增侦查员和指挥员沟通,新增拍照功能 #4

Merged
pa2ltb7y5 merged 2 commits from zyp into main 3 weeks ago

@ -19,18 +19,31 @@ from car import CAR
#from PiCamera_H264_Server import stream #from PiCamera_H264_Server import stream
import threading import threading
import cv2 import cv2
import requests
app = Flask(__name__, static_url_path='') app = Flask(__name__, static_url_path='')
# 照片保存路径 # 照片保存路径
PHOTO_PATH = "photo.jpg" PHOTO_PATH = "photo.jpg"
picam2 = None
# picam2 = Picamera2() # picam2 = Picamera2()
# picam2.configure(picam2.create_video_configuration(main={"format": 'XRGB8888', "size": (640, 480)})) # picam2.configure(picam2.create_video_configuration(main={"format": 'XRGB8888', "size": (640, 480)}))
# picam2.start() # picam2.start()
def gen_frames(): # generate frame by frame from camera def cameraon():
global picam2
picam2 = Picamera2() picam2 = Picamera2()
picam2.configure(picam2.create_video_configuration(main={"format": 'XRGB8888', "size": (640, 480)})) picam2.configure(picam2.create_video_configuration(main={"format": 'XRGB8888', "size": (640, 480)}))
picam2.start() picam2.start()
def cameradown():
global picam2
picam2.stop()
picam2.close()
def gen_frames(): # generate frame by frame from camera
global picam2
cameraon()
while True: while True:
# Capture frame-by-frame # Capture frame-by-frame
frame = picam2.capture_array() # read the camera frame frame = picam2.capture_array() # read the camera frame
@ -42,39 +55,79 @@ def gen_frames(): # generate frame by frame from camera
def capture_frame(): # def capture_frame():
picam2.close() # picam2.close()
frame = picam2.capture_array() # 假设picam2是你的相机对象 # frame = picam2.capture_array() # 假设picam2是你的相机对象
ret, buffer = cv2.imencode('.jpg', frame, [int(cv2.IMWRITE_JPEG_QUALITY), 50]) # ret, buffer = cv2.imencode('.jpg', frame, [int(cv2.IMWRITE_JPEG_QUALITY), 50])
img_str = base64.b64encode(buffer).decode() # img_str = base64.b64encode(buffer).decode()
picam2.start() # picam2.start()
return img_str # return img_str
# @app.route('/capture_frame')
# def capture_frame_route():
# img_str = capture_frame()
# return jsonify(img_str)
@app.route('/control/sendit', methods=['POST'])
def send_command():
# 定义目标 IP 地址、端口和路由
ip = "192.168.98.204"
port = 3000
route = "sendit2"
# 从请求中获取消息内容
data = request.json
message = data.get('message')
if message is None:
return jsonify({"error": "缺少 message 参数"}), 400
# 构建完整的 URL
url = f"http://{ip}:{port}/{route}"
# 发送 POST 请求
try:
response = requests.post(url, json={'message': message})
response.raise_for_status() # 检查请求是否成功
return f"命令已发送,服务器响应: {response.text}"
except requests.exceptions.RequestException as e:
return f"请求失败: {str(e)}", 500
@app.route('/capture')
def capture_image():
global picam2
# 获取一帧
frame = picam2.capture_array() # 读取当前帧
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
@app.route('/capture_frame') # 定义保存图片的路径
def capture_frame_route(): photo_path = "captured_photo.jpg"
img_str = capture_frame()
return jsonify(img_str) # 将帧保存为图片
try:
cv2.imwrite(photo_path, frame)
return f"Photo saved at {photo_path}"
except Exception as e:
return f"Failed to save photo: {str(e)}"
@app.route('/') @app.route('/')
def index(): def index():
return render_template('index-t.html') return render_template('index-t.html')
@app.route('/video_feed') # @app.route('/video_feed')
def video_feed(): # def video_feed():
#Video streaming route. Put this in the src attribute of an img tag # #Video streaming route. Put this in the src attribute of an img tag
# return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/startvadio')
def startvadio():
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame') return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
#---------------------------------------------------------------------------------
@app.route('/take_photo')
def take_photo():
picam2 = Picamera2()
picam2.configure(picam2.create_video_configuration(main={"format": 'XRGB8888', "size": (640, 480)}))
picam2.start()
frame = picam2.capture_array() # Capture a single frame
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
cv2.imwrite(PHOTO_PATH, frame) # Save the frame as a JPEG file
return send_file(PHOTO_PATH, as_attachment=True) # Send the file to download
#--------------------------------------------------------------------------------------- @app.route('/stopvadio')
def stopvadio():
cameradown()
return "closed"
# def gen(camera): # def gen(camera):
# """Video streaming generator function.""" # """Video streaming generator function."""

@ -25,9 +25,11 @@
</head> </head>
<body> <body>
<h5>实时视频流</h5> <h5>实时视频流</h5>
<img src="{{ url_for('video_feed') }}"> <img src="{{ url_for('startvadio') }}">
<button id="captureButton">Capture Frame</button> <button type="button" onclick="capture()" >拍照</button>
<img id="frameImage" src="" alt="Captured Frame" style="display:none; width: 640px; height: 480px;"> <button type="button" onclick="startvadio()" >开始视频</button>
<button type="button" onclick="stopvadio()" >停止视频</button>
<!-- <img id="frameImage" src="" alt="Captured Frame" style="display:none; width: 640px; height: 480px;"> -->
<p> 小车控制界面</p> <p> 小车控制界面</p>
<bodylink = "red"> <bodylink = "red">
<a href="control" target="_blank">小车控制</a> <a href="control" target="_blank">小车控制</a>
@ -44,9 +46,7 @@
<button type="button" onclick="left()" class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-left" > </button> <button type="button" onclick="left()" class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-left" > </button>
<button type="button" onclick="stop()" class="btn btn-lg btn-primary glyphicon glyphicon-stop"> </button> <button type="button" onclick="stop()" class="btn btn-lg btn-primary glyphicon glyphicon-stop"> </button>
<button type="button" onclick="right()" class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-right" > </button> <button type="button" onclick="right()" class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-right" > </button>
<!-- ---------------------------------------- -->
<button type="button" onclick="takePhoto()">拍照</button>
<!-- ---------------------------------------- -->
</div> </div>
<button id="rear" type="button" onclick="back()" class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-down" style="margin-left: 56px;"> </button> <button id="rear" type="button" onclick="back()" class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-down" style="margin-left: 56px;"> </button>
</div> </div>
@ -67,6 +67,12 @@
</div> </div>
<button id="down" type="button" onclick="down()" class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-down" style="margin-left: 56px;"> </button> <button id="down" type="button" onclick="down()" class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-down" style="margin-left: 56px;"> </button>
</div> </div>
<div>
<form id="sendCommandForm">
回复指令: <textarea id="message"></textarea><br>
<button type="button" onclick="sendCommand()">发送指令</button>
</form>
</div>
</div> </div>
<script src='/Decoder.js'></script> <script src='/Decoder.js'></script>
@ -91,6 +97,7 @@
ws.onclose = function (e) { ws.onclose = function (e) {
console.log('Client disconnected') console.log('Client disconnected')
} }
</script> </script>
@ -98,31 +105,106 @@
<script> <script>
$(document).ready(function() { function sendCommand() {
$('#captureButton').click(function() { var message = document.getElementById('message').value;
$.ajax({ $.ajax({
url: '/capture_frame', // 后端路由地址 type: "POST",
type: 'GET', url: "/control/sendit",
success: function(response) { data: JSON.stringify({
// 将响应中的图像数据设置到img标签的src属性 message: message
$('#frameImage').attr('src', 'data:image/jpeg;base64,' + response); }),
// 显示图像 contentType: "application/json",
$('#frameImage').show(); success: function (result) {
console.log(result);
alert("指令发送成功!");
}, },
error: function(error) { error: function (error) {
console.log('Error:', error); console.log('Error:', error);
} }
}); });
}
function capture() {
console.log("132465789891651354684");
$.ajax({
type: "GET",
dataType: "json",
url: "capture" ,
data: $('#form1').serialize(), //提交的数据
success: function (result) {
console.log(result); //打印服务端返回的数据(调试用)
if (result.resultCode == 200) {
}
;
},
error : function() {
}
}); });
}
function startvadio() {
// console.log("132465789891651354684");
$.ajax({
type: "GET",
dataType: "json",
url: "startvadio" ,
data: $('#form1').serialize(), //提交的数据
success: function (result) {
console.log(result); //打印服务端返回的数据(调试用)
if (result.resultCode == 200) {
}
;
},
error : function() {
}
}); });
function printClicked() {
}
function stopvadio() {
// console.log("132465789891651354684"); // console.log("132465789891651354684");
$.ajax({
type: "GET",
dataType: "json",
url: "stopvadio" ,
data: $('#form1').serialize(), //提交的数据
success: function (result) {
console.log(result); //打印服务端返回的数据(调试用)
if (result.resultCode == 200) {
} }
// --------------------------------------- ;
function takePhoto() { },
window.location.href = "{{ url_for('take_photo') }}"; // 重定向到拍照请求 error : function() {
} }
// --------------------------------------- });
}
// $(document).ready(function() {
// $('#captureButton').click(function() {
// $.ajax({
// url: '/capture_frame', // 后端路由地址
// type: 'GET',
// success: function(response) {
// // 将响应中的图像数据设置到img标签的src属性
// $('#frameImage').attr('src', 'data:image/jpeg;base64,' + response);
// // 显示图像
// $('#frameImage').show();
// },
// error: function(error) {
// console.log('Error:', error);
// }
// });
// });
// });
function printClicked() {
// console.log("132465789891651354684");
}
function forward() { function forward() {
console.log("132465789891651354684"); console.log("132465789891651354684");
$.ajax({ $.ajax({

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 508 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 508 KiB

Loading…
Cancel
Save