|
|
@ -8,21 +8,20 @@ License : MIT License
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from config import POSITIVE_SAMPLE
|
|
|
|
from config import POSITIVE_SAMPLE
|
|
|
|
from config import NEGATIVE_SAMPLE
|
|
|
|
from config import NEGATIVE_SAMPLE
|
|
|
|
from config import TRAINING_IMG_HEIGHT
|
|
|
|
from config import TRAINING_IMG_HEIGHT
|
|
|
|
from config import TRAINING_IMG_WIDTH
|
|
|
|
from config import TRAINING_IMG_WIDTH
|
|
|
|
from config import FEATURE_FILE_TRAINING
|
|
|
|
from config import FEATURE_FILE_TRAINING
|
|
|
|
from config import FEATURE_NUM
|
|
|
|
from config import FEATURE_NUM
|
|
|
|
from config import ADABOOST_LIMIT
|
|
|
|
from config import ADABOOST_LIMIT
|
|
|
|
from config import ADABOOST_CACHE_FILE
|
|
|
|
from config import ADABOOST_CACHE_FILE
|
|
|
|
from config import DEBUG_MODEL
|
|
|
|
from config import DEBUG_MODEL
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from haarFeature import Feature
|
|
|
|
from haarFeature import Feature
|
|
|
|
from image import ImageSet
|
|
|
|
from image import ImageSet
|
|
|
|
from adaboost import AdaBoost
|
|
|
|
from adaboost import AdaBoost
|
|
|
|
from adaboost import getCachedAdaBoost
|
|
|
|
from adaboost import getCachedAdaBoost
|
|
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
import os
|
|
|
|
import numpy
|
|
|
|
import numpy
|
|
|
@ -30,17 +29,17 @@ import numpy
|
|
|
|
|
|
|
|
|
|
|
|
class Cascade:
|
|
|
|
class Cascade:
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, face_dir = "", nonface_dir = "", train = True, limit = 30):
|
|
|
|
def __init__(self, face_dir="", nonface_dir="", train=True, limit=30):
|
|
|
|
#tot_samples = 0
|
|
|
|
# tot_samples = 0
|
|
|
|
|
|
|
|
|
|
|
|
self.Face = ImageSet(face_dir, sampleNum = POSITIVE_SAMPLE)
|
|
|
|
self.Face = ImageSet(face_dir, sampleNum=POSITIVE_SAMPLE)
|
|
|
|
self.nonFace = ImageSet(nonface_dir, sampleNum = NEGATIVE_SAMPLE)
|
|
|
|
self.nonFace = ImageSet(nonface_dir, sampleNum=NEGATIVE_SAMPLE)
|
|
|
|
|
|
|
|
|
|
|
|
tot_samples = self.Face.sampleNum + self.nonFace.sampleNum
|
|
|
|
tot_samples = self.Face.sampleNum + self.nonFace.sampleNum
|
|
|
|
|
|
|
|
|
|
|
|
self.classifier = AdaBoost
|
|
|
|
self.classifier = AdaBoost
|
|
|
|
|
|
|
|
|
|
|
|
self.haar = Feature(TRAINING_IMG_WIDTH, TRAINING_IMG_HEIGHT)
|
|
|
|
self.haar = Feature(TRAINING_IMG_WIDTH, TRAINING_IMG_HEIGHT)
|
|
|
|
|
|
|
|
|
|
|
|
if os.path.isfile(FEATURE_FILE_TRAINING + ".npy"):
|
|
|
|
if os.path.isfile(FEATURE_FILE_TRAINING + ".npy"):
|
|
|
|
|
|
|
|
|
|
|
@ -50,14 +49,14 @@ class Cascade:
|
|
|
|
if DEBUG_MODEL is True:
|
|
|
|
if DEBUG_MODEL is True:
|
|
|
|
self._mat = numpy.zeros((self.haar.featuresNum, tot_samples))
|
|
|
|
self._mat = numpy.zeros((self.haar.featuresNum, tot_samples))
|
|
|
|
|
|
|
|
|
|
|
|
for i in xrange(self.Face.sampleNum):
|
|
|
|
for i in range(self.Face.sampleNum):
|
|
|
|
featureVec = self.haar.calFeatureForImg(self.Face.images[i])
|
|
|
|
featureVec = self.haar.calFeatureForImg(self.Face.images[i])
|
|
|
|
for j in xrange(self.haar.featuresNum):
|
|
|
|
for j in range(self.haar.featuresNum):
|
|
|
|
self._mat[j][i ] = featureVec[j]
|
|
|
|
self._mat[j][i] = featureVec[j]
|
|
|
|
|
|
|
|
|
|
|
|
for i in xrange(self.nonFace.sampleNum):
|
|
|
|
for i in range(self.nonFace.sampleNum):
|
|
|
|
featureVec = self.haar.calFeatureForImg(self.nonFace.images[i])
|
|
|
|
featureVec = self.haar.calFeatureForImg(self.nonFace.images[i])
|
|
|
|
for j in xrange(self.haar.featuresNum):
|
|
|
|
for j in range(self.haar.featuresNum):
|
|
|
|
self._mat[j][i + self.Face.sampleNum] = featureVec[j]
|
|
|
|
self._mat[j][i + self.Face.sampleNum] = featureVec[j]
|
|
|
|
|
|
|
|
|
|
|
|
numpy.save(FEATURE_FILE_TRAINING, self._mat)
|
|
|
|
numpy.save(FEATURE_FILE_TRAINING, self._mat)
|
|
|
@ -70,17 +69,16 @@ class Cascade:
|
|
|
|
|
|
|
|
|
|
|
|
featureNum, sampleNum = self._mat.shape
|
|
|
|
featureNum, sampleNum = self._mat.shape
|
|
|
|
|
|
|
|
|
|
|
|
assert sampleNum == (POSITIVE_SAMPLE + NEGATIVE_SAMPLE)
|
|
|
|
assert sampleNum == (POSITIVE_SAMPLE + NEGATIVE_SAMPLE)
|
|
|
|
assert featureNum == FEATURE_NUM
|
|
|
|
assert featureNum == FEATURE_NUM
|
|
|
|
|
|
|
|
|
|
|
|
Label_Face = [+1 for i in xrange(POSITIVE_SAMPLE)]
|
|
|
|
Label_Face = [+1 for i in range(POSITIVE_SAMPLE)]
|
|
|
|
Label_NonFace = [-1 for i in xrange(NEGATIVE_SAMPLE)]
|
|
|
|
Label_NonFace = [-1 for i in range(NEGATIVE_SAMPLE)]
|
|
|
|
|
|
|
|
|
|
|
|
self._label = numpy.array(Label_Face + Label_NonFace)
|
|
|
|
self._label = numpy.array(Label_Face + Label_NonFace)
|
|
|
|
self.limit = limit
|
|
|
|
self.limit = limit
|
|
|
|
self.classifierNum = 0
|
|
|
|
self.classifierNum = 0
|
|
|
|
self.strong_classifier = [None for i in xrange(limit)]
|
|
|
|
self.strong_classifier = [None for i in range(limit)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def train(self):
|
|
|
|
def train(self):
|
|
|
|
|
|
|
|
|
|
|
@ -92,10 +90,10 @@ class Cascade:
|
|
|
|
from config import LABEL_NEGATIVE
|
|
|
|
from config import LABEL_NEGATIVE
|
|
|
|
|
|
|
|
|
|
|
|
cur_fpr = 1.0
|
|
|
|
cur_fpr = 1.0
|
|
|
|
mat = self._mat
|
|
|
|
mat = self._mat
|
|
|
|
label = self._label
|
|
|
|
label = self._label
|
|
|
|
|
|
|
|
|
|
|
|
for i in xrange(self.limit):
|
|
|
|
for i in range(self.limit):
|
|
|
|
|
|
|
|
|
|
|
|
if cur_fpr < EXPECTED_FPR:
|
|
|
|
if cur_fpr < EXPECTED_FPR:
|
|
|
|
break
|
|
|
|
break
|
|
|
@ -103,12 +101,12 @@ class Cascade:
|
|
|
|
cache_filename = ADABOOST_CACHE_FILE + str(i)
|
|
|
|
cache_filename = ADABOOST_CACHE_FILE + str(i)
|
|
|
|
|
|
|
|
|
|
|
|
if os.path.isfile(cache_filename):
|
|
|
|
if os.path.isfile(cache_filename):
|
|
|
|
self.strong_classifier[i] = getCachedAdaBoost(mat = self._mat,
|
|
|
|
self.strong_classifier[i] = getCachedAdaBoost(mat=self._mat,
|
|
|
|
label = self._label,
|
|
|
|
label=self._label,
|
|
|
|
filename= cache_filename,
|
|
|
|
filename=cache_filename,
|
|
|
|
limit = ADABOOST_LIMIT)
|
|
|
|
limit=ADABOOST_LIMIT)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
self.strong_classifier[i] = AdaBoost(mat, label, limit = ADABOOST_LIMIT)
|
|
|
|
self.strong_classifier[i] = AdaBoost(mat, label, limit=ADABOOST_LIMIT)
|
|
|
|
output, fpr = self.strong_classifier[i].train()
|
|
|
|
output, fpr = self.strong_classifier[i].train()
|
|
|
|
|
|
|
|
|
|
|
|
cur_fpr *= fpr
|
|
|
|
cur_fpr *= fpr
|
|
|
@ -120,7 +118,6 @@ class Cascade:
|
|
|
|
|
|
|
|
|
|
|
|
self.classifierNum += 1
|
|
|
|
self.classifierNum += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def updateTrainingDate(self, mat, output, fp_num):
|
|
|
|
def updateTrainingDate(self, mat, output, fp_num):
|
|
|
|
|
|
|
|
|
|
|
|
fp_num = int(fp_num)
|
|
|
|
fp_num = int(fp_num)
|
|
|
@ -131,35 +128,33 @@ class Cascade:
|
|
|
|
|
|
|
|
|
|
|
|
_mat[:, :POSITIVE_SAMPLE] = mat[:, :POSITIVE_SAMPLE]
|
|
|
|
_mat[:, :POSITIVE_SAMPLE] = mat[:, :POSITIVE_SAMPLE]
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
for i in xrange(POSITIVE_SAMPLE):
|
|
|
|
for i in range(POSITIVE_SAMPLE):
|
|
|
|
for j in xrange(FEATURE_NUM):
|
|
|
|
for j in range(FEATURE_NUM):
|
|
|
|
mat[j][i] = self._mat[j][i]
|
|
|
|
mat[j][i] = self._mat[j][i]
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
counter = 0
|
|
|
|
counter = 0
|
|
|
|
# only reserve negative samples which are classified wrong
|
|
|
|
# only reserve negative samples which are classified wrong
|
|
|
|
for i in xrange(POSITIVE_SAMPLE, self._label.size):
|
|
|
|
for i in range(POSITIVE_SAMPLE, self._label.size):
|
|
|
|
if output[i] != self._label[i]:
|
|
|
|
if output[i] != self._label[i]:
|
|
|
|
for j in xrange(FEATURE_NUM):
|
|
|
|
for j in range(FEATURE_NUM):
|
|
|
|
_mat[j][POSITIVE_SAMPLE + counter] = mat[j][i]
|
|
|
|
_mat[j][POSITIVE_SAMPLE + counter] = mat[j][i]
|
|
|
|
counter += 1
|
|
|
|
counter += 1
|
|
|
|
|
|
|
|
|
|
|
|
assert counter == fp_num
|
|
|
|
assert counter == fp_num
|
|
|
|
|
|
|
|
|
|
|
|
Label_Face = [+1 for i in xrange(POSITIVE_SAMPLE)]
|
|
|
|
Label_Face = [+1 for i in range(POSITIVE_SAMPLE)]
|
|
|
|
Label_NonFace = [-1 for i in xrange(fp_num)]
|
|
|
|
Label_NonFace = [-1 for i in range(fp_num)]
|
|
|
|
|
|
|
|
|
|
|
|
_label = numpy.array(Label_Face + Label_NonFace)
|
|
|
|
_label = numpy.array(Label_Face + Label_NonFace)
|
|
|
|
|
|
|
|
|
|
|
|
return _mat, _label
|
|
|
|
return _mat, _label
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def predict(self):
|
|
|
|
def predict(self):
|
|
|
|
|
|
|
|
|
|
|
|
output = numpy.zeros(POSITIVE_SAMPLE + NEGATIVE_SAMPLE, dtype= numpy.float16)
|
|
|
|
output = numpy.zeros(POSITIVE_SAMPLE + NEGATIVE_SAMPLE, dtype=numpy.float16)
|
|
|
|
for i in xrange(self.classifierNum):
|
|
|
|
for i in range(self.classifierNum):
|
|
|
|
|
|
|
|
self.strong_classifier[i].prediction(output, th=0)
|
|
|
|
self.strong_classifier[i].prediction(mat, th = 0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""unfinished"""
|
|
|
|
"""unfinished"""
|
|
|
|
|
|
|
|
|
|
|
@ -168,4 +163,3 @@ class Cascade:
|
|
|
|
|
|
|
|
|
|
|
|
def is_goodenough(self):
|
|
|
|
def is_goodenough(self):
|
|
|
|
pass
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|