score:1

Accepted answer

gen() runs loop which all time uses the same frame().

you have to get frame inside this loop.

def gen():
    while true:
        frame = color_detection.color_detection(0)
        if frame:
            yield b'--frame\r\ncontent-type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n'
        #else:
        #    print('no frame')

but color_detection should run without loop.
and you should create videocapture(1) only once.
and you should return frame even if you didn't detect any face.

path = os.path.join(cv2.data.haarcascades, 'haarcascade_frontalface_default.xml')
face_cascade = cv2.cascadeclassifier(path)
    
video = cv2.videocapture(1)

def color_detection(season):
    # ret tells if the camera works properly. frame is an actual frame from the video feed
    ret, frame = video.read()
    # make sure port is working and read the image
    if frame is not none and video.isopened():
        gray = cv2.cvtcolor(frame, cv2.color_bgr2gray)
        '''
        detect the faces within the subregions of the image in scales
        scalefactor indicates how much the image size is reduced at each image scale.
        minneighbors: higher value results in higher quality of the detected face.
        '''
        faces = face_cascade.detectmultiscale(gray, scalefactor=1.1, minneighbors=6)

        # draw circle around each face
        for (x, y, w, h) in faces:
            # use the stcoordinates to find the center of the face and from that point draw a rectangle of radius w/2 or h/2.
            center_coordinates = x + w // 2, y + h // 2
            radius = w // 2  # or can be h / 2 or can be anything based on your requirements
            # background color(black)
            mask = np.zeros(frame.shape[:2], dtype="uint8")
            # draw the desired region to crop out in white
            cv2.circle(mask, center_coordinates, radius, (255, 255, 255), -1)
            masked = cv2.bitwise_and(frame, frame, mask=mask)
            if season == 0: # spring
                # replace all (0,0,0)channel with coral pink
                masked[np.where((masked == [0, 0, 0]).all(axis=2))] = [121, 131, 248]
            elif season == 1: # summer
                #replace all (0,0,0)channel with rose red  
                masked[np.where((masked==[0,0,0]).all(axis=2))] = [86,30,194]
            elif season == 2: # fall
                #replace all (0,0,0)channel with red brown /cinnamon
                masked[np.where((masked==[0,0,0]).all(axis=2))] = [30,105,210]
            else: # winter
                #replace all (0,0,0)channel with burgundy red
                masked[np.where((masked==[0,0,0]).all(axis=2))] = [31,2,141]
            ret, jpeg = cv2.imencode('.jpg', masked)
        else: # it is `for/else` construction, not `if/else`
            ret, jpeg = cv2.imencode('.jpg', frame)
    
        return jpeg.tobytes()

    #return none

btw:

i see other problem. when it detects many faces then it creates new mask for every face and assigns every mask to original image - so every mask skip previous mask - so it should show only last face, and hide other faces. you should first create one mask with all circles and next use it on image.


edit:

i don't know what web framework you use so i used flask to create minimal working example.

import os
from flask import flask, response
import cv2
import numpy as np

app = flask(__name__)

print('\n'.join(sorted(os.listdir(cv2.data.haarcascades))))
    
path = os.path.join(cv2.data.haarcascades, 'haarcascade_frontalface_default.xml')
face_cascade = cv2.cascadeclassifier(path)
    
#video = cv2.videocapture(0)  # my webcam
video = cv2.videocapture(0)   # your webcam

def color_detection(season):    
    ret, frame = video.read()

    if frame is not none and video.isopened():
        gray = cv2.cvtcolor(frame, cv2.color_bgr2gray)

        faces = face_cascade.detectmultiscale(gray, scalefactor=1.1, minneighbors=6)

        # test two circles on image 640x480
        #faces = [[100, 100, 250, 250], [640-100-250, 480-100-250, 250, 250]]

        if len(faces) > 0:  # it can be `if faces:` because `faces` is `numpy array` which need different method to check if not empty
            # background color(black)
            mask = np.zeros(frame.shape[:2], dtype="uint8")
            
            # draw all circles on mask
            for (x, y, w, h) in faces:
                #print(x, y, w, h)
                
                # use the coordinates to find the center of the face and from that point draw a rectangle of radius w/2 or h/2.
                center_coordinates = x + w // 2, y + h // 2
                radius = max(w, h) // 2  # or can be h / 2 or can be anything based on your requirements
                
                # draw the desired region to crop out in white
                cv2.circle(mask, center_coordinates, radius, (255, 255, 255), -1)

            # use mask with all circles
            masked = cv2.bitwise_and(frame, frame, mask=mask)
            
            if season == 0: # spring - coral pink
                color = [121, 131, 248]
            elif season == 1: # summer - rose red  
                color = [86,30,194]
            elif season == 2: # fall - red brown /cinnamon
                color = [30,105,210]
            else: # winter - burgundy red
                color = [31,2,141]

            masked[np.where((masked == [0,0,0]).all(axis=2))] = color
        else:  # no faces
            masked = frame
                        
        ret, jpeg = cv2.imencode('.jpg', masked)
        return jpeg.tobytes()
    

def gen():
    while true:
        frame = color_detection(0)
        if frame:
            yield (b'--frame\r\ncontent-type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
        #else:
        #    print('no frame')
                    
                    
@app.route('/')
def index():
    return '<image src="/seasoncolor">'
                    
@app.route('/seasoncolor')
def seasoncolor():
    return response(gen(), mimetype='multipart/x-mixed-replace; boundary=frame')
    
    
if __name__ == '__main__':
    #app.debug = true
    app.run()

btw:

to make sure: videocapture can work only with local camera where you run web server. it can't work with remote camera on user computer. only user's browser has access to its camera. to work with remote camera on user computer you would have to use javascript to access camera in user browser and send frames to server - like in my examples in my github python-examples: web camera in browser - canvas - take image and upload to server


Related Query

More Query from same tag