I'm trying to implement an object detection web app using flask.
The flow of my app is:
The user will upload an image.
The image will get saved to a directory ('/static/uploads' folder)
A function called 'get_images' will read the image, load the object detector model, and finally write the image with detection at the specified folder ('/static/detections/')
A template called 'uploaded.html' will then display the uploaded image from the upload directory, and also the image with detections from detections directory.
The app runs fine when ran for the first time and when the server is launched again. But if I try to upload another image after running detection on the first image, the image with detections get overwritten with the previous image but its name is preserved, ultimately resulting in the first image with detections being displayed again and again. My flask app (app.py) code is as follows:
app = Flask(__name__)
UPLOAD_FOLDER = './static/uploads/'
DETECTION_FOLDER = './static/detections/'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['DETECTION_FOLDER'] = DETECTION_FOLDER
# app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
# app.config['TEMPLATES_AUTO_RELOAD'] = True
#app.route("/")
def index():
return render_template("index.html")
#app.route("/about")
def about():
return render_template("about.html")
#app.route('/uploader', methods = ['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['file']
# create a secure filename
filename = secure_filename(f.filename)
print(filename)
# save file to /static/uploads
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
print(filepath)
f.save(filepath)
print(filepath)
get_image(filepath,filename)
return render_template("uploaded.html", display_detection = filename, fname = filename)
if __name__ == '__main__':
app.run(port=4000, debug=True)
Function get_image() is a method of file app_helper.py and is ultimately performing a cv2.imwrite on the image with detections. I thought the problem might be with this section of the code as this is the only place where any 'writing' is done. So, I ran the app_helper.py function multiple times, and not once the images were overwritten (in the '/static/detections/' folder).
I'm including some images to explain my concern better,
Page after running the first detection looks like this
'/static/detections/' folder after first run
'/static/uploads/' folder after uploading my 2nd image
As soon I run the detector, this is what happens in the '/static/detections/' folder, though the file name is preserved
And since the new file name (phone.jpg) is now associated with same image as 'phone2.jpg' the detection image doesn't not change. I kept repeating this, and any new image I uploaded - it got overwritten by 'phone2.jpg'!
I repeat, I tried running get_images() method separately - even after running it on multiple images NO SUCH OVERWRITES took place. For ref, get_images() method is a slight modification of this code. ('Uploaded.html' relies on the filename to display images, which is being maintained here)
e.g. get_images('/data/images/kite.jpg','kite.jpg')
ps- I also tried adding,
# app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
# app.config['TEMPLATES_AUTO_RELOAD'] = True
also, after the first execution, I emptied the uploads and detections folder to check if that helps,
But these didn't work.
Kindly help me out, I want my app to bear multiple runs (of upload and detect) without such issues.
Thank you.
Related
I am trying to use my Flask API to save an image to the database OR just a file system but this is something I have never done and am getting nowhere with it.
I would like to be able to return the image back when the route is called and be able to use it in my ReactJS Application using just a img tag.
All I have been able to find is how to save the image to the Database and then download it using a route. I need to be able to return it. (It works just not what I need.)
Here is what that was:
#app.route('/img-upload', methods=['POST'])
def img_upload():
file = request.files['image']
newFile = Mealplan(name=file.filename, data=file.read())
db.session.add(newFile)
db.session.commit()
return jsonify({"Done!" : "The file has been uploaded."})
#app.route('/get-mealplan-image/<given_mealplan_id>')
def download_img(given_mealplan_id):
file_data = MealPlan.query.filter_by(id=given_mealplan_id).first()
return send_file(BytesIO(file_data.data), attachment_filename=file_data.name, as_attachment=True)
Save the files on the file system will be a more proper method. Here is a minimal example:
from flask import send_from_directory
basedir = os.path.abspath(os.path.dirname(__file__))
uploads_path = os.path.join(basedir, 'uploads') # assume you have created a uploads folder
#app.route('/img-upload', methods=['POST'])
def upload_image():
f = request.files['image']
f.save(os.path.join(uploads_path , f.filename)) # save the file into the uploads folder
newFile = Mealplan(name=f.filename) # only save the filename to database
db.session.add(newFile)
db.session.commit()
return jsonify({"Done!" : "The file has been uploaded."})
#app.route('/images/<path:filename>')
def serve_image(filename):
return send_from_directory(uploads_path, filename) # return the image
In your React app, you can use the filename to build to the image URL: /images/hello.jpg
Update:
If you can only get the id, the view function will be similar:
#app.route('/get-mealplan-image/<given_mealplan_id>')
def download_img(given_mealplan_id):
file_data = MealPlan.query.filter_by(id=given_mealplan_id).first()
return send_from_directory(uploads_path, file_data.name)
I'm new to Python and Google Cloud. Using Flask I have created a web page where a user can choose a file from their computer and upload it to a GCS bucket that I have already created. I'm following Google's documentation example which uses the Google Python API library. I'm able to upload files whose names are just a single word, like 'image' but if my file is named 'image one' then I get the following error-
FileNotFoundError: [Errno 2] No such file or directory: 'image one.jpg'
Here's my code:
#app.route('/upload', methods = ['GET' , 'POST'])
def upload():
if request.method == "POST":
f = request.files['file']
f.save(secure_filename(f.filename))
gcs_upload(f.filename)
def gcs_upload(filename):
storage_client = storage.Client() # instantiate a client
bucket = storage_client.bucket('bucket_name')
blob=bucket.blob(filename) # file name at the destination should be the same
blob.upload_from_filename(filename) # file to be uploaded
if __name__ == '__main__':
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
app.run(port=8080, debug=True)
If I'm writing a production level application then I would want a user to upload a file even if it has spaces in its name.
I reproduced the issue on my own project and the problem you face arise from the use of secure_filename function. According to werkzeug documentation the function secure_filename will replace any whitespace of the user provided filename with an underscore. Adding some logging you might see that:
f.filename # 'foo bar.png'
secure_filename(f.filename) # 'foo_bar.png'
So, when you call the gcs_upload function you're passing the original filename instead of the one returned by secure_filename and as the error message points out such file does not exist.
To solve the issue just change your upload function to:
def upload():
if request.method == "POST":
f = request.files['file']
filename = secure_filename(f.filename)
f.save(filename)
gcs_upload(filename)
Try to quote filename (by using urllib) before. This is an example by using python3:
import urllib.parse
filename = "files name.jpg"
new_file = str(urllib.parse.quote(filename))
I have a script that generates an image.
That image is saved in a directory inside my OS static folder. image.png is saved in:
-static
-images
-monkeys
- image.png
The server endpoint function should upload the image into my S3-bucket and return that static file from my bucket, not from my OS file system.
This does not work for some reason.
The image uploading works fine, I can see the image in the bucket, I'm just not able to serve the static image, I get an error:
"The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.". Basically it cannot find the image.
I am using flask-S3 in the following way:
app = Flask(__name__)
app.config['FLASKS3_BUCKET_NAME'] = os.environ.get('S3_BUCKET_NAMEING')
app.config['USE_S3_DEBUG'] = True
s3 = FlaskS3(app)
My endpoint for serving the static image:
#app.route('/image/monkey/<address>', methods = ['GET'])
def monkey_image(address):
# There is some code here that generates that image and places it
# inside the monkeys folder. I did not include it because
# it is not relevant to the question
image = open(image_path, 'rb')
S3_path = 'images/monkeysS3/' + monkey_image_name
upload_image_to_s3_bucket(image,'static/' + S3_path)
return redirect(flask_url_for('static', filename=S3_path))
So the last 2 lines matters.
upload_image_to_s3 works. The issue comes from
return redirect(flask_url_for('static', filename=path)).
It just can't find the image inside my S3 bucket.
This goes for development and production as well.
Thanks
I want to upload an image file to imgur using the python-Flask. So for this I am submitting an image file from the form and want to upload this file to imgur.
But the point is the example snippets given in the imgur api want the path name of the file that was uploaded. So far I was trying to upload but I am stuck!!
This is my main.py file
if request.method == "POST":
image = request.files.get('myfile') #myfile is name of input tag
config ={
'album':album,
'name':'Catastrophe!',
'title':'Catastrophe!'
}
print os.path.realpath(image.filename) # this line gives me wrong path of file.
print "uploading image..."
#image = client.upload_from_path(filepath,config=config,anon=False)
The commented print statement gives me path like this
/home/suraj/Desktop/FlaskTrials/wallpaper.jpg
But the thing is the correct file path could be anything the user wants to choose image from
How do I get this path. Am I doing the right thing to upload the image to imgur api ?
I would be able to do by making an dir in root folder and adding image to it and then get the filename of that and upload to imgur.
But I was wandering is it possible without saving and image file.
Thanks in advance
It looks to me like you forgot to save the file on the server. Here is a modified version of your code based on http://flask.pocoo.org/docs/0.10/patterns/fileuploads/.
if request.method == "POST":
image = request.files['myfile'] #myfile is name of input tag
config ={
'album':album,
'name':'Catastrophe!',
'title':'Catastrophe!'
}
print "uploading image..."
filename = secure_filename(image.filename)
file.save(os.path.join('/home/suraj/Pictures', filename))
print os.path.realpath(image.filename)
I recommend considering restricting the file names to certain extensions, as suggested by the Flask doc.
So I am trying to test out serving some user uploaded files in Flask. For images I am simply renaming them with a shortened UUID and putting them in a folder, but for other file types I would like to retain the original filename, so I devised the convoluted method of saving each file in a subfolder named with a UUID. Everything works fine, both the images and files upload and are in the directories they should be in. Just to test I made a template for a download page to just display the filename(planned to implement a download button later). However, when I plug the generated URL in for an uploaded file, I get a 404, and the function that url is supposed to be bound to doesn't even appear to execute(I had it print the filename in console and it doesnt even print), and in console the url is displayed: "GET /xVgePgj2Y HTTP/1.1" 404 -
My code for uploading the files and making the URL:
else:
new_folder_name = shortuuid.uuid()[:9]
os.mkdir(os.path.join(app.config['FILE_FOLDER'], new_folder_name))
file.save(os.path.join(os.path.join(app.config['FILE_FOLDER'], new_folder_name), filename))
new_folder_path = os.path.join(app.config['FILE_FOLDER'], new_folder_name)
return url_for('uploaded_file', new_folder_name=new_folder_name)
My code for serving the files:
#app.route('/<new_folder_name>', methods=['GET'])
def uploaded_file(new_folder_name):
filename = subfolder_fetch(new_folder_name)
return render_template("download.html", filename=filename)
and finally my code for fetching the filename from the subdirectory (called in the serving function - didn't pass the filename to the url_for function because that would make it ugly and complicated):
def subfolder_fetch(new_folder_name):
stuff = os.listdir(os.path.join(app.config['FILE_FOLDER'], new_folder_name))
for name in folder:
print (name)
return name
I'm puzzled as to what is even going on and why my uploaded_file function isn't even being called.
Thanks in advance.