1

Basically I have three file which is app.py camera.py and gallery.html. I attach my code for your reference.

app.py

from flask import Flask, Response, json, render_template
from werkzeug.utils import secure_filename
from flask import request
from os import path, getcwd
import time
import os

app = Flask(__name__)
import cv2
from camera import VideoCamera


app.config['file_allowed'] = ['image/png', 'image/jpeg']
app.config['train_img'] = path.join(getcwd(), 'train_img')


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():
    return Response(gen(VideoCamera()),
                    mimetype='multipart/x-mixed-replace; boundary=frame')

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

@app.route('/gallery')
def get_gallery():
   images = os.listdir(os.path.join(app.static_folder, "capture_image"))
   return render_template('gallery.html', images=images)
app.run()

camera.py

import cv2
import face_recognition
from PIL import Image
import os
import time



dir_path = "C:/tutorial/face_recognition/venv/src4/capture_image"

class VideoCamera(object):
    def __init__(self):
        self.video = cv2.VideoCapture(0)

    def get_frame(self):
        success, frame = self.video.read()
        small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
        rgb_small_frame = small_frame[:, :, ::-1]
        face_locations = face_recognition.face_locations(rgb_small_frame,number_of_times_to_upsample=2)

        for face_location in face_locations:
            top, right, bottom, left = face_location

            face_image = rgb_small_frame[top:bottom, left:right]
            pil_image = Image.fromarray(face_image)
            File_Formatted = ("%s" % (top)) + ".jpg"
            file_path = os.path.join( dir_path, File_Formatted) 
            pil_image.save(file_path)



        ret, jpeg = cv2.imencode('.jpg', frame)
        return jpeg.tobytes()

gallery.html

<section class="row">
  {% for image in images %}
    <section class="col-md-4 col-sm-6" style="background-color: green;">
      <img src="{{ url_for('static', filename='capture_image/' + image) }}">
    </section>
  {% endfor %}
</section>

This what i have done so far, the webcam will capture the face in webcam and save in folder. Then send the image to gallery.html. Currently, i am want to display the image real time in html templete without refresh when the face is captured it will automatically display in html gallery.html dynamically or real time.For your information i am using flask,python and openCV

My question is how i can display the face capture real time without refresh. When new face captured it will automatically display in gallery.html?

Hope someone can regarding on this matter.Thank you

  • If all you do is capture a photo, store it and send it to your page, why do not you do it directly on the client side with javascript? Basically: you capture your photo with javascript ---> you send it to FLASK via Ajax ---> and you stock it. – Tobin May 27 '19 at 14:16
  • My worries is if i captured the face using the javascript, do capture face can give the result. My plan after capture the face the system will automatically recognize who is the person. –  May 27 '19 at 14:31
  • Do you know how to make facial recognition from an image? If so then there is no problem. Javascript ---> Ajax / FLASK ---> photo storage ---> facial recognition from the photo ---> result. – Tobin May 27 '19 at 15:15
  • Yup, I can try this solution but regarding on my code can u help me how to use javascript/ and ajax/flask to capture the image and store in photo storage? i am newbie in javascript.. –  May 27 '19 at 18:23

1 Answers1

2

OKAY. The first thing is to download this module : webcamJS . This is the javascript module that will allow you to capture photos from the client side. Test it to familiarize yourself with it (there are many alternatives, but in my opinion it is one of the simplest solutions).

But I'm nice, I still put a minimal code to show you how to use it:

