作者 | 李秋键
责编 | Carol
封图 | CSDN 下载自视觉中国
众所周知随着人工智能智能的发展,人工智能的落地项目也在变得越来越多,尤其是计算机视觉方面。
首先图像分类是根据各自在图像信息中所反映的不同特征,把不同类别的目标区分开来的图像处理方法。它是利用计算机对图像进行定量分析,把图像或图像中的每个像元或区域划归为若干个类别中的某一种,以代替人的视觉判读。
这里整体程序的流程如下:
最终输出的程序效果如下图:
一、实验前的准备
首先我们使用的python版本是3.6.5所用到的模块如下:
configparser :配置文件模块 读写配置文件
keras:用来训练和调用神经网络模型
素材准备
首先我们准备不同的图片放到一个特定文件夹下。图片分为三个类别,一个是溺水图片文件夹,一个是正常游泳图片文件夹,另一个是疑似溺水无法判定的图片文件夹。在这里我们把它放到data文件夹下,
其中疑似图片文件夹,如下图可见:
人体姿态识别搭建
1、姿态配置文件设定:
在这里为了足够的精度和方便调用,我们使用百度提供的人体分析接口。按照官方的规定设定了配置文件。主要就是设定人体各个肢体零件连接配置。
其对应的代码如下:
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)
在设置好基本的配置文件后,我们通过百度申请的账号密匙等等调用接口即可。这里实现的效果如下:
对应代码如下:
classBaiDuAPI(object):
# 特殊 构造函数 初始化函数
def__init__(self):
app_id = "20038443"
api_key = "LhtctcN7hf6VtkHHcUGwXKfw"
secret_key = "wzWACH340kE0FGhvA9CqWsiRwltf5wFE"
self.client = AipBodyAnalysis(app_id, api_key, secret_key)
""" 读取图片 """
defget_file_content(self, photoPath):
withopen(photoPath, 'rb') asfp:
returnfp.read
""" 主函数 """
deffile_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 )
1、神经网络的搭建:
这里设定的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))
2、模型的调用:
代码如下:
# 载入模型
model = load_model( 'model_selector.h5')
label = np.array([ '正常', '疑似', '溺水'])
defimage_change(image):
image = image.resize(( 224, 224))
image = img_to_array(image)
image = image / 255
image = np.expand_dims(image, 0)
returnimage
classBaiDuAPI(object):
# 特殊 构造函数 初始化函数
def__init__(self):
app_id = "20038443"
api_key = "LhtctcN7hf6VtkHHcUGwXKfw"
secret_key = "wzWACH340kE0FGhvA9CqWsiRwltf5wFE"
self.client = AipBodyAnalysis(app_id, api_key, secret_key)
""" 读取图片 """
defget_file_content(self, photoPath):
withopen(photoPath, 'rb') asfp:
returnfp.read
""" 主函数 """
deffile_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
作者简介:
李秋键,CSDN博客专家,CSDN达人课作者。硕士在读于中国矿业大学,开发有taptap竞赛获奖等等。