Python, OpenCV: classify gender using ORB features and KNN -
task: classify images of human faces female or male. training images labels available, obtain test image webcam.
using: python 2.7, opencv 2.4.4
i using orb extract features grayscale image hope use training k-nearest neighbor classifier. each training image of different person number of keypoints , descriptors each image different. problem i'm not able understand opencv docs knn , orb. i've seen other questions orb, knn , flann didn't much.
what nature of descriptor given orb? how different descriptors obtained brief, surf, sift, etc.?
it seems feature descriptors should of same size each training sample in knn. how make sure descriptors of same size each image? more generally, in format should features presented knn training given data , labels? should data int or float? can char?
the training data can found here.
i using haarcascade_frontalface_alt.xml
opencv samples
right knn model given 10 images training see if program passes without errors which, not.
here code:
import cv2 numpy import float32 np.float32 def choosecascade(): # todo: option diferent cascades # haar classifier frontal face _cascade = cv2.cascadeclassifier('haarcascade_frontalface_alt.xml') return _cascade def croptoobj(cascade,imagefile): # load 1-channel grayscale image image = cv2.imread(imagefile,0) # crop object of interest in image objregion = cascade.detectmultiscale(image) # todo: if multiple ojbects in image? x1 = objregion[0,0] y1 = objregion[0,1] x1pluswidth = objregion[0,0]+objregion[0,2] y1plusheight = objregion[0,1]+objregion[0,3] _objimage = image[y1:y1plusheight,x1:x1pluswidth] return _objimage def recognizer(filenames): # orb contructor orb = cv2.orb(nfeatures=100) keypoints = [] descriptors = [] # cascade face detection haarfacecascade = choosecascade() # start processing images imagefile in filenames: # find faces using haar cascade faceimage = croptoobj(haarfacecascade,imagefile) # extract keypoints , description facekeypoints, facedescriptors = orb.detectandcompute(faceimage, mask = none) #print facedescriptors.shape descrow = facedescriptors.shape[0] desccol = facedescriptors.shape[1] flatfacedescriptors = facedescriptors.reshape(descrow*desccol).astype(np.float32) keypoints.append(facekeypoints) descriptors.append(flatfacedescriptors) print descriptors # knn model , training on descriptors responses = [] name in filenames: if name.startswith('bf'): responses.append(0) # female else: responses.append(1) # male knn = cv2.knearest() knntrainsuccess = knn.train(descriptors, responses, isregression = false) # isregression = false, implies classification # obtain test face image cam capture = cv2.videocapture(0) closecamera = -1 while(closecamera < 0): _retval, _camimage = capture.retrieve() # find face in camera image testfaceimage = haarfacecascade.detectmultiscale(_camimage) # todo: if multiple faces? # keyponts , descriptors of test face image testfacekp, testfacedesc = orb.detectandcompute(testfaceimage, mask = none) testdescrow = testfacedesc.shape[0] flattestfacedesc = testfacedesc.reshape(1,testdescrow*testdesccol).astype(np.float32) # args in knn.find_nearest: testdata, neighborhood returnedvalue, result, neighborresponse, distance = knn.find_nearest(flattestfacedesc,3) print returnedvalue, result, neighborresponse, distance # display results # todo: overlay classification text cv2.imshow("testimage", _camimage) closecamera = cv2.waitkey(1) cv2.destroyallwindows() if __name__ == '__main__': filenames = ['bf09nes_gray.jpg', 'bf11nes_gray.jpg', 'bf13nes_gray.jpg', 'bf14nes_gray.jpg', 'bf18nes_gray.jpg', 'bm25nes_gray.jpg', 'bm26nes_gray.jpg', 'bm29nes_gray.jpg', 'bm31nes_gray.jpg', 'bm34nes_gray.jpg'] recognizer(filenames)
currently getting error @ line knn.train()
descriptors
not detected numpy array.
also, approach wrong? supposed use other way gender classification? wasn't satisfied fisherface , eigenface example in opencv facerec demo please don't direct me those.
any other appreciated. thanks.
--- edit ---
i've tried few things , come answer.
i still hoping in community can me suggesting idea don't have hardcode things solution. suspect knn.match_nearest() isn't doing need do.
and expected, recognizer not @ accurate , prone giving misclassification due rotation, lighting, etc. suggestions on improving approach appreciated.
the database using training is: karolinska directed emotional faces
i have doubts on effectiveness/workability of described approach. here's approach might want consider. contents of gen
folder @ http://www1.datafilehost.com/d/0f263abc. note when data size gets bigger(~10k training samples), size of model may become unacceptable(~100-200mb). need pca/lda etc.
import cv2 import numpy np import os def feacnt(): mat = np.zeros((400,400,3),dtype=np.uint8) ret = extr(mat) return len(ret) def extr(img): return sobel(img) def sobel(img): gray = cv2.cvtcolor(img,cv2.color_bgr2gray) klr = [[-1,0,1],[-2,0,2],[-1,0,1]] kbt = [[1,2,1],[0,0,0],[-1,-2,-1]] ktb = [[-1,-2,-1],[0,0,0],[1,2,1]] krl = [[1,0,-1],[2,0,-2],[1,0,-1]] kd1 = [[0,1,2],[-1,0,1],[-2,-1,0]] kd2 = [[-2,-1,0],[-1,0,1],[0,1,2]] kd3 = [[0,-1,-2],[1,0,-1],[2,1,0]] kd4 = [[2,1,0],[1,0,-1],[0,-1,-2]] karr = np.asanyarray([ klr, kbt, ktb, krl, kd1, kd2, kd3, kd4 ]) gray=cv2.resize(gray,(40,40)) res = np.float32([cv2.resize(cv2.filter2d(gray, -1,k),(15,15)) k in karr]) return res.flatten() root = 'c:/data/gen' model='c:/data/models/svm/gen.xml' imgs = [] idx =0 path, subdirs, files in os.walk(root): name in files: p =path[len(root):].split('\\') p.remove('') lbl = p[0] fpath = os.path.join(path, name) imgs.append((fpath,int(lbl))) idx+=1 samples = np.zeros((len(imgs),feacnt()),dtype = np.float32) labels = np.zeros(len(imgs),dtype = np.float32) i=0. f,l in imgs: print img = cv2.imread(f) samples[i]=extr(img) labels[i]=l i+=1 svm = cv2.svm() svmparams = dict( kernel_type = cv2.svm_poly, svm_type = cv2.svm_c_svc, degree=3.43, gamma=1.5e-4, coef0=1e-1, ) print 'svm train' svm.train(samples,labels,params=svmparams) svm.save(model) print 'done' result = np.float32( [(svm.predict(s)) s in samples]) correct=0. total=0. i,j in zip(result,labels): total+=1 if i==j: correct+=1 print '%f'%(correct/total)
Comments
Post a Comment