summaryrefslogtreecommitdiff
path: root/notebooks/utils/HaarSaliency.py
blob: 6a511efbb2db55801d6a71065e270501100633a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import os
from os.path import join
import cv2
import numpy as np
import xml.etree.ElementTree
class HaarSaliency:

    # Input images should be between 320x240 and 640x480
    classifiers = []
    face_matrix = []
    flags = 0
    nstages = 0

    def __init__(self, cascade, min_size=60, max_size=400,
        face_neighbors=3, sal_neighbors=0, blur_kernel=(31,31), scale_factor=1.1, stage_start=1):

        self.face_neighbors = face_neighbors
        self.sal_neighbors = sal_neighbors
        self.scale_factor = scale_factor
        self.blur_kernel = blur_kernel
        self.min_size = (min_size, min_size)
        self.max_size = (max_size, max_size)
        self.stage_start = stage_start

        cdir, cname = os.path.split(cascade)
        cname, ext = os.path.splitext(cname)

        root = xml.etree.ElementTree.parse(cascade)
        #width = int(root.find('./cascade/width').text.strip())
        #height = int(root.find('./cascade/height').text.strip())
        self.nstages = int(root.find('./cascade/stageNum').text.strip())

        # initialize classifiers
        cascades = [join(cdir,cname,str(c)+'.xml') for c in range(stage_start,self.nstages+1) ]
        self.classifiers = [cv2.CascadeClassifier(c) for c in cascades]

    def get_saliency(self,src):
        
        # conver to grayscale
        src_gray = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)

        # run face detector on all stage-classifiers
        self.face_matrix = [self.detect_faces(src_gray,c) for c in self.classifiers]

        # create saliency map in grayscale
        w,h = src.shape[1],src.shape[0]
        saliency = np.zeros((h,w), dtype=np.float32).reshape(h,w)

        # draw face-roi as stage-weighted grayscale vals
        # min_neighbors sets max value for grayscale --> white
        for i,face_list in enumerate(self.face_matrix,1):
            inc = round(255./float(self.face_neighbors)/float(self.nstages-self.stage_start)) * i
            if face_list is not None:
                for x1,y1,fw,fh in face_list:
                    saliency[y1:y1+fh,x1:x1+fw] += inc

        # normalize, clip, and recast as uint8
        smax = saliency.max()
        if smax > 255:
            saliency /= (smax/255)
        saliency = np.clip(saliency,0,255)
        saliency = np.array(saliency,dtype=np.uint8)
        
        # blur, colormap, and composite
        saliency = cv2.GaussianBlur(saliency,self.blur_kernel,0)
        dst = cv2.applyColorMap(saliency, cv2.COLORMAP_JET)
        return dst

    def detect_faces(self,src,classifier):

        matches = classifier.detectMultiScale(src, self.scale_factor,
            self.sal_neighbors, self.flags, self.min_size, self.max_size)

        if matches is None or len(matches) < 1:
            return None
        else:
            return sorted(map(tuple,matches),reverse=True) # lg --> sm