作者 | 李秋键
责编 | Carol
封图 | 下载自视觉中国
众所周知随着人工智能智能的发展,人工智能的落地项目也在变得越来越多,尤其是计算机视觉方面。
所以今天我们也是做一个计算机视觉方面的训练,用python来判断用户溺水行为,结合姿态识别和图像识别得到结果。其中包括姿态识别和图像分类。
首先图像分类是根据各自在图像信息中所反映的不同特征,把不同类别的目标区分开来的图像处理方法。它是利用计算机对图像进行定量分析,把图像或图像中的每个像元或区域划归为若干个类别中的某一种,以代替人的视觉判读。
人体姿态是被主要分为基于计算机视角的识别和基于运动捕获技术的识别。基于计算机视觉的识别主要通过各种特征信息来对人体姿态动作进行识别, 比如视频图像序列、人体轮廓、多视角等。
这里整体程序的流程如下:
百度姿态识别图片并标注
CNN网络实现图像分类
根据分类结果可视化输出结果
最终输出的程序效果如下图:
首先我们使用的python版本是3.6.5所用到的模块如下:
OpenCV:用来调用姿态识别接口绘制姿态识别结果
Baidu-aip:用来加载人体分析模块实现人体姿态识别
configparser :配置文件模块 读写配置文件
keras:用来训练和调用神经网络模型
素材准备
首先我们准备不同的图片放到一个特定文件夹下。图片分为三个类别,一个是溺水图片文件夹,一个是正常游泳图片文件夹,另一个是疑似溺水无法判定的图片文件夹。在这里我们把它放到data文件夹下,
其中疑似图片文件夹,如下图可见:
在这里为了足够的精度和方便调用,我们使用百度提供的人体分析接口。按照官方的规定设定了配置文件。主要就是设定人体各个肢体零件连接配置。
其对应的代码如下:
def draw_line(self, img): # nose ---> neck cv2.line(img, (int(self.dic['nose']['x']), int(self.dic['nose']['y'])), (int(self.dic['neck']['x']), int(self.dic['neck']['y'])), (0, 255, 0), 2) # neck --> left_shoulder cv2.line(img, (int(self.dic['neck']['x']), int(self.dic['neck']['y'])), (int(self.dic['left_shoulder']['x']), int(self.dic['left_shoulder']['y'])), (0, 255, 0), 2) # neck --> right_shoulder cv2.line(img, (int(self.dic['neck']['x']), int(self.dic['neck']['y'])), (int(self.dic['right_shoulder']['x']), int(self.dic['right_shoulder']['y'])), (0, 255, 0), 2) # left_shoulder --> left_elbow cv2.line(img, (int(self.dic['left_shoulder']['x']), int(self.dic['left_shoulder']['y'])), (int(self.dic['left_elbow']['x']), int(self.dic['left_elbow']['y'])), (0, 255, 0), 2) # left_elbow --> left_wrist cv2.line(img, (int(self.dic['left_elbow']['x']), int(self.dic['left_elbow']['y'])), (int(self.dic['left_wrist']['x']), int(self.dic['left_wrist']['y'])), (0, 255, 0), 2) # right_shoulder --> right_elbow cv2.line(img, (int(self.dic['right_shoulder']['x']), int(self.dic['right_shoulder']['y'])), (int(self.dic['right_elbow']['x']), int(self.dic['right_elbow']['y'])), (0, 255, 0), 2) # right_elbow --> right_wrist cv2.line(img, (int(self.dic['right_elbow']['x']), int(self.dic['right_elbow']['y'])), (int(self.dic['right_wrist']['x']), int(self.dic['right_wrist']['y'])), (0, 255, 0), 2) # neck --> left_hip cv2.line(img, (int(self.dic['neck']['x']), int(self.dic['neck']['y'])), (int(self.dic['left_hip']['x']), int(self.dic['left_hip']['y'])), (0, 255, 0), 2) # neck --> right_hip cv2.line(img, (int(self.dic['neck']['x']), int(self.dic['neck']['y'])), (int(self.dic['right_hip']['x']), int(self.dic['right_hip']['y'])), (0, 255, 0), 2) # left_hip --> left_knee cv2.line(img, (int(self.dic['left_hip']['x']), int(self.dic['left_hip']['y'])), (int(self.dic['left_knee']['x']), int(self.dic['left_knee']['y'])), (0, 255, 0), 2) # right_hip --> right_knee cv2.line(img, (int(self.dic['right_hip']['x']), int(self.dic['right_hip']['y'])), (int(self.dic['right_knee']['x']), int(self.dic['right_knee']['y'])), (0, 255, 0), 2) # left_knee --> left_ankle cv2.line(img, (int(self.dic['left_knee']['x']), int(self.dic['left_knee']['y'])), (int(self.dic['left_ankle']['x']), int(self.dic['left_ankle']['y'])), (0, 255, 0), 2) # right_knee --> right_ankle cv2.line(img, (int(self.dic['right_knee']['x']), int(self.dic['right_knee']['y'])), (int(self.dic['right_ankle']['x']), int(self.dic['right_ankle']['y'])), (0, 255, 0), 2)2、姿态识别调用:
在设置好基本的配置文件后,我们通过百度申请的账号密匙等等调用接口即可。这里实现的效果如下:
对应代码如下:
class BaiDuAPI(object): # 特殊 构造函数 初始化函数 def __init__(self): app_id ="20038443" api_key = "LhtctcN7hf6VtkHHcUGwXKfw" secret_key = "wzWACH340kE0FGhvA9CqWsiRwltf5wFE" self.client = AipBodyAnalysis(app_id, api_key, secret_key) """ 读取图片 """ def get_file_content(self, photoPath): with open(photoPath, 'rb') as fp: return fp.read() """ 主函数 """ def file_main(self, photoPath): img = self.get_file_content('{}'.format(photoPath)) """ 调用人体关键点识别 """ # 此处只能对一个人进行关键点识别 # 也就是说一个图片如果有好多人的话,只能标出一个人的关节特征 # 此处可以做修改,即进行把一张图所有人的关节特征都表达出来 # ------ # print(self.client.bodyAnalysis(img)) result = self.client.bodyAnalysis(img)['person_info'][0]['body_parts'] jo = joint.Joint(result) jo.xunhun(photoPath) # print(result )CNN识别模型的建立
这里设定的CNN模型挺常见的模型相似,通过设定卷积核、步长、训练批次等等搭建网络。
代码如下:
model = Sequential() #创建一个神经网络对象 #添加一个卷积层,传入固定宽高三通道的图片,以32种不同的卷积核构建32张特征图, # 卷积核大小为3*3,构建特征图比例和原图相同,激活函数为relu函数。 model.add(Conv2D(input_shape=(IMG_W,IMG_H,3),filters=32,kernel_size=3,padding='same',activation='relu')) #再次构建一个卷积层 model.add(Conv2D(filters=32,kernel_size=3,padding='same',activation='relu')) #构建一个池化层,提取特征,池化层的池化窗口为2*2,步长为2。 model.add(MaxPool2D(pool_size=2,strides=2)) #继续构建卷积层和池化层,区别是卷积核数量为64。 model.add(Conv2D(filters=64,kernel_size=3,padding='same',activation='relu')) model.add(Conv2D(filters=64,kernel_size=3,padding='same',activation='relu')) model.add(MaxPool2D(pool_size=2,strides=2)) #继续构建卷积层和池化层,区别是卷积核数量为128。 model.add(Conv2D(filters=128,kernel_size=3,padding='same',activation='relu')) model.add(Conv2D(filters=128,kernel_size=3,padding='same',activation='relu')) model.add(MaxPool2D(pool_size=2, strides=2)) model.add(Flatten()) #数据扁平化 model.add(Dense(128,activation='relu')) #构建一个具有128个神经元的全连接层 model.add(Dense(64,activation='relu')) #构建一个具有64个神经元的全连接层 model.add(Dropout(DROPOUT_RATE)) #加入dropout,防止过拟合。 model.add(Dense(CLASS,activation='softmax')) #输出层,一共3个神经元,对应3个分类 adam = Adam(lr=LEARNING_RATE) #创建Adam优化器 model.compile(optimizer=adam,loss='categorical_crossentropy',metrics=['accuracy']) #使用交叉熵代价函数,adam优化器优化模型,并提取准确率 train_generator = train_datagen.flow_from_directory( #设置训练集迭代器 TRAIN_PATH, #训练集存放路径 target_size=(IMG_W,IMG_H), #训练集图片尺寸 batch_size=BATCH_SIZE #训练集批次 ) test_generator = test_datagen.flow_from_directory( #设置测试集迭代器 TEST_PATH, #测试集存放路径 target_size=(IMG_W,IMG_H), #测试集图片尺寸 batch_size=BATCH_SIZE, #测试集批次 ) print(train_generator.class_indices) #打印迭代器分类 try: model = load_model('{}.h5'.format(SAVE_PATH)) #尝试读取训练好的模型,再次训练 print('model upload,start training!') except: print('not find model,start training') #如果没有训练过的模型,则从头开始训练 model.fit_generator( #模型拟合 train_generator, #训练集迭代器 steps_per_epoch=len(train_generator), #每个周期需要迭代多少步 epochs=EPOCHS, #迭代周期 validation_data=test_generator, #测试集迭代器 validation_steps=len(test_generator) #测试集迭代多少步 ) model.save('{}.h5'.format(SAVE_PATH)) #保存模型 print('finish {} epochs!'.format(EPOCHS))同训练的步骤相似,这里我们首先也是是通过调用百度姿态识别进行图片人体分析,然后分类预测结果。
代码如下:
# 载入模型 model = load_model('model_selector.h5') label = np.array(['正常','疑似','溺水']) def image_change(image): image = image.resize((224, 224)) image = img_to_array(image) image = image / 255 image = np.expand_dims(image, 0) return image class BaiDuAPI(object): # 特殊 构造函数 初始化函数 def __init__(self): app_id ="20038443" api_key = "LhtctcN7hf6VtkHHcUGwXKfw" secret_key = "wzWACH340kE0FGhvA9CqWsiRwltf5wFE" self.client = AipBodyAnalysis(app_id, api_key, secret_key) """ 读取图片 """ def get_file_content(self, photoPath): with open(photoPath, 'rb') as fp: return fp.read() """ 主函数 """ def file_main(self, photoPath): img = self.get_file_content('{}'.format(photoPath)) """ 调用人体关键点识别 """ # 此处只能对一个人进行关键点识别 # 也就是说一个图片如果有好多人的话,只能标出一个人的关节特征 # 此处可以做修改,即进行把一张图所有人的关节特征都表达出来 # ------ # print(self.client.bodyAnalysis(img)) result = self.client.bodyAnalysis(img)['person_info'][0]['body_parts'] jo = joint.Joint(result) jo.xunhun(photoPath) # print(result ) #预测2.jpg的结果 try: image = load_img("2.jpg") #plt.imshow(image) image = image_change(image) baiduapi = BaiDuAPI() baiduapi.file_main('2.jpg') img=cv2.imread("temp.jpg") img_PIL = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) myfont = ImageFont.truetype(r'C:/Windows/Fonts/simfang.ttf', 40) draw = ImageDraw.Draw(img_PIL) draw.text((300, 10), label[model.predict_classes(image)][0], font=myfont, fill=(200, 100, 0)) img_OpenCV = cv2.cvtColor(np.asarray(img_PIL), cv2.COLOR_RGB2BGR) cv2.imshow('frame', img_OpenCV) cv2.waitKey(0) except: pass #预测1.jpg的结果 try: image = load_img("1.jpg") #plt.imshow(image) image = image_change(image) baiduapi = BaiDuAPI() baiduapi.file_main('1.jpg') img=cv2.imread("temp.jpg") img_PIL = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) myfont = ImageFont.truetype(r'C:/Windows/Fonts/simfang.ttf', 40) draw = ImageDraw.Draw(img_PIL) draw.text((300, 10), label[model.predict_classes(image)][0], font=myfont, fill=(200, 100, 0)) img_OpenCV = cv2.cvtColor(np.asarray(img_PIL), cv2.COLOR_RGB2BGR) cv2.imshow('frame', img_OpenCV) cv2.waitKey(0) except: pass #预测3.jpg的结果 try: image = load_img("3.jpg") #plt.imshow(image) image = image_change(image) baiduapi = BaiDuAPI() baiduapi.file_main('3.jpg') img=cv2.imread("temp.jpg") img_PIL = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) myfont = ImageFont.truetype(r'C:/Windows/Fonts/simfang.ttf', 40) draw = ImageDraw.Draw(img_PIL) draw.text((300, 10), label[model.predict_classes(image)][0], font=myfont, fill=(200, 100, 0)) img_OpenCV = cv2.cvtColor(np.asarray(img_PIL), cv2.COLOR_RGB2BGR) cv2.imshow('frame', img_OpenCV) cv2.waitKey(0) except: pass最终运行程序结果如下:
源码地址:
https://pan.baidu.com/s/1qMwPCTTyqDWPXoPj1XnKgA
提取码:us2k
作者简介:
李秋键,博客专家,达人课作者。硕士在读于中国矿业大学,开发有taptap竞赛获奖等等。
推荐阅读高文、张钹、杨强隔空论道:AI精度与隐私的博弈
90行Python代码,让张小龙的微信地球转起来
独家揭秘!抖音爆款漫画变身特效的背后技术
字节跳动 8 年,抖音、头条的技术能力开发者都可以用起来了!
从微信「拍一拍」,我想到了那些神奇的一行代码功能
4 张图读懂比特币矿商8年兴衰与变迁
你点的每个“在看”,我都认真当成了AI