TensorFlow23: “恶作剧” --人脸检测

前面有一个帖《OpenCV检测场景内是否有移动物体》我用树莓派做了一个简单的Motion Detection,放在卫生间的,它会在我上大号时自动播放音乐。

我一个人租房,几个盆友周末时常会找我玩,他们觉得我做的Motion Detection很垃圾。于是我就想恶搞一下,用TensorFlow做一个“人脸识别”,在我上大号时播放音乐,如果是别人就播放《张震讲鬼故事》(@xingCI说放屁声更搞)。

我的任务的训练一个模型可以区分“我”和“其它人”的脸。注意,上面“人脸识别”我是加引号的,其实并不是真正的人脸识别,充其量就是个图像分类。如果你要使用真正的人脸识别,可以试试现成的库OpenFace+dlib《使用OpenFace进行人脸识别》。

有人已经把TensorFlow移植到了树莓派,项目地址tensorflow-on-raspberry-pi

准备数据

本帖需要使用到两组数据:一组是包含我脸的图像,另一组包含其它人人脸的图像。

其它人人脸的收集

找一堆图片,只要不包含自己就行,然后使用OpenCV提取图像中的大脸。

提取图像中的人脸,我使用OpenCV,据说使用dlib效果更好。

other_peoples_faces.py:

  1. import cv2  
  2. import os  
  3. import sys  
  4.    
  5. IMAGE_DIR = '图片目录路径'  
  6.    
  7. OUTPUT_DIR = './other_people'  
  8. if not os.path.exists(OUTPUT_DIR):  
  9.     os.makedirs(OUTPUT_DIR)  
  10.    
  11. # http://blog.topspeedsnail.com/archives/10511  
  12. # wget https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml  
  13. face_haar = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")  
  14.    
  15. for (dirpath, dirnames, filenames) in os.walk(IMAGE_DIR):  
  16.     for filename in filenames:  
  17.         if filename.endswith('.jpg'):  
  18.             image_path = os.path.join(dirpath, filename)  
  19.             print('process: ', image_path)  
  20.             img = cv2.imread(image_path)  
  21.               
  22.             gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
  23.             faces = face_haar.detectMultiScale(gray_image, 1.35)  
  24.             for face_x,face_y,face_w,face_h in faces:  
  25.                 face = img[face_y:face_y+face_h, face_x:face_x+face_w]  
  26.    
  27.                 face = cv2.resize(face, (6464))  
  28.    
  29.                 cv2.imshow("img", face)  
  30.                 cv2.imwrite(os.path.join(OUTPUT_DIR, filename), face)  
  31.    
  32.             key = cv2.waitKey(30) & 0xff  
  33.             if key == 27:  
  34.                 sys.exit(0)  

TensorFlow练习23: '恶作剧'

4万多图片,我只提取了1万张脸,应该够使了。

TensorFlow练习23: '恶作剧'图像大小 64×64

TensorFlow练习23: '恶作剧'

上面是OpenCV做的人脸检测,有了这个数据集又可以反过来训练TensorFlow版本的人脸检测。

斗大熊的脸

给自己拍照1万张,这是我一次拍照最多的一回。

  1. import cv2  
  2. import os  
  3. import sys  
  4.    
  5. OUTPUT_DIR = './my_faces'  
  6. if not os.path.exists(OUTPUT_DIR):  
  7.     os.makedirs(OUTPUT_DIR)  
  8.    
  9. face_haar = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")  
  10.    
  11. cam = cv2.VideoCapture(0)  
  12.    
  13. count = 0  
  14. while True:  
  15.     print(count)  
  16.     if count < 10000:  
  17.         _, img = cam.read()  
  18.    
  19.         gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
  20.         faces = face_haar.detectMultiScale(gray_image, 1.35)  
  21.         for face_x,face_y,face_w,face_h in faces:  
  22.             face = img[face_y:face_y+face_h, face_x:face_x+face_w]  
  23.    
  24.             face = cv2.resize(face, (6464))  
  25.             cv2.imshow('img', face)  
  26.             cv2.imwrite(os.path.join(OUTPUT_DIR, str(count)+'.jpg'), face)  
  27.             count += 1  
  28.         key = cv2.waitKey(30) & 0xff  
  29.         if key == 27:  
  30.             break  
  31.     else:  
  32.         break  

