参加学校的国创比赛的时候,我们小组的项目有一部分内容需要用到利用摄像头实现实时检测人脸的表情,因为最近都在看深度学习方面的相关知识,所以就自己动手实现了一下这个小Demo.参考网上的资料,发现大部分是使用CNN和DNN进行学习,经过本人亲自实践,我发现DNN的识别效果更佳~(楼主接下来就要讲的是基于DNN的模型,要是你对CNN的模型感兴趣,欢迎私戳楼主~)

所需环境:opencv + tensorflow1.8 + pycharm

代码以及模型的下载地址:https://github.com/tgpcai/Microexpression_recognition(如果喜欢请帮楼主点个start~)

最后实现的结果图:

目录

1.数据集简介

2.代码实现

(0)实现Demo的代码组织结构

(1)数据预处理

(2)训练模型

(3)调用模型实现人脸微表情识别

3.个人遇坑以及总结


1.数据集简介

人脸表情识别程序所采用的数据集为FER2013(facial-expression-recognition 2013)以及中科院的微表情数据,该数据集需要在kaggle网

站上进行下载,下载地址为:https://www.kaggle.com/c/challenges-in-representation-learning-facial-expression-recognition-challenge/data

下载的数据是压缩文件,对其进行手动解压,解压后文件格式是csv,文件名为fer2013.csv,对这个文件进行提取可以得到三个文件,具体的提取过程会在后续进行介绍:

其中train文件的emotion一共有7种,csv文件中每个数字对应一种表情,7种表情包括:0 - 'angry', 1 - 'disgusted',2 - 'fearful', 3 - 'happy', 4 - 'sad', 5 - 'surprised', 6 - 'neutral'(这也是咱们能识别的表情)

打开train.csv文件每一行除了emotion的标记之外,还有一幅影像,只不过在csv文件里,影像用灰度值表示了,csv文件打开之后,里面的内容如下:

不过可能由于FER2013数据集的质量不太好,大部分模型的验证精度只有60%(如googleNet和AlexNet都只有63%)左右,好一点的可以到70%。我自己训练的模型验证经度只有55-56左右!

网上很多参考资料都把灰度值表示的影像变成了.jpg能看的图片,但实际上并不需要这样做,因为你把这灰度值的影像变为.jpg,后面还是需要经过一系列步骤在转换成灰度值,不过我也会贴出如何把这灰度值影响变为.jpg结尾的图片!

中科院的数据集如下:

同样对其进行灰度化、图像大小的处理,之后方可当成输入数据进行模型的训练。

 2.代码实现

 (0)实现Demo的代码组织结构

demo.py 调用系统摄像头完成实时识别人脸微表情

main.py 包含训练模型、测试模型的接口

model.py DNN算法的实现

utils.py 对数据集合的预处理

(1)数据预处理

  有两种方式,第一种方式只是为了看看数据集的图片,而不是只能看到灰度值,而真正参与模型的训练的数据处理方式是第二种!

  1)把这灰度值的影像变为.jpg

 import csv
import os #数据集路径
database_path = 'C:/Users/tgp/Desktop/Machine Learning/人脸识别/fer2013' #将路径组合后返回
csv_file = os.path.join(database_path, 'fer2013.csv')
train_csv = os.path.join(database_path, 'train.csv')
val_csv = os.path.join(database_path, 'val.csv')
test_csv = os.path.join(database_path, 'test.csv') with open(csv_file) as f:
#使用csv中的reader()打开.csv文件
csvr = csv.reader(f) #将迭代器指向文件的第二行,因为第一行为标签
header = next(csvr)
rows = [row for row in csvr] #按最后一列的标签将数据集进行分割
trn = [row[:-1] for row in rows if row[-1] == 'Training']
csv.writer(open(train_csv, 'w+'), lineterminator='\n').writerows([header[:-1]] + trn)
print(len(trn)) val = [row[:-1] for row in rows if row[-1] == 'PublicTest']
csv.writer(open(val_csv, 'w+'), lineterminator='\n').writerows([header[:-1]] + val)
print(len(val)) tst = [row[:-1] for row in rows if row[-1] == 'PrivateTest']
csv.writer(open(test_csv, 'w+'), lineterminator='\n').writerows([header[:-1]] + tst)
print(len(tst))
 import csv
