python - 如何使用 OpenCV 和 Flask 捕获图像?
问题描述
我正在尝试运行这个网站,该网站使用烧瓶,当你按下下一步时它会拍照,但它只在我第一次访问该 URL 时有效。当我被重定向到相同的网址时,它不再起作用。
请帮助我已经坚持了几个月了,不知道该怎么办了。
from camera import VideoCamera
import cv2
import time
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hello'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///drug1.sqlite'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
med_list = []
timestr = time.strftime("%Y%m%d-%H%M%S")
cam = cv2.VideoCapture(0)
video_stream = VideoCamera()
@app.route('/')
def index():
return render_template('vid.html')
def gen(camera):
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
@app.route('/video_feed')
def video_feed():
@app.route("/scan", methods =["POST","GET"])
def scan():
drug_list = []
if request.method == 'POST':
bc = request.form['barcode']
print(bc)
if request.form['submit_button'] == 'Next':
return redirect(url_for('scan2',image=image_link,drug=drug,strength=strength,med_list=med_list))
return render_template("scan.html")
@app.route("/scan2", methods =["POST","GET"])
def scan2():
drug = session.get("drug",None)
image_link = session.get("image_link",None)
strength = session.get("strength",None)
if request.method == 'POST':
if request.form['submit_button'] == 'Next':
retval, frame = cam.read()
cv2.imwrite('img{}.png'.format(timestr), frame)
return redirect(url_for('scan'))
return render_template("scan2.html",image=image_link,drug=drug,strength=strength)
解决方案
如果您想使用用户笔记本电脑中的内置摄像头拍照,那么您必须使用JavaScript
,因为只有网络浏览器才能访问用户的摄像头 - 服务器无法访问用户的计算机。
这是显示来自用户相机的流的示例,它可以截屏。但它仍然需要 JavaScript 才能将其发送到服务器。
from flask import Flask, render_template_string
app = Flask(__name__)
@app.route('/')
def index():
return render_template_string('''
<video id="video" width="640" height="480" autoplay style="background-color: grey"></video>
<button id="snap">Take Photo</button>
<canvas id="canvas" width="640" height="480" style="background-color: grey"></canvas>
<script>
// Elements for taking the snapshot
var video = document.getElementById('video');
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
// Get access to the camera!
if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
// Not adding `{ audio: true }` since we only want video now
navigator.mediaDevices.getUserMedia({ video: true }).then(function(stream) {
//video.src = window.URL.createObjectURL(stream);
video.srcObject = stream; // assing stream to <video>
video.play(); // play stream
});
}
// Trigger photo take
document.getElementById("snap").addEventListener("click", function() {
context.drawImage(video, 0, 0, 640, 480); // copy video frame to canvas
});
</script>
''')
if __name__ == '__main__':
app.run(debug=True)
编辑:
这是可以在服务器上发送图像的示例。
以及我在这段代码中拥有的一些有用的链接
https://developers.google.com/web/fundamentals/media/capturing-images
https://github.com/jhuckaby/webcamjs
https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob
from flask import Flask, render_template_string, request
app = Flask(__name__)
@app.route('/')
def index():
return render_template_string('''
<video id="video" width="640" height="480" autoplay style="background-color: grey"></video>
<button id="send">Take & Send Photo</button>
<canvas id="canvas" width="640" height="480" style="background-color: grey"></canvas>
<script>
// Elements for taking the snapshot
var video = document.getElementById('video');
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
// Get access to the camera!
if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
// Not adding `{ audio: true }` since we only want video now
navigator.mediaDevices.getUserMedia({ video: true }).then(function(stream) {
//video.src = window.URL.createObjectURL(stream);
video.srcObject = stream;
video.play();
});
}
// Trigger photo take
document.getElementById("send").addEventListener("click", function() {
context.drawImage(video, 0, 0, 640, 480); // copy frame from <video>
canvas.toBlob(upload, "image/jpeg"); // convert to file and execute function `upload`
});
function upload(file) {
// create form and append file
var formdata = new FormData();
formdata.append("snap", file);
// create AJAX requests POST with file
var xhr = new XMLHttpRequest();
xhr.open("POST", "{{ url_for('upload') }}", true);
xhr.onload = function() {
if(this.status = 200) {
console.log(this.response);
} else {
console.error(xhr);
}
alert(this.response);
};
xhr.send(formdata);
}
</script>
''')
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
#fs = request.files['snap'] # it raise error when there is no `snap` in form
fs = request.files.get('snap')
if fs:
print('FileStorage:', fs)
print('filename:', fs.filename)
fs.save('image.jpg')
return 'Got Snap!'
else:
return 'You forgot Snap!'
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True, port=5000)
编辑:
我找到了将流发送到服务器的示例,它使用当前时间绘制红色边框和文本并将其发送回浏览器。
# https://developers.google.com/web/fundamentals/media/capturing-images
# https://github.com/jhuckaby/webcamjs
# https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob
# https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL
# https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
from flask import Flask, render_template_string, request, make_response
import cv2
import numpy as np
import datetime
app = Flask(__name__)
@app.route('/')
def index():
return render_template_string('''
<video id="video" width="320" height="240" autoplay style="background-color: grey"></video>
<button id="send">Take & Send Photo</button>
<canvas id="canvas" width="320" height="240" style="background-color: grey"></canvas>
<img id="image" src="" width="320" height="240" style="background-color: grey"></img>
<img id="image64" src="" width="320" height="240" style="background-color: grey"></img>
<script>
// Elements for taking the snapshot
var video = document.getElementById('video');
// Element to display snapshot
// you need canvas to get image. canvas can be hidden using `createElement("canvas")`
// var canvas = document.createElement("canvas");
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var image = document.getElementById('image');
var image64 = document.getElementById('image64');
// Get access to the camera!
if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
// Not adding `{ audio: true }` since we only want video now
navigator.mediaDevices.getUserMedia({ video: true }).then(function(stream) {
//video.src = window.URL.createObjectURL(stream);
video.srcObject = stream;
video.play();
//console.log('setInterval')
window.setInterval(function() {
//context.drawImage(video, 0, 0);
context.drawImage(video, 0, 0, 320, 240); // better use size because camera may gives data in different size then <video> is displaying
image64.src = canvas.toDataURL();
canvas.toBlob(upload, "image/jpeg");
}, 100);
});
}
// Trigger photo take
document.getElementById("send").addEventListener("click", function() {
//context.drawImage(video, 0, 0);
context.drawImage(video, 0, 0, 320, 240); // better use size because camera may gives data in different size then <video> is displaying
image64.src = canvas.toDataURL();
canvas.toBlob(upload, "image/jpeg");
});
function upload(file) {
// create form
var formdata = new FormData();
// add file to form
formdata.append("snap", file);
// create AJAX connection
var xhr = new XMLHttpRequest();
xhr.open("POST", "{{ url_for('upload') }}", true);
xhr.responseType = 'blob';
// define function which get response
xhr.onload = function() {
if(this.status = 200) {
//console.log(this.response);
} else {
console.error(xhr);
}
//alert(this.response);
//img.onload = function(){
// ctx.drawImage(img, 0, 0)
//}
image.src = URL.createObjectURL(this.response); // blob
};
// send form in AJAX
xhr.send(formdata);
//image.src = URL.createObjectURL(file);
}
</script>
''')
def send_file_data(data, mimetype='image/jpeg', filename='output.jpg'):
# https://stackoverflow.com/questions/11017466/flask-to-return-image-stored-in-database/11017839
response = make_response(data)
response.headers.set('Content-Type', mimetype)
response.headers.set('Content-Disposition', 'attachment', filename=filename)
return response
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
#fs = request.files['snap'] # it raise error when there is no `snap` in form
fs = request.files.get('snap')
if fs:
#print('FileStorage:', fs)
#print('filename:', fs.filename)
# https://stackoverflow.com/questions/27517688/can-an-uploaded-image-be-loaded-directly-by-cv2
# https://stackoverflow.com/a/11017839/1832058
img = cv2.imdecode(np.frombuffer(fs.read(), np.uint8), cv2.IMREAD_UNCHANGED)
#print('Shape:', img.shape)
# rectangle(image, start_point, end_point, color, thickness)
img = cv2.rectangle(img, (20, 20), (300, 220), (0, 0, 255), 2)
text = datetime.datetime.now().strftime('%Y.%m.%d %H.%M.%S.%f')
img = cv2.putText(img, text, (5, 15), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1, cv2.LINE_AA)
#cv2.imshow('image', img)
#cv2.waitKey(1)
# https://jdhao.github.io/2019/07/06/python_opencv_pil_image_to_bytes/
ret, buf = cv2.imencode('.jpg', img)
#return f'Got Snap! {img.shape}'
return send_file_data(buf.tobytes())
else:
return 'You forgot Snap!'
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True, port=5000)
相机HTTP
仅适用于地址127.0.0.1
0.0.0.0
它需要,HTTPS
但它需要。cert
您可以使用测试,ssl_context='adhoc'
但浏览器会警告您这是不安全的连接,您必须接受它。
app.run(host='0.0.0.0', port=5000, ssl_context='adhoc')
推荐阅读
- websphere - 如何使用 Spring Boot 应用程序在 IBM Web-Sphere 上创建 Web 服务器插件配置文件?
- excel - 使用 VBA 将连续信息添加到 Word 文档
- python - 管道:运行 make 命令时文件描述符错误
- powershell - PowerShell 5.1 和 PowerShell 7 相同的脚本,不同的结果
- android - 每次我更改 Compose Jatpack 的代码时都构建和刷新
- sql-server - SQL Server Linux 更改排序规则
- npm - 使用 BroadcastChannel 库时如何解决“未定义要求”?
- c# - 如何从 ListViewItem 获取 ProgressRing?
- project - Taskjuggler - 任务报告中的资源名称
- python - 如何在python中操作嵌套字典并为其附加一个键?