在镜头前摇头晃脑、摆pose,戴眼镜、耳机,仰天45,写代码,呲牙咧嘴,玩手机。。。一定要多样化,直到拍1万张大脸。

训练模型

训练数据有了,下面开始训练。

  1. import tensorflow as tf  
  2. import cv2  
  3. import numpy as np  
  4. import os  
  5. from sklearn.model_selection import train_test_split  
  6. import random  
  7. import sys  
  8.    
  9. my_image_path = 'my_faces'  
  10. others_image_path = 'other_people'  
  11.    
  12. image_data = []  
  13. label_data = []  
  14.    
  15. def get_padding_size(image):  
  16.     h, w, _ = image.shape  
  17.     longest_edge = max(h, w)  
  18.     top, bottom, left, right = (0000)  
  19.     if h < longest_edge:  
  20.         dh = longest_edge - h  
  21.         top = dh // 2  
  22.         bottom = dh - top  
  23.     elif w < longest_edge:  
  24.         dw = longest_edge - w  
  25.         left = dw // 2  
  26.         right = dw - left  
  27.     else:  
  28.         pass  
  29.     return top, bottom, left, right  
  30.    
  31. def read_data(img_path, image_h=64, image_w=64):  
  32.     for filename in os.listdir(img_path):  
  33.         if filename.endswith('.jpg'):  
  34.             filepath = os.path.join(img_path, filename)  
  35.             image = cv2.imread(filepath)  
  36.    
  37.             top, bottom, left, right = get_padding_size(image)  
  38.             image_pad = cv2.copyMakeBorder(image, top , bottom, left, right, cv2.BORDER_CONSTANT, value=[000])  
  39.             image = cv2.resize(image_pad, (image_h, image_w))  
  40.    
  41.             image_data.append(image)  
  42.             label_data.append(img_path)  
  43.    
  44. read_data(others_image_path)  
  45. read_data(my_image_path)  
  46.    
  47. image_data = np.array(image_data)  
  48. label_data = np.array([[0,1if label == 'my_faces' else [1,0for label in label_data])  
  49.    
  50. train_x, test_x, train_y, test_y = train_test_split(image_data, label_data, test_size=0.05, random_state=random.randint(0100))  
  51.    
  52. # image (height=64 width=64 channel=3)  
  53. train_x = train_x.reshape(train_x.shape[0], 64643)  
  54. test_x = test_x.reshape(test_x.shape[0], 64643)  
  55.    
  56. # nomalize  
  57. train_x = train_x.astype('float32') / 255.0  
  58. test_x = test_x.astype('float32') / 255.0  
  59.    
  60. print(len(train_x), len(train_y))  
  61. print(len(test_x), len(test_y))  
  62.    
  63. #############################################################  
  64. batch_size = 128  
  65. num_batch = len(train_x) // batch_size  
  66.    
  67. X = tf.placeholder(tf.float32, [None64643])  # 图片大小64x64 channel=3  
  68. Y = tf.placeholder(tf.float32, [None2])  
  69.    
  70. keep_prob_5 = tf.placeholder(tf.float32)  
  71. keep_prob_75 = tf.placeholder(tf.float32)  
  72.    
  73. def panda_joke_cnn():  
  74.    
  75.     W_c1 = tf.Variable(tf.random_normal([33332], stddev=0.01))  
  76.     b_c1 = tf.Variable(tf.random_normal([32]))  
  77.     conv1 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(X, W_c1, strides=[1111], padding='SAME'), b_c1))  
  78.     conv1 = tf.nn.max_pool(conv1, ksize=[1221], strides=[1221], padding='SAME')  
  79.     conv1 = tf.nn.dropout(conv1, keep_prob_5)  
  80.    
  81.     W_c2 = tf.Variable(tf.random_normal([333264], stddev=0.01))  
  82.     b_c2 = tf.Variable(tf.random_normal([64]))  
  83.     conv2 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv1, W_c2, strides=[1111], padding='SAME'), b_c2))  
  84.     conv2 = tf.nn.max_pool(conv2, ksize=[1221], strides=[1221], padding='SAME')  
  85.     conv2 = tf.nn.dropout(conv2, keep_prob_5)  
  86.    
  87.     W_c3 = tf.Variable(tf.random_normal([336464], stddev=0.01))  
  88.     b_c3 = tf.Variable(tf.random_normal([64]))  
  89.     conv3 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv2, W_c3, strides=[1111], padding='SAME'), b_c3))  
  90.     conv3 = tf.nn.max_pool(conv3, ksize=[1221], strides=[1221], padding='SAME')  
  91.     conv3 = tf.nn.dropout(conv3, keep_prob_5)  
  92.    
  93.     # Fully connected layer  
  94.     W_d = tf.Variable(tf.random_normal([8*16*32512], stddev=0.01))  
  95.     b_d = tf.Variable(tf.random_normal([512]))  
  96.     dense = tf.reshape(conv3, [-1, W_d.get_shape().as_list()[0]])  
  97.     dense = tf.nn.relu(tf.add(tf.matmul(dense, W_d), b_d))  
  98.     dense = tf.nn.dropout(dense, keep_prob_75)  
  99.    
  100.     W_out = tf.Variable(tf.random_normal([5122], stddev=0.01))  
  101.     b_out = tf.Variable(tf.random_normal([2]))  
  102.     out = tf.add(tf.matmul(dense, W_out), b_out)  
  103.     return out  
  104.    
  105. def train_cnn():  
  106.     output = panda_joke_cnn()  
  107.    
  108.     loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(output, Y))  
  109.     optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)  
  110.    
  111.     accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(output, 1), tf.argmax(Y, 1)), tf.float32))  
  112.    
  113.     tf.summary.scalar("loss", loss)  
  114.     tf.summary.scalar("accuracy", accuracy)  
  115.     merged_summary_op = tf.summary.merge_all()  
  116.    
  117.     saver = tf.train.Saver()  
  118.     with tf.Session() as sess:  
  119.         sess.run(tf.global_variables_initializer())  
  120.    
  121.         summary_writer = tf.summary.FileWriter('./log', graph=tf.get_default_graph())  
  122.    
  123.         for e in range(50):  
  124.             for i in range(num_batch):  
  125.                 batch_x = train_x[i*batch_size : (i+1)*batch_size]  
  126.                 batch_y = train_y[i*batch_size : (i+1)*batch_size]  
  127.                 _, loss_, summary = sess.run([optimizer, loss, merged_summary_op], feed_dict={X: batch_x, Y: batch_y, keep_prob_5:0.5, keep_prob_75: 0.75})  
  128.    
  129.                 summary_writer.add_summary(summary, e*num_batch+i)  
  130.                 print(e*num_batch+i, loss_)  
  131.    
  132.                 if (e*num_batch+i) % 100 == 0:  
  133.                     acc = accuracy.eval({X: test_x, Y: test_y, keep_prob_5:1.0, keep_prob_75: 1.0})  
  134.                     print(e*num_batch+i, acc)  
  135.                     # save model  
  136.                     if acc > 0.98:  
  137.                         saver.save(sess, "i_am_a_joke.model", global_step=e*num_batch+i)  
  138.                         sys.exit(0)  
  139.    
  140. train_cnn()  