import os
from PIL import Image
import numpy as np database_path = 'C:/Users/tgp/Desktop/Machine Learning/人脸识别/fer2013' train_csv = os.path.join(database_path, 'train.csv')
val_csv = os.path.join(database_path, 'val.csv')
test_csv = os.path.join(database_path, 'test.csv') train_set = os.path.join(database_path, 'train')
val_set = os.path.join(database_path, 'val')
test_set = os.path.join(database_path, 'test') for save_path, csv_file in [(train_set, train_csv), (val_set, val_csv), (test_set, test_csv)]:
if not os.path.exists(save_path):
os.makedirs(save_path) num = 1
with open(csv_file) as f:
csvr = csv.reader(f)
header = next(csvr)
#使用enumerate遍历csvr中的标签(label)和特征值(pixel)
for i, (label, pixel) in enumerate(csvr):
#将特征值的数组转化为48*48的矩阵
pixel = np.asarray([float(p) for p in pixel.split()]).reshape(48, 48)
subfolder = os.path.join(save_path, label)
if not os.path.exists(subfolder):
os.makedirs(subfolder)
#将该矩阵转化为RGB图像,再通过convert转化为8位灰度图像,L指灰度图模式,L=R*299/1000+G*587/1000+B*114/1000
im = Image.fromarray(pixel).convert('L')
image_name = os.path.join(subfolder, '{:05d}.jpg'.format(i))
print(image_name)
im.save(image_name)

执行完上面的代码,你就可以在相应的路径看到如下图:

这样就完成了从灰度图到可视化的转变。

  2)简便的数据预处理(训练模型时采用的办法)

 import collections
import numpy as np
import pandas as pd
from tensorflow.python.framework import dtypes, random_seed def load_data(data_file):
data = pd.read_csv(data_file)
pixels = data['pixels'].tolist()
width = 48
height = 48
faces = []
for pixel_sequence in pixels:
# 从csv中获取人脸的数据
face = [int(pixel) for pixel in pixel_sequence.split(' ')]
# 把脸的数据变为48*48像素,利用plt.imshow即可打印出图片
face = np.asarray(face).reshape(width, height)
faces.append(face)
# 把faces从列表变为三维矩阵。(35887,)----->(35887,48,48)
faces = np.asarray(faces)
# 添加维度,将faces从(35887,48,48)------>(35887,48,48,1)
faces = np.expand_dims(faces, -1)
# one-hot编码,把属于该类表情置1,其余为0,并转换为矩阵
emotions = pd.get_dummies(data['emotion']).as_matrix()
return faces, emotions class DataSet(object):
def __init__(self, images, labels, reshape=True, dtype=dtypes.float32, seed=None):
seed1, seed2 = random_seed.get_seed(seed)
np.random.seed(seed1 if seed is None else seed2)
if reshape:
# 将images(35887,48,48,1)变为(35887,2304)
assert images.shape[3] == 1
images = images.reshape(images.shape[0],images.shape[1]*images.shape[2]) # 类型转换,并进行灰度处理
if dtype == dtypes.float32:
images = images.astype(np.float32)
images = np.multiply(images, 1.0 / 255.0)
# 设置私有属性
self._num_examples = images.shape[0]
self._images = images
self._labels = labels
self._epochs_completed = 0
self._index_in_epoch = 0 @property
def images(self):
return self._images @property
def labels(self):
return self._labels @property
def num_examples(self):
return self.num_examples @property
def epochs_completed(self):
self._epochs_completed # 批量获取训练数据
def next_batch(self, batch_size,shuffle=True):
start = self._index_in_epoch
if self._epochs_completed == 0 and start == 0 and shuffle:
# 打乱顺序
perm0 = np.arange(self._num_examples)
np.random.shuffle(perm0)
self._images = self._images[perm0]
self._labels = self._labels[perm0] if start + batch_size > self._num_examples:
self._epochs_completed += 1
rest_num_examples = self._num_examples - start
images_rest_part = self._images[start:self._num_examples]
labels_rest_part = self._labels[start:self._num_examples]
# 当剩余的数据不够一次batch_size,就在之前的数据中随机选取并进行组合
if shuffle:
perm = np.arange(self._num_examples)
np.random.shuffle(perm)
self._images = self._images[perm]
self._labels = self._labels[perm]
start = 0
self._index_in_epoch = batch_size - rest_num_examples
end = self._index_in_epoch
images_new_part = self._images[start:end]
labels_new_part = self._labels[start:end]
return np.concatenate((images_rest_part, images_new_part), axis=0), np.concatenate(
(labels_rest_part, labels_new_part), axis=0)
else:
self._index_in_epoch += batch_size
end = self._index_in_epoch
return self._images[start:end], self._labels[start:end] def input_data(train_dir, dtype = dtypes.float32, reshape = True, seed=None):
training_size = 28709
validation_size = 3589
test_size = 3589 train_faces, train_emotions = load_data(train_dir)
print("Data load success!") # 验证数据
validation_faces = train_faces[training_size: training_size + validation_size]
validation_emotions = train_emotions[training_size: training_size + validation_size] # 测试数据
test_faces = train_faces[training_size + validation_size:]
test_emotions = train_emotions[training_size + validation_size:] # 训练数据
train_faces = train_faces[: training_size]
train_emotions = train_emotions[: training_size] Datasets = collections.namedtuple('Datasets', ['train', 'validation', 'test'])
train = DataSet(train_faces, train_emotions, reshape=reshape,)
validation = DataSet(validation_faces, validation_emotions, dtype=dtype, reshape=reshape, seed=seed)
test = DataSet(test_faces, test_emotions, dtype=dtype, reshape=reshape, seed=seed)
return Datasets(train=train, validation=validation, test=test)

