作者 | 李秋鍵
責編 | Carol
封圖 | CSDN 下載自視覺中國
眾所周知隨著人工智慧智能的發展,人工智慧的落地項目也在變得越來越多,尤其是計算機視覺方面。
首先圖像分類是根據各自在圖像信息中所反映的不同特徵,把不同類別的目標區分開來的圖像處理方法。它是利用計算機對圖像進行定量分析,把圖像或圖像中的每個像元或區域劃歸為若干個類別中的某一種,以代替人的視覺判讀。
這裡整體程序的流程如下:
- CNN網絡實現圖像分類
- 根據分類結果可視化輸出結果
最終輸出的程序效果如下圖:
一、實驗前的準備
首先我們使用的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競賽獲獎等等。
文章來源: https://twgreatdaily.com/zh-mo/fGRNBXMBiuFnsJQVQCC9.html