Python Forum

Full Version: Nested loops in openCV
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I am fairly new to python but have been coding for a long time. I am trying to use OpenCV to detect faces in an image and then iterate through the pixels detected by the face detection. I am then adding all of the RGB values of the image together and then taking an average. It is my hope that this will give me the average skin tone of the person in the photo. But, I am having some trouble with nested loops in python. At first I tried a for loop, but then I realized in python for loops always start at 0 so this was not useful. I then tried a nested while loop as seen below, but was met with an unexpected result. These are on lines 32 to 34.

[inline]
import numpy as np
import cv2

#load xml files, in openCV
face_cascade = cv2.CascadeClassifier('C:\Program Files\opencv\sources\data\haarcascades\haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('C:\Program Files\opencv\sources\data\haarcascades\haarcascade_eye.xml')

#define image and convert to grayscale, these are my own images, swap with whatever you want
img = cv2.imread('face2.jpg')
gray = cv2.imread('face2.jpg',0)

#scan for faces and draw rectangle
faces = face_cascade.detectMultiScale(gray, 1.3, 5)

#these four values are the xy coordinates passed to create the rectangle for face detection
x1= faces[0][0]
x2= faces[0][2]
y1= faces[0][1]
y2= faces[0][3]
#values to store the  RGB values of the face
avgR=0
avgB=0
avgG=0
#calculating the other two corners of the rectange as well as the center.
topRight= x1 + (x2-x1)
bottomLeft= y1 + (y2-y1)
centerX= (x2-x1)/2
centerY= (y2-y1)/2
counter=0
off=True
#the nested loop that is giving me problems.
for()
    yG= y1
    while yG <= bottomLeft:
#get the RGB values in each pixel
        insertRed= img[x1,y1,0]
        insertGreen= img[x1,y1,1]
        insertBlue= img[x1,y1,2]
        #insertRed= img[centerY,centerX,0]
        #insertGreen= img[centerY,centerX,1]
        #insertBlue= img[centerY,centerX,2]
    #add them together
        avgR= avgR+ insertRed
        avgG= avgG + insertGreen
        avgB= avgB +insertBlue
        #counter is used to get the average
        counter= counter+1
    #this was done for testing to see what the program is actually reading
        img[x1,yG]= [40,40,40]
    #increment
        x1= x1+1
        yG=yG+1


#this just draws a rectangle guide around the face
for (x,y,w,h) in faces:
    img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)

    roi_gray = gray[y:y+h, x:x+w]
    roi_color = img[y:y+h, x:x+w]


#calculate the average of each color
avgR= avgR/counter
avgG= avgG/counter
avgB= avgB/counter

cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

print(avgR, avgG, avgB)
input('Press ENTER to exit')
[/inline]

When executed, a blue rectangle will surround a face and a gray line, which represents all of the pixels iterated over, bisects the rectangle diagonally. What I want is for the entire rectangle to be iterated over. I could scan over the correct dimensions with a for loop, but it would start at index 0 0, so this was not useful to my purpose. Please let me know if I need to clarify my question further
As a general rule of thumb, if you are trying to iterate over every pixel in an image (or more generally every object in a numpy array) you are doing something wrong.

You can simply sum the image slice over the appropriate axis and divide. In fact I think you would probably find there was even a mean function in numpy that could work on specified array axes automatically.

I'm gonna mess around with some face detection myself and I'll post back if you haven't figured it out later.