0

I don't understand what is wrong in my code. What the following code is trying to do is that when the user clicks "submit" (1) it makes a directory out of the uploaded files with directory name given by user, and then (2) take the training picture and predict who the picture is of then (3) displays the predicted picture. I get the following errors:

127.0.0.1 - - [03/Sep/2021 10:57:42] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [03/Sep/2021 10:57:42] "GET /display/ HTTP/1.1" 404 - 127.0.0.1 - - [03/Sep/2021 10:57:53] "POST /predict HTTP/1.1" 302 - 127.0.0.1 - - [03/Sep/2021 10:57:53] "GET /predict HTTP/1.1" 405 -

app.py

import os
from flask import Flask, flash, request, redirect, render_template, url_for, send_file
import flask
from werkzeug.utils import secure_filename
import fcr_cv
from fcr_cv import fcr

app = Flask(__name__)

app.secret_key = "secret key"
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024

# # Get current path
# path = os.getcwd()
# # file Upload
# UPLOAD_FOLDER = os.path.join(path, 'uploads')

# Make directory if uploads is not exists
# if not os.path.isdir(UPLOAD_FOLDER):
# os.mkdir(UPLOAD_FOLDER)

# app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

# Allowed extension you can set your own
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])


def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS


def validate_input(request: flask.Request):
    input = {}
    try:
        input["sample"] = request.files.getlist('sample')
        input["test"] = request.files.get("test")
        input["folder"] = request.form["folder"]

        # allowed_file

    except Exception as e:
        print(e)
        return False, input

    return True, input


@app.route('/predict', methods=['POST'])
def predict():
    if request.method == 'POST':
        if 'sample' not in request.files:
            flash('No file part')
            return redirect(request.url)
        if 'test' not in request.files:
            flash('No test part')
            return redirect(request.url)

        is_valid, input = validate_input(request)

        if not is_valid:
            flash('Invalid input')
            return redirect(request.url)

        files = input["sample"]
        for file in files:

            data = input["folder"]
            path = os.path.join("uploads", data)
            os.makedirs(path, exist_ok=True)
            app.config["UPLOAD_FOLDER"] = path
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], file.filename))

        file = input["test"]
        test_filepath = os.path.join("uploads", "test_image.jpg")
        file.save(test_filepath)
        target_image = fcr_cv.fcr(path, app.config["UPLOAD_FOLDER"])
        flash('Image successfully uploaded and displayed below')
        return redirect(request.url, filename=target_image)
    else:
        flash('Allowed image types are -> png, jpg, jpeg, gif')
        return redirect(request.url)


@app.route('/')
def upload_form():
    return render_template('upload.html')


@app.route('/display/<filename>')
def cv_display_image(filename):
    print(filename)
    #print('display_image filename: ' + filename)
    return send_file(os.path.join("uploads", filename), mimetype='image/jpeg')


if __name__ == "__main__":
    app.run()

upload.html

<html>
<body>

<title>Python Flask Multiple Files Upload Example</title>
<h2>Select file(s) to upload</h2>

<form class="form" form action="{{ url_for('predict') }}" method="POST">
    <div class="row">
        <p class="label">Sample files</p>
        <input class="input" type="file" name="sample" multiple="true" autocomplete="off" required>
    </div>
    <div class="row">
        <p class="label">Folder Name</p>
        <input type="text" name="folder" required>
    </div>
    <div class="row">
        <p class="label">Training File</p>
        <input class="input" type="file" name="test" multiple="false" autocomplete="off" required>
    </div>

    <input type="submit" name="submit" value="Predict">
<div>
    <img src="{{ url_for('cv_display_image', filename=filename) }}">
</div>
</form>

</html>
</body>

fcr_cv.py

#import imutils
from imutils import paths
import face_recognition
import pickle
import cv2
import os
import time
from matplotlib import pyplot as plt
#import uploadfiles
#from uploadfiles import app

#UPLOAD_FOLDER = 'uploads/'
#UPLOAD_FOLDER = uploadfiles.upload_file()

