(听着好像有点多余,原本就是要把灰度图转为csv来读取。。)
代码:
import numpy as np
import os
from PIL import Image
import cv2
import matplotlib.pyplot as plt
from tqdm import tqdm
import pandas as pd
#from config import *
import dlib
#********************check over
# 目的是实现从csv到jpg的转换
# conver_csv_to_jpg是实现转换
# crop_face_area是实现ROI区域的提取
def convert_csv_to_jpg(csv_path):
# 加载opencv的人脸识别文件
# 'haarcascade_frontalface_alt' 的准确度更高,但是速度更慢
# 'haarcascade_frontalface_default' 准确度较低,但是更快而且更轻巧
# detector = cv2.CascadeClassifier(haarcascade_frontalface_alt)
detector = dlib.get_frontal_face_detector()
landmark_predictor = dlib.shape_predictor(
'D:\\realsense_window\\CNN-Facial-Expression-Recognition-master\\data\\shape_predictor_68_face_landmarks.dat')
# 将csv通过PIL转换为jpg
data = pd.read_csv(csv_path, encoding="ISO-8859-1")
train_path_data = {'path': [], 'emotion': []}
valid_path_data = {'path': [], 'emotion': []}
test_path_data = {'path': [], 'emotion': []}
train_landmark = []
valid_landmark = []
test_landmark = []
if not os.path.exists(TRAIN_DIR):
os.mkdir(TRAIN_DIR)
if not os.path.exists(TEST_DIR):
os.mkdir(TEST_DIR)
if not os.path.exists(VALID_DIR):
os.mkdir(VALID_DIR)
total = 0
# 将cssv文件中的数据如emotion,pixel,usage打包成之后读取,同时需要处理多个数据的常用手段
for label, pixels, usage in tqdm(zip(data['emotion'], data['pixels'], data['Usage'])):
# 修改文件为指定大小
img = np.asarray(pixels.split()).astype(
np.int32).reshape([img_size, img_size])
# 裁剪文件为所需要的人脸部分
all_faces, all_landmarks = crop_face_area(
detector, landmark_predictor, img, img_size)
if all_faces is None:
continue
for img, landmarks in zip(all_faces, all_landmarks):
# fromarray可以说明img此时为np的矩阵格式,Image中的fromarray这个函数实现从矩阵保存的像素值到照片的转换
img = Image.fromarray(img).convert(mode='L') # 转为单通道
fname = str(total) + '.jpg' # filename的格式
# fer2013.csv中已经实现将各个csv文件的对应内容写好,包括pixel(与转换为照片有关),emotion(0-6对应于不同的情绪),usage对应于training,testing,validing
if usage == 'Training':
save_path = TRAIN_DIR + '\\' + fname # 文件的保存路径
train_path_data['path'].append(fname)
train_path_data['emotion'].append(label)
train_landmark.append(landmarks)
elif usage == 'PrivateTest':
save_path = VALID_DIR + '\\' + fname
valid_path_data['path'].append(fname)
valid_path_data['emotion'].append(label)
valid_landmark.append(landmarks)
else:
save_path = TEST_DIR + '\\' + fname
test_path_data['path'].append(fname)
test_path_data['emotion'].append(label)
test_landmark.append(landmarks)
img.save(save_path)
total += 1
# 将train_landmark中的内容转为array格式,np.asarray(file,dtype=floatxx,ord)
train_landmark = np.asarray(train_landmark)
valid_landmark = np.asarray(valid_landmark)
test_landmark = np.asarray(test_landmark)
np.savez(TRAIN_LANDMARK_PATH, landmark=train_landmark) # 生成npz的压缩文件
np.savez(VALID_LANDMARK_PATH, landmark=valid_landmark)
np.savez(TEST_LANDMARK_PATH, landmark=test_landmark)
# dataframe是pandas的存储数据的方式,类似与matlab的矩阵和excel的表格,第一个参数与是用于存储的数据,可以是字符什么的,
# 第二个数据index和第三个数据column分别代表行和列的标记,注意长度要和所给数据的行列大小一致
# 例如df=pd.DataFrame([[1,2,3,4],[2,3,4,5],
# [3,4,5,6],[4,5,6,7]],
# index=list('ABCD'),columns=list('ABCD'))
# df=
'''A B C D
A 1 2 3 4
B 2 3 4 5
C 3 4 5 6
D 4 5 6 7
'''
train_path_data = pd.DataFrame(train_path_data)
train_path_data.to_pickle(TRAIN_PATH)
valid_path_data = pd.DataFrame(valid_path_data)
valid_path_data.to_pickle(VALID_PATH)
test_path_data = pd.DataFrame(test_path_data)
test_path_data.to_pickle(TEST_PATH)
# 输出training,testing,validing中文件的个数
print('Total: {}, training: {}, valid: {}, test: {}'.format(
total, len(train_path_data), len(valid_path_data), len(test_path_data)))
def crop_face_area(detector, landmark_predictor, image, img_size):
"""
裁剪图像的人脸部分,并resize到img_size尺寸
:param detector:
:param image:
:param img_size:
:return: Two numpy arrays containing the area and landmarks of all faces.
None if no face was detected.
"""
# p_img = Image.fromarray(image).convert(mode='RGB')
# cv_img = cv2.cvtColor(np.asarray(p_img), cv2.COLOR_RGB2GRAY)
# faces = detector.detectMultiScale(
# image=cv_img,
# scaleFactor=1.1,
# minNeighbors=1,
# minSize=(30, 30),
# flags=0
# )
# if len(faces) != 0:
# x, y, w, h = faces[0]
# cv_img = cv2.resize(cv_img[x:x + w, y:y + h], (img_size, img_size))
# return np.asarray(cv_img)
# else:
# return None
# 将image从np.array转化为RGB的照片的格式
p_img = Image.fromarray(image).convert(mode='RGB')
# 将P_img从RGB转为灰度图
cv_img = cv2.cvtColor(np.asarray(p_img), cv2.COLOR_RGB2GRAY)
# 检测灰度图cv_img中的人脸
faces = detector(cv_img, 1)
all_landmarks = []
all_faces = []
if len(faces) > 0:
for face in faces:
shape = landmark_predictor(cv_img, face)
landmarks = np.ndarray(shape=[68, 2])
for i in range(68):
landmarks[i] = (shape.part(i).x, shape.part(i).y)
all_landmarks.append(landmarks)
x1, y1, x2, y2 = face.left(), face.top(), face.right(), face.bottom()
# 裁剪照片多余的部分
if x1 < 0:
x1 = 0
if x1 > cv_img.shape[1]:
x1 = cv_img.shape[1]
if x2 < 0:
x2 = 0
if x2 > cv_img.shape[1]:
x2 = cv_img.shape[1]
if y1 < 0:
y1 = 0
if y1 > cv_img.shape[0]:
y1 = cv_img.shape[0]
if y2 < 0:
y2 = 0
if y2 > cv_img.shape[0]:
y2 = cv_img.shape[0]
img = cv2.resize(cv_img[y1:y2, x1:x2], (img_size, img_size))
all_faces.append(img)
# 返回每张照片img中的人脸所在的位置
return np.asarray(all_faces), np.asarray(all_landmarks)
else:
return None, None
'''
def count_lines(csv_path):
data = pd.read_csv(csv_path, encoding="ISO-8859-1")
return data.shape[0]
#data.shape[0]代表csv文件中有多少行,也即有多少张照片
'''
'''
def show_class_distribution(file_path):
label_num = np.zeros([7], dtype=np.int32)
data = pd.read_csv(file_path)
for label in data['emotion']:
label_num[label] += 1 # get the name of emotions alreay-known
rects = plt.bar(class_names, label_num)
plt.title('Label Distribution')
plt.xlabel("Label")
plt.ylabel("Number")
for rect in rects:
height = rect.get_height()
plt.text(rect.get_x() + rect.get_width() / 2, height +
1, str(height), ha="center", va="bottom")
plt.show()
'''
if __name__ == '__main__':
DATA_PATH = 'D:\\2019-10-19\\csv\\fer2013_2.csv'
convert_csv_to_jpg(DATA_PATH)