Face Detection using Web(Html css) and Python
Asked Answered
B

3

6

I am pretty new to web technologies. I am making a chatbot with face detection integrated although I know how to work with python and its libs with other works, i am facing issue while loading the pages

Requirement: Face detection on web, for now, we can refer to it as localhost. So for this, I have OpenCV Harcascade file ready and the detection part is also happening. sample below image and code for web and pyton.

Error: By clicking on Weblink python flask navigation are going to a pending state.

enter image description here

As you can see here Face detection is working but when i am clicking on Collect my Image link its loading forever. Please help on this.

Html Code:

<!DOCTYPE html>
<html>
<head>
    <title>Video Stream</title>
    <!-- <link rel="stylesheet" href="templates/css/main.css"> -->
</head>
<body>

<h2>ChatBot</h2>
<p >{{ alert }}</p>

<div class="container">
  <img class="bottomright" class="center" style="width: 500px;height: 300px;"src="{{ url_for('video_feed') }}">
  <div class="col-md-6 col-sm-6 col-xs-6"> <a href="/exec2" class="btn btn-sm animated-button victoria-one">Collect My Images</a> </div>
</div>  
</body>
</html>

Python Main.py class:-

from flask import Flask, render_template, Response
from camera import VideoCamera
# import create_data

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.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():
    return Response(gen(VideoCamera()),
                    mimetype='multipart/x-mixed-replace; boundary=frame')

@app.route('/exec2')
def parse1():
#     response_data_collection = 
    print("Here")
    VideoCamera().save_to_dataset()
#     if response_data_collection != None:
#         print("Done with Collecting Data")
#     else:    
#         response_data_collection = "Couldn't able to create data files"
#     return render_template('index.html', alert='Done with Collecting Data')

@app.route('/training')
def training():
    return render_template('training.html', alert='Not Yet Trained')

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)

Need help correcting parse1() class.

VideoCamera.py:- (Where all face detection related py code lies)

import cv2
import os
import time
face_cascade=cv2.CascadeClassifier("haarcascade_frontalface_alt2.xml")
ds_factor=0.6
datasets = 'datasets'

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

    def __del__(self):
        self.video.release()

    def get_frame(self):
        success, image = self.video.read()
        image=cv2.resize(image,None,fx=ds_factor,fy=ds_factor,interpolation=cv2.INTER_AREA)
        gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
        face_rects=face_cascade.detectMultiScale(gray,1.3,5)
        for (x,y,w,h) in face_rects:
            cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),2)
            break
        ret, jpeg = cv2.imencode('.jpg', image)
        return jpeg.tobytes()

    def save_to_dataset(self):
        return_data = ''
        sub_data = 'Tapan_1'
        (width, height) = (130, 100) 


        count = 1
        path = os.path.join(datasets, sub_data)
        if not os.path.isdir(path):
            os.mkdir(path)
            while count < 20: 
                success, image = self.video.read()
                image=cv2.resize(image,None,fx=ds_factor,fy=ds_factor,interpolation=cv2.INTER_AREA)
                gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
                face_rects=face_cascade.detectMultiScale(gray,1.3,5)
                for (x,y,w,h) in face_rects:
                    cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),2)
                    face = gray[y:y + h, x:x + w]
                    face_resize = cv2.resize(face, (width, height))
                    cv2.imwrite('%s/%s.png' % (path,count), face_resize)
                count += 1

                if count == 20:
                    return_data = '20 image captured.'
                    # cv2.waitKey(1)
                    # self.video.release()
                    # cv2.destroyAllWindow()
                    # time.sleep(1)

                    break
        else:
            return_data = "Data already Thr"

        return return_data

So when I am clicking on Collect my Images the network going to a pending state.

here are some screenshots.

enter image description here

enter image description here

Here you can see the Here message is printing but not navigating to exec2 page, hence this is unable to take pictures. if you are thinking might be some issue with capturing images I can surely tell there is no issue with that. I have tested with one direct link where pictures are taking so there is no problem in Videocamera python code. Something going wrong with python calling the functions.

If you can help me with the same code or if you have any reference code from your understanding which might work in this scenario please let me know Thanks.

Boast answered 8/6, 2020 at 6:4 Comment(0)
S
2

There should be exception somewhere in save_to_dataset. More debugging is needed to find the source of the exception. Since there isn't much error checking in the function, one way you could start debugging is by with putting the call in a try except block, something like:

def parse1():
#     response_data_collection = 
    #print("Here")
    try:
        VideoCamera().save_to_dataset()
    except Exception as e:
        exc = 'Exc Type: {}'.format(type(e))
        exc += 'Exc Args: {}'.format(e.args)
        print(exc)
        raise # Raise the original exception

If there is an exception, this will print the exception type and message of the exception in the logs that you are referring (instead of "Here").

Note that this is intended only for debugging. Ideally, in this scenario, you should be adding more error checking in save_to_dataset function.

