caffe使用别人训练好的模型
我觉得都是一样的套路,不管是python还是c++
掌握好步骤流程就行
加载网络结构流程
_1、设置gpu或者cpu模式
2、设置gpu设备号
3、加载网络结构,caffeModel和prototxt文件
4、处理输入图片,例如减去均值和归一化操作
5、前向传播
6、处理计算之后的结果_
#python代码
#ssd mobileNet检测图片
import numpy as np
import sys,os
import cv2
caffe_root = '/home/ssd/caffe/'
sys.path.insert(0, caffe_root + 'python')
import caffe
import time
net_file= 'deploy.prototxt'
caffe_model= 'tr.caffemodel'
test_dir = "/home/qwe/Desktop/12"
if not os.path.exists(caffe_model):
print("MobileNetSSD_deploy.affemodel does not exist,")
print("use merge_bn.py to generate it.")
exit()
caffe.set_mode_gpu()
caffe.set_device(0)
net = caffe.Net(net_file,caffe_model,caffe.TEST)
CLASSES = ('background', 'obj')
def preprocess(src):
img = cv2.resize(src, (512,256))
img = img - 127.5
img = img * 0.007843
return img
def postprocess(img, out):
h = img.shape[0]
w = img.shape[1]
box = out['detection_out'][0,0,:,3:7] * np.array([w, h, w, h])
cls = out['detection_out'][0,0,:,1]
conf = out['detection_out'][0,0,:,2]
return (box.astype(np.int32), conf, cls)
def detect(imgfile):
origimg = cv2.imread(imgfile)
img = preprocess(origimg)
img = img.astype(np.float32)
img = img.transpose((2, 0, 1))
start_time = time.time()
net.blobs['data'].data[...] = img
out = net.forward()
box, conf, cls = postprocess(origimg, out)
pro_time = time.time() - start_time
print('use time: ' + str(pro_time) + 's')
for i in range(len(box)):
p1 = (box[i][0], box[i][1])
p2 = (box[i][2], box[i][3])
cv2.rectangle(origimg, p1, p2, (0,255,0))
p3 = (max(p1[0], 15), max(p1[1], 15))
title = "%s:%.2f" % (CLASSES[int(cls[i])], conf[i])
cv2.putText(origimg, title, p3, cv2.FONT_ITALIC, 0.6, (0, 255, 0), 1)
cv2.imshow("SSD", origimg)
k = cv2.waitKey(0) & 0xff
#Exit if ESC pressed
if k == 27 : return False
return True
for f in os.listdir(test_dir):
if detect(test_dir + "/" + f) == False:
break
|——————————————————————————
|—–从上面的python代码中可以看出完整的加载模型流程
|—–而使用c++会有几点需要注意的地方
|——————————————————————————
//-------ssd.h
class Detector
{
public:
Detector(const string& model_file,const string& weights_file);
std::vector<std::vector<float> > Detect(const cv::Mat& _img);
private:
boost::shared_ptr<Net<float> > net_;
};
//------ssd.cpp
Detector::Detector(const string &model_file, const string &weights_file)
{
#ifdef CPU_ONLY
Caffe::set_mode(Caffe::CPU);
#else
Caffe::set_mode(Caffe::GPU);
#endif
/* Load the network. */
net_.reset(new Net<float>(model_file, TEST));
net_->CopyTrainedLayersFrom(weights_file);
}
std::vector<std::vector<float> >Detector::Detect(const cv::Mat &_img)
{
cv::Mat img = _img.clone();
Blob<float>* inputBlob = net_->input_blobs()[0];
int width = inputBlob->width(); //网络规定的输入图片的宽度和高度
int height = inputBlob->height();
cv::resize(img,img,cv::Size(width,height));//将测试图片进行调整大小
img.convertTo(img, CV_32FC3); //转为浮点图
img = (img - 127.5) * 0.007843;
float* data = inputBlob->mutable_cpu_data(); //将图片的像素值,复制进网络的输入Blob
for (int k = 0; k<3; ++k){
for (int i = 0; i<height; ++i){
for (int j = 0; j<width; ++j){
int index = (k*height + i)*width + j; //获取偏移量
data[index] = img.at<Vec3f>(i, j)[k];
}
}
}
vector<Blob<float>* > inputs(1, inputBlob);
//const vector<Blob<float>* >& outputBlobs = net_->Forward(inputs); //进行前向传播,并返回最后一层的blob
const vector<Blob<float>* >& outputBlobs = net_->Forward(); //进行前向传播,并返回最后一层的blob
Blob<float>* outputBlob = outputBlobs[0]; //输出blob
const float* result = outputBlob->cpu_data();
vector<vector<float> > detections;
for (int i = 0; i<outputBlob->count(); ++i) //将输出blob里的特征数值,拷贝到vector里并返回
{
if (result[0] == -1) {
// Skip invalid detection.
result += 7;
continue;
}
vector<float> detection(result, result + 7);
detections.push_back(detection);
result += 7;
}
return detections;
}
几个不同的地方
_1,将待测试图片加载进网络中
2,运算完成之后取出数据_
python中写法比较简单,按照套路直接写
加载待测图片
#python 代码
#----------------------------
#加载待测图片
origimg = cv2.imread(imgfile)
#将图片减去均值,归一化处理
img = cv2.resize(src, (512,256))
img = img - 127.5
img = img * 0.007843
#将图片转换成float类型
img = img.astype(np.float32)
img = img.transpose((2, 0, 1))
#将图片内容送进网络中进行前向传播
net.blobs['data'].data[...] = img
#前向传播
out = net.forward()
/*c++代码
-------------------------------------*/
//opencv 读取图片文件
cv::Mat img = cv::imread(fileName);
Blob<float>* inputBlob = net_->input_blobs()[0];
//网络规定的输入图片的宽度和高度
int width = inputBlob->width();
int height = inputBlob->height();
cv::resize(img,img,cv::Size(width,height));//将测试图片进行调整大小
img.convertTo(img, CV_32FC3); //转为浮点图
img = (img - 127.5) * 0.007843; //减去均值,归一化图像
/*减均值也可以使用cv::subtract函数,例如:
cv::Mat mean(height,width,image.type(),cv::Scalar(102.9801,115,122.77);
cv::Mat normalized;
cv::subtract(image,mean,normalized);
*/
//------
//将图片加载进网络结构前向传播
float* data = inputBlob->mutable_cpu_data(); //将图片的像素值,复制进网络的输入Blob
for (int k = 0; k<3; ++k)
{
for (int i = 0; i<height; ++i){
for (int j = 0; j<width; ++j){
int index = (k*height + i)*width + j; //获取偏移量
data[index] = img.at<Vec3f>(i, j)[k];
}
}
}
/*也可以写成下面的形式
std::vector<cv::Mat> input_channels;
float* input_data = inputBlob->mutable_cpu_data();
for (int i = 0; i < inputBlob->channels(); ++i)
{
cv::Mat channel(height, width, CV_32FC1, input_data);
input_channels->push_back(channel);
input_data += width * height;
}
cv::split(img, input_channels);
*/
//前向传播,直接取最后一层输出结果
const vector<Blob<float>* >& outputBlobs = net_->Forward();
//这样的写法要注意网络结构最后是否有多个分支,如果是多个分支,则会导致最后的结果将多个分支的结果融合在一起,不好区分。
从前向传播之后取最后的检测结果
#python代码
#------------------------
#out = net.forward()
h = img.shape[0] #待测图片的高
w = img.shape[1] #待测图片的宽
#取出out中的detection_out的blob中的数据,按照blob名字取数据。
#detection_out中的是包含7个float数据,从第4个到第7个分别代表位置坐标
#由于要还原到原来的图片中的实际位置,所以分别乘以原图中的宽高
box = out['detection_out'][0,0:3,7] * np.array([w,h,w,h)
cls = out['detection_out'][0,0,:,1] #第二个位置是分类结果
conf = out['detection_out'][0,0,:,2]#第三个位置是分类置信度
/*C++代码
----------------------------*/
const vector<Blob<float>* >& outputBlobs = net_->Forward();
Blob<float>* outputBlob = outputBlobs[0]; //输出blob
const float* result = outputBlob->cpu_data();
vector<vector<float> > detections;
//注意这里 outputBlob->count() 和 outputBlob->height()的数值也许是不一样的
for (int i = 0; i<outputBlob->count(); ++i)
{
if (result[0] == -1) {
// Skip invalid detection.
result += 7;
continue;
}
vector<float> detection(result, result + 7);
detections.push_back(detection);
result += 7;
}