到此,我们就完成了对fer2013数据的处理。

 (2)训练模型

采用的是DNN模型,个人感觉DNN的大致过程和CNN较为相似,楼主有一篇博客就是利用CNN实现手写数字的识别,感兴趣或者对于DNN实现算法不是很理解的,可以跳过去看看。

 import os
import cv2
import tensorflow as tf
from utils import * EMOTIONS = ['angry', 'disgusted', 'fearful', 'happy', 'sad', 'surprised', 'neutral'] def deepnn(x):
x_image = tf.reshape(x, [-1, 48, 48, 1])
# conv1
W_conv1 = weight_variables([5, 5, 1, 64])
b_conv1 = bias_variable([64])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
# pool1
h_pool1 = maxpool(h_conv1)
# norm1
norm1 = tf.nn.lrn(h_pool1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75) # conv2
W_conv2 = weight_variables([3, 3, 64, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
norm2 = tf.nn.lrn(h_conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75)
h_pool2 = maxpool(norm2) # Fully connected layer
W_fc1 = weight_variables([12 * 12 * 64, 384])
b_fc1 = bias_variable([384])
h_conv3_flat = tf.reshape(h_pool2, [-1, 12 * 12 * 64])
h_fc1 = tf.nn.relu(tf.matmul(h_conv3_flat, W_fc1) + b_fc1) # Fully connected layer
W_fc2 = weight_variables([384, 192])
b_fc2 = bias_variable([192])
h_fc2 = tf.matmul(h_fc1, W_fc2) + b_fc2 # linear
W_fc3 = weight_variables([192, 7])
b_fc3 = bias_variable([7])
y_conv = tf.add(tf.matmul(h_fc2, W_fc3), b_fc3) return y_conv def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME') def maxpool(x):
return tf.nn.max_pool(x, ksize=[1, 3, 3, 1],
strides=[1, 2, 2, 1], padding='SAME') def weight_variables(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial) def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial) def train_model(train_data):
fer2013 = input_data(train_data)
max_train_steps = 30001 x = tf.placeholder(tf.float32, [None, 2304])
y_ = tf.placeholder(tf.float32, [None, 7]) y_conv = deepnn(x) cross_entropy = tf.reduce_mean(
tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) with tf.Session() as sess:
saver = tf.train.Saver()
sess.run(tf.global_variables_initializer()) for step in range(max_train_steps):
batch = fer2013.train.next_batch(25)
if step % 100 == 0:
train_accuracy = accuracy.eval(feed_dict={x: batch[0], y_: batch[1]})
print('step %d, training accuracy %g' % (step, train_accuracy))
if step + 1 == max_train_steps:
saver.save(sess, './models/emotion_model', global_step=step + 1)
train_step.run(feed_dict={x: batch[0], y_: batch[1]}) def image_to_tensor(image):
tensor = np.asarray(image).reshape(-1, 2304) * 1 / 255.0
return tensor

训练完模型后在你相应的文件夹里面会出现如下图所示:

这就是训练模型保存的参数,楼主最后也会贴出自己训练的模型,方便你们下载和使用。

(3)调用模型实现人脸微表情识别

采用的方法是调用摄像头实时识别人脸微表情,具体的过程为:调用opencv自带的人脸识别器,调用系统摄像头拍摄出人脸图片,对人脸图片进行预处理,将处理完成的图片传入模型,最后将模型分析的结果反馈至运行的窗口

如下图所示:这些都是opencv自带的有关脸部识别的识别器。

一般采用的是这几个:

其中个人认为_alt2的识别器效果最好。

具体如何调用系统摄像头以及实时别人微表情的代码如下:

 import cv2
import numpy as np
import sys
import tensorflow as tf
import PIL.Image as Image
import matplotlib.pyplot as plt
from model import * # 加载opencv自带的人脸识别器
CASC_PATH = 'D:/Anaconda3/Lib/site-packages/cv2/data/haarcascade_frontalface_alt2.xml'
cascade_classifier = cv2.CascadeClassifier(CASC_PATH)
# 人脸七种微表情
EMOTIONS = ['angry', 'disgusted', 'fearful', 'happy', 'sad', 'surprised', 'neutral'] def format_image(image):
# image如果为彩色图:image.shape[0][1][2](水平、垂直像素、通道数)
if len(image.shape) > 2 and image.shape[2] == 3:
# 将图片变为灰度图
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 它可以检测出图片中所有的人脸,并将人脸用vector保存各个人脸的坐标、大小(用矩形表示)
# 调整scaleFactor参数的大小,可以增加识别的灵敏度,推荐1.1
faces = cascade_classifier.detectMultiScale(image, scaleFactor=1.1, minNeighbors=5)
# 如果图片中没有检测到人脸,则返回None
if not len(faces) > 0:
return None, None
# max_are_face包含了人脸的坐标,大小
max_are_face = faces[0]
# 在所有人脸中选一张最大的脸
for face in faces:
if face[2] * face[3] > max_are_face[2] * max_are_face[3]:
max_are_face = face # 这两步可有可无
face_coor = max_are_face
image = image[face_coor[1]:(face_coor[1] + face_coor[2]), face_coor[0]:(face_coor[0] + face_coor[3])]
# 调整图片大小,变为48*48
try:
image = cv2.resize(image, (48, 48), interpolation=cv2.INTER_CUBIC)
except Exception:
print("problem during resize")
return None, None return image, face_coor def demo(modelPath, showBox=True):
# 调用模型分析人脸微表情
# tf.reset_default_graph()
face_x = tf.placeholder(tf.float32, [None, 2304])
y_conv = deepnn(face_x)
probs = tf.nn.softmax(y_conv) # 加载模型
saver = tf.train.Saver()
ckpt = tf.train.get_checkpoint_state(modelPath)
sess = tf.Session()
if ckpt and ckpt.model_checkpoint_path:
saver.restore(sess, ckpt.model_checkpoint_path)
print("Restore model sucsses!!\nNOTE: Press 'a' on keyboard to capture face.") # feelings_facesy用来存储emojis表情
feelings_faces = []
for index, emotion in enumerate(EMOTIONS):
# imread函数(文件路径,读取方式)
# cv2.IMREAD_COLOR:读入一副彩色图片;(1)返回三维矩阵,且为[120,120,3]
# cv2.IMREAD_GRAYSCALE:以灰度模式读入图片;(0)返回二维矩阵,且为[120,120]
# cv2.IMREAD_UNCHANGED:读入一幅图片,并包括其alpha通道(-1)返回三维矩阵,且为[120,120,4]
feelings_faces.append(cv2.imread('D:/Dict/Facial-Expression-Recognition-master/data/emojis/' + emotion + '.png', 1)) # 获取笔记本的摄像头,
video_captor = cv2.VideoCapture(0) emoji_face = []
result = None
while True:
# 获取摄像头的每帧图片,若获得,则ret的值为True,frame就是每一帧的图像,是个三维矩阵
ret, frame = video_captor.read() detected_face, face_coor = format_image(frame)
if showBox:
if face_coor is not None:
# 获取人脸的坐标,并用矩形框出
[x, y, w, h] = face_coor
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 255, 0), 2) # 每隔10ms刷新一次,并且等当键盘输入a的时候,截取图像,因为是64位系统所以必须要0xFF == ord('a')
if cv2.waitKey(1) & 0xFF == ord('a'):
if detected_face is not None:
cv2.imwrite('a.jpg', detected_face)
print(detected_face)
print("获取成功")
# 将图片变为tensorflow可以接受的格式
tensor = image_to_tensor(detected_face)
result = sess.run(probs, feed_dict={face_x: tensor})
print(result) if result is not None:
for index, emotion in enumerate(EMOTIONS):
# 将七种微表情的文字添加到图片中
cv2.putText(frame,emotion,(10,index*20 + 20),cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1)
# 将七种微表情的概率用矩形表现出来
cv2.rectangle(frame,(130, index*20 + 10),(130+int(result[0][index]*100), (index + 1) * 20 + 4), (255, 0, 0), -1)
# 获取人脸微表情相应的emojis表情
emoji_face = feelings_faces[np.argmax(result[0])] # 将emojis表情添加到图片中的指定位置 方法1:
frame[200:320, 10:130, :] = emoji_face[:, :, :]
cv2.imwrite('b.jpg', frame)
# 将emojis表情添加到图片中的指定位置 方法2:
# for c in range(0, 1):
# frame[200:320, 10:130, c] = emoji_face[:, :, c] * (emoji_face[:, :, 3] / 255.0) + frame[200:320, 10:130, c] * (1.0 - emoji_face[:, :, 3] / 255.0) cv2.imshow('face', frame)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
# 释放系统摄像头,关闭窗口
video_captor.release()
cv2.destroyAllWindows()