准确率曲线:

TensorFlow练习23: '恶作剧'

下面要做的就是在树莓派上使用模型,代码示例:

  1. output = panda_joke_cnn()  
  2. predict = tf.argmax(output, 1)  
  3.    
  4. saver = tf.train.Saver()  
  5. sess = tf.Session()  
  6. saver.restore(sess, tf.train.latest_checkpoint('.'))  
  7.    
  8. def is_my_face(image):  
  9.     res = sess.run(predict, feed_dict={X: [image/255.0], keep_prob_5:1.0, keep_prob_75: 1.0})  
  10.     if res[0] == 1:  
  11.         return True  
  12.     else:  
  13.         return False  
  14.    
  15. face_haar = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")  
  16. cam = cv2.VideoCapture(0)  
  17.    
  18. while True:  
  19.     _, img = cam.read()  
  20.     gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
  21.     faces = face_haar.detectMultiScale(gray_image, 1.35)  
  22.     for face_x,face_y,face_w,face_h in faces:  
  23.         face = img[face_y:face_y+face_h, face_x:face_x+face_w]  
  24.    
  25.         face = cv2.resize(face, (6464))  
  26.    
  27.         print(is_my_face(face))  
  28.    
  29.         cv2.imshow('img', face)  
  30.         key = cv2.waitKey(30) & 0xff  
  31.         if key == 27:  
  32.             sys.exit(0)  
  33.    
  34. sess.close()  

总结:占用内存100多M,准确率还凑合,先用着。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值