前言#
Github コードアドレス: https://github.com/HansRen1024/Object-Classification-of-Mapping-Features
後でいくつかの変更を行いましたが、 最新コードは Github を見てください ここでコードを更新することはありません。
Save_Feature_cam.py はカメラで撮影し、スペースキーを押して特徴を保存します。
Contrast_Feature_cam.py はカメラで撮影し、スペースキーを押して特徴を比較し、結果を出力します。
Save_image.py は大量の画像を保存して特徴ライブラリのリソースとして使用します。各カテゴリに対して 3 枚の画像を保存します。
Save_Feature_image.py は上記で収集した画像から特徴を保存します。
Test_All.py は test.txt
ファイル内の画像パスとカテゴリインデックスを使用してテストします。test.txt の形式は、トレーニング caffe モデルで生成された LMDB ファイルの txt ファイル内容形式と一致します。[画像パス + スペース + カテゴリインデックス]
この方法は実際には顔検出に非常に似ていますが、一般的な物体検出に使用されています。利点は、検出したい物体のデータセットが特に少ない場合やデータセットを収集するのが不便な場合に、効果が非常に顕著であることです。また、オンライン学習にも使用できます。具体的な原理は難しくなく、畳み込みニューラルネットワークを通じて特徴を抽出し、特定の層の特徴を保存します。再度写真を撮影し、すべてのライブラリ内の特徴とユークリッド距離を求めます。ただし、どの畳み込みネットワークを選択するか、どの層の特徴を選択するかは状況によります。その後、C++ で caffe と ncnn を呼び出してこの機能を実現するコードを完成させました。ここでは公開しませんが、興味がある方は自分で研究してみても難しくありません。
以下のコードは caffe モジュールを呼び出す内容について理解できない場合は、以前に書いたブログ記事を参照してください。平均を.npy ファイルに変換するコードも含まれています。
一、特徴保存コード:#
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Mon Aug 28 13:09:05 2017
@author: hans
http://blog.csdn.net/renhanchi
"""
import caffe
import cv2
import os
import skimage
import numpy as np
import matplotlib.pyplot as plt
prototxt='doc/deploy_squeezenet.prototxt'
caffe_model='doc/squeezenet.caffemodel'
mean_file='doc/mean_squeezenet.npy'
caffe.set_mode_gpu()
net = caffe.Net(prototxt,caffe_model,caffe.TEST)
for name,feature in net.blobs.items(): #各層の特徴スケールを確認
print name + '\t' + str(feature.data.shape)
def show(data, padsize=1, padval=0):
data -= data.min()
data /= data.max()
n = int(np.ceil(np.sqrt(data.shape[0])))
padding = ((0, n ** 2 - data.shape[0]), (0, padsize), (0, padsize)) + ((0, 0),) * (data.ndim - 3)
data = np.pad(data, padding, mode='constant', constant_values=(padval, padval))
data = data.reshape((n, n) + data.shape[1:]).transpose((0, 2, 1, 3) + tuple(range(4, data.ndim + 1)))
data = data.reshape((n * data.shape[1], n * data.shape[3]) + data.shape[4:])
plt.imshow(data)
plt.axis('off')
def saveFeat(image):
global prob
im = caffe.io.resize_image(image,(227,227,3))
transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape}) #data blob 構造(n, k, h, w)
transformer.set_transpose('data', (2, 0, 1)) #画像の次元順序を変更(h, w, k)->(k, h, w)
transformer.set_mean('data', np.load(mean_file).mean(1).mean(1))
transformer.set_raw_scale('data', 255)
net.blobs['data'].data[...] = transformer.preprocess('data', im)
net.forward()
# labels_filename='card/words_card.txt'
# labels = np.loadtxt(labels_filename, str, delimiter='\t')
# prob = net.blobs['prob'].data[0].flatten()
# order = prob.argsort()[-1]
# print 'class:', labels[order], 'accuracy: ', prob[order]
conv1_data = net.blobs['conv10'].data[0] #特徴を抽出
conv1_data.tofile(claPath+'feat.bin')
show(conv1_data)
c = cv2.VideoCapture(0)
while 1:
ret, image = c.read()
cv2.rectangle(image,(117,37),(522,442),(0,255,0),2)
cv2.imshow("aaa", image)
key = cv2.waitKey(10)
if key == ord(' '):
cla = str(raw_input("クラス名を入力してください: "))
claPath = os.path.join(r'features/%s/' %cla)
if not os.path.exists(claPath):
os.makedirs(claPath)
else:
print "このクラスは以前に保存されています"
os._exit(1)
img = image[40:440, 120:520]
img = skimage.img_as_float(image[40:440, 120:520]).astype(np.float32)
saveFeat(img)
elif key == 27:
cv2.destroyAllWindows()
break
二、特徴比較コード:#
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Mon Aug 28 15:39:58 2017
@author: hans
http://blog.csdn.net/renhanchi
"""
import caffe
import cv2
import os
import skimage
import numpy as np
from math import sqrt
dirpath = 'features/'
prototxt='doc/deploy_squeezenet.prototxt'
caffe_model='doc/squeezenet.caffemodel'
mean_file='doc/mean_squeezenet.npy'
caffe.set_mode_gpu()
net = caffe.Net(prototxt,caffe_model,caffe.TEST)
def contrastFeat(image):
global similarity
similarity = []
cla = []
im = caffe.io.resize_image(image,(227,227,3))
transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape}) #data blob 構造(n, k, h, w)
transformer.set_transpose('data', (2, 0, 1)) #画像の次元順序を変更(h, w, k)->(k, h, w)
transformer.set_mean('data', np.load(mean_file).mean(1).mean(1))
transformer.set_raw_scale('data', 255)
net.blobs['data'].data[...] = transformer.preprocess('data', im)
net.forward()
conv1_data = net.blobs['conv10'].data[0] #特徴を抽出
for dirname in os.listdir(dirpath):
if os.path.isdir(r'%s%s/' %(dirpath, dirname)):
claPath = os.path.join(r'%s%s/' %(dirpath, dirname))
feat = np.fromfile(claPath+'feat.bin', dtype = np.float32)
feat = feat.reshape(conv1_data.shape[0],conv1_data.shape[1],conv1_data.shape[2])
dis = 0
for n in range(feat.shape[0]):
for h in range(feat.shape[1]):
for w in range(feat.shape[2]):
dis += pow(conv1_data[n,h,w]-feat[n,h,w],2)
L2 = sqrt(dis)
similarity.append(1/(1+L2))
cla.append(dirname)
similarity = np.array(similarity)
print similarity
order = similarity.argsort()[-1]
print 'クラス:', cla[order], '確率:', similarity[order]
c = cv2.VideoCapture(0)
while 1:
ret, image = c.read()
cv2.rectangle(image,(117,37),(522,442),(0,255,0),2)
cv2.imshow("aaa", image)
key = cv2.waitKey(10)
if key == ord(' '):
img = image[40:440, 120:520]
img = skimage.img_as_float(image[40:440, 120:520]).astype(np.float32)
contrastFeat(img)
elif key == 27:
cv2.destroyAllWindows()
break