到此整个Demo就实现完成了。

3.个人遇坑以及总结

(1)数据预处理过程,大多都需要用到pandas和numpy这两个库,所以必须能够较为熟练的掌握这两个库的使用

(2)网上的考察资料中对于调用 cascade_classifier.detectMultiScale这个函数时,对其一个参数scaleFactor设置为1.3,这直接导致对于人脸的识别不够敏感,上网参阅相关资料后,得知这个值一般设置为1.1较为合适,且对于人脸的识别也比较敏感

(3)因为对于opencv这个库使用不够熟练,一开始一直碰壁,所以你要是和我一样,建议先去这个网站了解一下OPENCV的大致使用方法:https://docs.opencv.org/trunk/d6/d00/tutorial_py_root.html

4.该模型的不足以及日后的发展

(1)目前划分的微表情类别较少,难以覆盖人类多种交织的表情。

(2)对于某人表情识别的准备率还不够高,例如厌恶。

(3)模型未能处理多帧连续表情的变化,这将限制我们对少数微表情的识别的准确率。

5.完善算法以及平台的应用

(1)采用LSTM(长短时记忆算法),新增加一个时间维度用于记录多帧微表情的变化,然后在结果DNN模型完善算法。

(2)可以将此项目应用于检测疲劳驾驶以及刑侦等领域