You configure your HTML page and add the following div (do not blame me for the structure of the code, I know it's not pretty, all this hodgepodge between html and javascript, but it works):

<div id="my_photo_booth">
    <div id="my_camera"></div>

        <script src="{{url_for('static',filename='js/webcam.min.js')}}"></script>
        <script src="{{url_for('static',filename='audio/shutter.mp3')}}"></script>
        <script src="{{url_for('static',filename='audio/shutter.ogg')}}"></script>

        <!-- Configure a few settings and attach camera -->
        <script language="JavaScript">
            Webcam.set({
                // live preview size
                width: 320,
                height: 240,

                // device capture size
                dest_width: 640,
                dest_height: 480,

                // final cropped size
                crop_width: 480,
                crop_height: 480,

                // format and quality
                image_format: 'jpeg',
                jpeg_quality: 90,

                // flip horizontal (mirror mode)
                flip_horiz: true
            });
            Webcam.attach( '#my_camera' );
        </script>

        <br>
        <div id="results" style="display:none">
            <!-- Your captured image will appear here... -->
        </div>

        <!-- A button for taking snaps -->
        <form>
            <div id="pre_take_buttons">
                <!-- This button is shown before the user takes a snapshot -->
                <input type=button class="btn btn-success btn-squared" value="CAPTURE" onClick="preview_snapshot()">
            </div>

            <div id="post_take_buttons" style="display:none">
                <!-- These buttons are shown after a snapshot is taken -->
                <input type=button class="btn btn-danger btn-squared responsive-width" value="&lt; AGAIN" onClick="cancel_preview()">
                <input type=button class="btn btn-success btn-squared responsive-width" value="SAVE &gt;" onClick="save_photo()" style="font-weight:bold;">
            </div>
        </form>

</div>

A bit of javascript to manipulate the photo capture and send the photo to the server:

<script language="JavaScript">
    // preload shutter audio clip
    var shutter = new Audio();
    shutter.autoplay = false;
    shutter.src = navigator.userAgent.match(/Firefox/) ? '/static/audio/shutter.ogg' : '/static/audio/shutter.mp3';

    function preview_snapshot() {
        // play sound effect
        try { shutter.currentTime = 0; } catch(e) {;} // fails in IE
        shutter.play();

        // freeze camera so user can preview current frame
        Webcam.freeze();

        // swap button sets
        document.getElementById('pre_take_buttons').style.display = 'none';
        document.getElementById('post_take_buttons').style.display = '';
    }

    function cancel_preview() {
        // cancel preview freeze and return to live camera view
        Webcam.unfreeze();

        // swap buttons back to first set
        document.getElementById('pre_take_buttons').style.display = '';
        document.getElementById('post_take_buttons').style.display = 'none';
    }

    function save_photo() {
        // actually snap photo (from preview freeze).
        Webcam.snap( function(data_uri) {
            // display results in page
            console.log(data_uri);

            // shut down camera, stop capturing
            Webcam.reset();

            $.getJSON($SCRIPT_ROOT + '/_photo_cap', {
                photo_cap: data_uri,
            },function(data){
                var response = data.response;
            });

        } );
    }
</script>

Obviously this code you add it to the bottom of your html code.

I hope you'll manage with all this. But the interesting part here is the save_photo() function. In this function, I get the data uri from the photo and send it to flask via ajax (Check this link to see how to use jquery / ajax to send data to flask).

On the flask side:

import base64

@bp.route('/photo')
def photo():
    return render_template('photo.html')


@bp.route('/_photo_cap')
def photo_cap():
    photo_base64 = request.args.get('photo_cap')
    header, encoded = photo_base64.split(",", 1)
    binary_data = base64.b64decode(encoded)
    image_name = "photo.jpeg"

    with open(os.path.join("app/static/images/captures",image_name), "wb") as f:
        f.write(binary_data)
    //facial recognition operations
    response = 'your response'

    return jsonify(response=response)

Here there are two routes, one to render the photo capture page, and another to receive the data uri sent via ajax.

Basically what happens in the second route is that I get the data uri, I convert it to base64 and I store it on my disk. Then that's where you intervene. You do your facial recognition operations, then you return a response to your page.

Tobin
  • 2,029
  • 2
  • 11
  • 19
  • Hye @Tobin thanks you very much for your advise and help..I work on this right know.. I will update u soon –  May 29 '19 at 02:04
  • I have problem at this code $.getJSON($SCRIPT_ROOT + '/_photo_cap', { photo_cap: data_uri, },function(data){ var response = data.response; }); how actually it's works and how it related with @bp.route('/_photo_cap').. i fail to get result from this code –  May 29 '19 at 08:37
  • I put you a link to one of my previous replies where I explain how to [send data to FLASK via ajax and jquery](https://stackoverflow.com/questions/52870184/get-data-from-html-and-do-some-operation-on-it-and-pass-the-data-back-to-the-f/52883461#52883461) – Tobin May 29 '19 at 19:48
  • I think you forgot to specify the dynamic path to the site: `` – Tobin May 29 '19 at 19:51
  • Yup. I put it in my html code.. but the last curly braces show red color..what the error actually? weird, it's look like i fail to declare $script_root –  May 30 '19 at 08:37
  • i also get this error header, encoded = photo_base64.split(",", 1) AttributeError: 'NoneType' object has no attribute 'split' –  May 30 '19 at 09:00
  • You have to import the module base64, sorry I forgot to specify it. I just edited my answer and added it... But tell me, can you currently capture a photo and see the save & again buttons? – Tobin May 31 '19 at 15:47
  • About script_root, you must load it obligatorily after jquery. The error you get at the level of the split line is due to the fact that the data uri of the photo is not transmitted to flask. Review the javascript code to make sure there is no error, even a semicolon or a comma. – Tobin May 31 '19 at 15:52
  • currently i can capture the photo..but the photo don't save in file i created..how can i show u my code to u? –  Jun 10 '19 at 02:02
  • Hi Tabin, for your progress right know i already able to capture the face and save in capture folder...but when i run localhost:5000/_photo_cap...it show error like this _File "app.py", line 19, in photo_cap header, encoded = photo_base64.split(",", 1) AttributeError: 'NoneType' object has no attribute 'split'_...for your information i for testing purpose i try to pass try make **response = image_name**...but display error like above –  Jun 10 '19 at 08:39
  • `@bp.route('/_photo_cap')` : this function is supposed to receive a data-uri, to format it and to decode the data-uri. It is therefore mandatory to send the data-uri parameter. For that, you do not have to call the route `localhost:5000/_photo_cap` directly as you do. That's why the function is managed by ajax. Basically, I capture a photo, javascript recovers the data-uri and via ajax send the data-uri to flask ... – Tobin Jun 10 '19 at 11:36
  • Okey I understood...what should i do to display capture picture in my html page? Fpr my understanding I should call __localhost:5000/_photo_cap__ in my html page to display the image later with people name.. –  Jun 11 '19 at 01:14
  • I think this is another topic, so I recommend you ask a new question where you describe this problem. Basically how to display an image on a page with flask. – Tobin Jun 11 '19 at 11:18
  • oke tobin..thank you very much tobin for your help.. Really appreciate it.. Tq for support and help me again :) –  Jun 12 '19 at 01:02