Sidewinder answered 16/6, 2020 at 5:51 Comment(0)
M
1

tl;dr: The problems: Your self.video = cv2.VideoCapture(0) run twice.

If you don't want to use the global variable, you can fix the instance.

class VideoCamera:
    def __new__(cls, *args, **kwargs):
        if getattr(cls, '_instance', False):
            return cls._instance

        cls._instance = super().__new__(cls, *args, **kwargs)
        return cls._instance

    def __init__(self):
        if not hasattr(self, 'video'):
            self.video = cv2.VideoCapture(0)

Full code

And I do some modifications to let the code is more clear? The full code sees the following:

# camera.py
import cv2
import os
import time
from flask import Response
from pathlib import Path
import uuid
from contextlib import contextmanager
from typing import Callable

# https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_frontalface_alt2.xml
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_alt2.xml")
ds_factor = 0.6
datasets = 'datasets'


class VideoCamera:
    def __new__(cls, *args, **kwargs):
        if getattr(cls, '_instance', False):
            return cls._instance

        cls._instance = super().__new__(cls, *args, **kwargs)
        return cls._instance

    def __init__(self):
        if not hasattr(self, 'video'):
            self.video = cv2.VideoCapture(0)
            # self.video.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
            # self.video.set(cv2.CAP_PROP_FRAME_HEIGHT, 360)

    def get_frame(self) -> bytes:
        success, image = self.video.read()

        if not success:
            return b''

        image = cv2.resize(image, None, fx=ds_factor, fy=ds_factor, interpolation=cv2.INTER_AREA)
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        face_rects = face_cascade.detectMultiScale(gray, 1.3, 5)
        for (x, y, w, h) in face_rects:
            cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
            break
        ret, jpeg = cv2.imencode('.jpg', image)
        return jpeg.tobytes()

    def save_to_dataset(self) -> str:
        data_set_size: int = 20
        sub_folder = 'Tapan_1'
        (width, height) = (130, 100)

        dst_dir = Path(__file__).parent / Path(f'{datasets}/{sub_folder}')
        dst_dir.mkdir(parents=True, exist_ok=True)
        num_of_files = len([_ for _ in dst_dir.glob('*.*')])

        if num_of_files >= data_set_size:
            return ""

        for _ in range(data_set_size - num_of_files):
            success, image = self.video.read()
            image = cv2.resize(image, None, fx=ds_factor, fy=ds_factor, interpolation=cv2.INTER_AREA)
            gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
            face_rects = face_cascade.detectMultiScale(gray, 1.3, 5)
            for (x, y, w, h) in face_rects:
                cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
                face = gray[y:y + h, x:x + w]
                face_resize = cv2.resize(face, (width, height))
                cv2.imwrite(f'{dst_dir/Path(str(uuid.uuid4()))}.png', face_resize)
        return f'{data_set_size} image captured.'

from flask import Flask, render_template, Response
from camera import VideoCamera


app = Flask(__name__)


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


def gen(camera):
    while True:
        frame: bytes = 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('/exec2')
def parse1():
    response_data_collection = VideoCamera().save_to_dataset()
    response_data_collection = "Done with Collecting Data" if response_data_collection else "Do nothing"
    return render_template('index.html', alert=response_data_collection)


@app.route('/training')
def training():
    return render_template('training.html', alert='Not Yet Trained')


if __name__ == '__main__':
    app.run(debug=True)

Molecule answered 16/6, 2020 at 11:22 Comment(2)
Is there anything else I am missing at my HTML code.. cause I literally copy-paste the answer you gave, but it didn't work for me... after clicking on this it still loading.Boast
No, I don't change anything on the HTML. So weird, I can't believe you can't run, I mean that code is working well on my machine, may I talk with you at the chat room? And if anyone else wants to discuss too, welcome you join the room.Molecule
P
0

It seems the problem with your code is that you are re-instantiating the VideoCamera causing the code to try self.video = cv2.VideoCapture(0) twice. The second time when the VideoCamera class is instantiated (i.e. in the parse1 function) it is trying to allocate the same camera (i.e. number 0) again which is not possible. You can open a camera only once.

Try to instantiate the VideoCamera once upon your flask application like the following:

...

app = Flask(__name__)
app_wide_camera = VideoCamera()

...

@app.route('/video_feed')
def video_feed():
    # CHANGED HERE
    return Response(gen(app_wide_camera),
                    mimetype='multipart/x-mixed-replace; boundary=frame')

@app.route('/exec2')
def parse1():
#     response_data_collection = 
    print("Here")
#   CHANGED HERE
    app_wide_camera.save_to_dataset()
...
Phonetician answered 12/6, 2020 at 7:42 Comment(1)
Hi Bro, This way already tried... Not working. Still i tried once more to confirm didn't work.Boast

© 2022 - 2024 — McMap. All rights reserved.