参考资料:https://docs.opencv.org/trunk/d6/d00/tutorial_py_root.html

     https://blog.csdn.net/labPqsdr/article/details/80704969


以上就是本次Demo的完成过程以及体会,欢迎交流

tensorflow下基于DNN实现实时分辨人脸微表情的更多相关文章

  1. 一文详解如何用 TensorFlow 实现基于 LSTM 的文本分类(附源码)

    雷锋网按:本文作者陆池,原文载于作者个人博客,雷锋网已获授权. 引言 学习一段时间的tensor flow之后,想找个项目试试手,然后想起了之前在看Theano教程中的一个文本分类的实例,这个星期就用 ...

  2. 大数据下基于Tensorflow框架的深度学习示例教程

    近几年,信息时代的快速发展产生了海量数据,诞生了无数前沿的大数据技术与应用.在当今大数据时代的产业界,商业决策日益基于数据的分析作出.当数据膨胀到一定规模时,基于机器学习对海量复杂数据的分析更能产生较 ...

  3. 关于运行“基于极限学习机ELM的人脸识别程序”代码犯下的一些错误

    代码来源 基于极限学习机ELM的人脸识别程序 感谢文章主的分享 我的环境是 win10 anaconda Command line client (version 1.6.5)(conda 4.3.3 ...

  4. 转:基于开源项目OpenCV的人脸识别Demo版整理(不仅可以识别人脸,还可以识别眼睛鼻子嘴等)【模式识别中的翘楚】

    文章来自于:http://blog.renren.com/share/246648717/8171467499 基于开源项目OpenCV的人脸识别Demo版整理(不仅可以识别人脸,还可以识别眼睛鼻子嘴 ...

  5. 基于Xenomai的实时Linux分析与研究

    转自:http://blog.csdn.net/cyberlabs/article/details/6967192 引 言 随着嵌入式设备的快速发展,嵌入式设备的功能和灵活性要求越来越高,很多嵌入式设 ...

  6. 【应用笔记】【AN004】VB环境下基于RS-485的4-20mA电流采集

    版本:第一版作者:周新稳 杨帅 日期:20160226 =========================== 本资料高清PDF 下载: http://pan.baidu.com/s/1c1uuhLQ ...

  7. 基于GPUImage的实时美颜滤镜

    1.背景 前段时间由于项目需求,做了一个基于GPUImage的实时美颜滤镜.现在各种各样的直播.视频App层出不穷,美颜滤镜的需求也越来越多.为了回馈开源,现在我把它放到了GitHub https:/ ...

  8. tensorflow实现基于LSTM的文本分类方法

    tensorflow实现基于LSTM的文本分类方法 作者:u010223750 引言 学习一段时间的tensor flow之后,想找个项目试试手,然后想起了之前在看Theano教程中的一个文本分类的实 ...

  9. 在TensorFlow中基于lstm构建分词系统笔记

    在TensorFlow中基于lstm构建分词系统笔记(一) https://www.jianshu.com/p/ccb805b9f014 前言 我打算基于lstm构建一个分词系统,通过这个例子来学习下 ...

随机推荐

  1. RHCE认证考前辅导

    一一:Linux认证题库详细说明 注意事项 (1) RHCSA上午2.5小时,RHCE下午3.5小时,考生需对题目非常熟练. (2) 5样东西必带(身份证.1支黑色水笔.常用邮箱.姓名拼音.聪明的脑袋 ...

  2. vue install后出现的问题

    出现这个问题你要先把node-sass移除后重新安装 执行下面命令 npm remove node-sass --save-dev 然后安装 npm install node-sass@latest ...

  3. C#概念总结(二)

    1.C#的方法:<access Specifier>  <Return Type>< Method Name>(Parmeter list){     method ...

  4. PHP编译安装时常见错误解决办法

    转载自:http://www.bkjia.com/PHPjc/1008013.html This article is post on https://coderwall.com/p/ggmpfa c ...

  5. 安装cx_Oracle 6

    首先声明,本文是在Linux 环境下进行安装.不涉及Windows 版安装. 一. 了解cx_Oracle 安装要求 要python 通过cx_Oracle 6 操作Oracle 数据库,以下几个条件 ...

  6. String 类的实现(2)引用计数与写时拷贝

    1.引用计数 我们知道在C++中动态开辟空间时是用字符new和delete的.其中使用new test[N]方式开辟空间时实际上是开辟了(N*sizeof(test)+4)字节的空间.如图示其中保存N ...

  7. python datetime.datetime is not JSON serializable

    1.主要是python  list转换成json时对时间报错:datetime.datetime(2014, 5, 23, 9, 33, 3) is not JSON serializable. 2. ...

  8. 【C++ Primer | 15】继承的构造函数

    继承的构造函数 子类为完成基类初始化,在C++11之前,需要在初始化列表调用基类的构造函数,从而完成构造函数的传递.如果基类拥有多个构造函数,那么子类也需要实现多个与基类构造函数对应的构造函数. cl ...

  9. MySql-8.0.12 安装教程

    MySql-8.0.12 安装教程随笔https://www.cnblogs.com/CrazyDemo/p/9409995.html MySQL 安装https://m.runoob.com/mys ...

  10. 一脸懵逼学习hadoop之HDFS的java客户端编写

    1:eclipse创建一个项目,然后导入对应的jar包: 鼠标右击项目,点击properties或者alt+enter快捷键--->java build path--->libraries ...