#get paths of each file in folder named Images
#Images here contains my data(folders of various persons)`
#app = Flask(__name__)
def fcr(path, UPLOAD_FOLDER):
    imagePaths = list(paths.list_images((UPLOAD_FOLDER)))
    knownEncodings = []
    knownNames = []
    # loop over the image paths
    
    for (i, imagePath) in enumerate(imagePaths):
        # extract the person name from the image path
        print(imagePath)
        name = imagePath.split(os.path.sep)[-1]
        # load the input image and convert it from BGR (OpenCV ordering)
        # to dlib ordering (RGB)
        image = cv2.imread(imagePath)
        rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        #Use Face_recognition to locate faces
        boxes = face_recognition.face_locations(rgb,model='hog')
        # compute the facial embedding for the face
        encodings = face_recognition.face_encodings(rgb, boxes)
        # loop over the encodings
        for encoding in encodings:
            knownEncodings.append(encoding)
            knownNames.append(name)
    #save emcodings along with their names in dictionary data
    data = {"encodings": knownEncodings, "names": knownNames}
    #print(data)
    #use pickle to save data into a file for later use
    f = open("face_enc", "wb")
    f.write(pickle.dumps(data))
    f.close()

    #find path of xml file containing haarcascade file
    cascPathface = os.path.dirname(cv2.__file__) + "/data/haarcascade_frontalface_alt2.xml"
    # load the harcaascade in the cascade classifier
    faceCascade = cv2.CascadeClassifier(cascPathface)
    # load the known faces and embeddings saved in last file
    data = pickle.loads(open('face_enc', "rb").read())
    
    # image = cv2.imread('test/aj4.jpeg')
    image = cv2.imread(path)
    #cv2.imshow("Frame", image)
    #print(image)
    
    
    rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    #convert image to Greyscale for haarcascade
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    faces = faceCascade.detectMultiScale(gray,
                                         scaleFactor=1.1,
                                         
                                         minNeighbors=5,
                                         minSize=(60, 60),
                                         flags=cv2.CASCADE_SCALE_IMAGE)
    
    encodings = face_recognition.face_encodings(rgb)
    names = []
    
    # loop over the facial embeddings incase
    # we have multiple embeddings for multiple fcaes
    for encoding in encodings:
        #Compare encodings with encodings in data["encodings"]
        #Matches contain array with boolean values and True for the embeddings it matches closely
        #and False for rest
        matches = face_recognition.compare_faces(data["encodings"],
        encoding)
        #set name =inknown if no encoding matches
        name = "Unknown"
        # check to see if we have found a match
        if True in matches:
            #Find positions at which we get True and store them
            matchedIdxs = [i for (i, b) in enumerate(matches) if b]
            counts = {}
            # loop over the matched indexes and maintain a count for
            # each recognized face face
            for i in matchedIdxs:
                #Check the names at respective indexes we stored in matchedIdxs
                name = data["names"][i]
                #increase count for the name we got
                counts[name] = counts.get(name, 0) + 1
                #set name which has highest count
                name = max(counts, key=counts.get)
     
     
            # update the list of names
            names.append(name)
            #print(xyz)
            # loop over the recognized faces
            for ((x, y, w, h), name) in zip(faces, names):
                # rescale the face coordinates
                # Window name in which image is displayed
                #window_name = 'image'
                cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
                cv2.putText(image, name, (x, y), cv2.FONT_HERSHEY_SIMPLEX,
                 0.75, (0, 255, 0), 2)
     #   plt.figure(image)
     #   plt.imshow(image)
        #plt.axis('off') # if you want to remove coordinates
        #data = random.random((5,5))
        plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
        #image.set_cmap('hot')
        plt.axis('off')
        cv2.imwrite('./uploads/target_image', image)
        return "target_image"
      #  plt.savefig("test.png", bbox_inches='tight')
      #  cv2.show()
#        cv2.imshow("Frame", image)
#        cv2.waitKey(0)
#        cv2.destroyAllWindows()
#        cv2.waitKey(1)
        
#fcr('test/aj1.jpeg','uploads/')
Sambam
  • 33
  • 5
  • 1
    Your `redirect` causes a `GET` request which is not a valid method for the view `predict`. – Selcuk Sep 03 '21 at 06:44
  • Do you understand what a `405 Method Not Allowed` error means in HTTP, in general? (If not, you should use a search engine to figure that out.) Do you understand what a *method* is, in the context of HTTP? (in case you don't: it's the things like GET, POST etc.) Do you see why your code causes a GET method request for the `/predict` URL? Do you think it should be doing that? (Hint: read the documentation for `redirect`.) Do you think your code should be supporting it? (Hint: when you write `@app.route('/predict', methods=['POST'])`, what do you think that means?) – Karl Knechtel Sep 03 '21 at 06:53
  • Yes I do know what 405 error means but I dont see where I get it wrong with my GET and POST methods. If I have specified /PREDICT by methods=['POST'] should it still be causing a GET method? – Sambam Sep 03 '21 at 06:56
  • Does https://stackoverflow.com/questions/21689364/method-not-allowed-flask-error-405 help? It's the first result I get when I put `flask status 405` into a search engine. – Karl Knechtel Sep 03 '21 at 07:01
  • I added `GET` in my method, I was doing this before as well but I am getting this error: _This page isn’t working127.0.0.1 redirected you too many times._ – Sambam Sep 03 '21 at 07:12
  • And @KarlKnechtel the reference did help, thank you. I stumbled across it before but did not use it properly. – Sambam Sep 03 '21 at 07:13
  • Well, yes; handling the error of "the user tried to GET this page and shouldn't" with a *redirect to the same page, using GET* isn't going to work. And of course you aren't going to be able to redirect using POST because you don't have any form data to do it with. Instead of trying to check `if request.method == 'POST':` and redirecting, you should let Flask handle the error by showing a 405 page, and *designing the rest of your website such that you only link to that page via a form that creates a POST*. – Karl Knechtel Sep 03 '21 at 07:16
  • Someone trying to bypass your user interface to do something the server isn't prepared for, isn't something you should handle with a *nice* error message. – Karl Knechtel Sep 03 '21 at 07:17
  • So would you recommend creating another separate method for GET? – Sambam Sep 03 '21 at 08:43

0 Answers0