---作者吴疆,未经允许,严禁转载,违权必究---
---欢迎指正,需要源码和文件可站内私信联系---
-----------点击此处链接至博客园原文-----------
功能说明:利用Python web框架Django,将faster-rcnn的demo程序以网页形式展现出来,简而言之是基于B-S架构的编程,直观地以网页形式展示目标检测的功能。
运行环境:Window7 cpu Python2.7 Pycharm5.0 Django1.8x
一、功能预览
首先,启动服务器,将返回一个网址: http://127.0.0.1:8000/ 即本机地址 (模拟网页,本机同时是服务器和模拟前端用户)
然后,我们可以登录上面给出的地址
接着,我们输入相关内容,点击ok
等待网页返回处理后的结果(楼下俺的女朋友)
可以看到此时后台在执行faster rcnn相关代码
如果想复现上述功能,请按本人写作顺序依次进行相关操作。
二、Django环境的搭建
参考链接:Django自学之路
以本人Windows7系统为例看上述参考链接中Django环境搭建2.1.2部分,建议选Django1.8版本,便于后续学习。建议自主学习本网址Django视图与网址部分,半小时就能理解。大致能对新建Django工程、工程目录下应有什么文件、以及主要的一些文件如views.py、urls.py的作用有个清晰的理解,这些内容还是静静地学习这个网址的讲解,后文我也会提及一部分。以下是本人安装Django的简要笔记,大略可以参考一下。
三、本文Django工程中的文件上传机制
参考这篇博客,其基于deepin linux 2013、Python 2.7、Django 1.6.2环境实现的,由于本人环境为Window7 Django1.8,因此需要做部分修改,结合上述参考blog做如下操作:
(1)创建项目与应用
这部分内容在”一”中所给参考链接中讲解的非常清楚,本人Django工程地址:E:\deep learning\py-faster-rcnn-master\tools\,首先cmd模式下cd到你想放置的路径,然后输入django-admin.py startproject mysite2 即可创建一个名为mysite2的Django工程,接着cd到mysite2的路径 cd mysite2,在项目下创建一个disk应用 python manage.py startapp disk,这时,可以在相应位置看到新建的Django工程,以及可以看到类似于下面的Django工程目录结构。
打开mysite2/mysite2/settings.py,将disk应用添加进去,如下所示:
# Application definition INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'disk', )
(2)设计model(数据库)
打开mysite2/disk/models.py,添加如下内容即可创建两个字段,username用于存放用户名、headImg用于存放上传图片路径。
from django.db import models # Create your models here. class User(models.Model): username = models.CharField(max_length = 30) headImg = models.FileField(upload_to = './upload/') def __unicode__(self): return self.username
后面执行上传图片操作时,会将图片传至upload文件夹内。
(3)数据库同步
cmd模式下cd 到Django工程mysite2(第一级的mysite2)下,依次敲入以下命令(由于本人版本不同所以命令与上述参考博客中略有不同),按提示依次输入python manage.py syncdb,python manage.py makemigration,python manage.py migrate,正常情况下,cmd窗口应该会显示以下内容:(忽略我这里设置的路径,我刚开始默认存在c盘的,为了方便工作我后来直接拷贝整个Django工程到e盘相关路径下,也是能正常工作的)
同时将在mysite2中看到一些和数据库有关的文件
(4)创建视图函数mysite2\disk\views.py
在这里我直接把demo.py稍加修改也一并放在这里了,详情可看注释,重点关注register()函数
# -*- coding:utf-8 -*- #Author: Wu Jiang import _init_paths #导入路径,调用faster_rcnn中相关模块 from django.shortcuts import render,render_to_response from django import forms #Django表单方式上传图片 from django.http import HttpResponse from disk.models import User from fast_rcnn.config import cfg from fast_rcnn.test import im_detect from fast_rcnn.nms_wrapper import nms #from utils.timer import Timer by wj 11.3 import matplotlib.pyplot as plt #matlab中画图工具 import numpy as np import scipy.io as sio import caffe, os, sys, cv2 import argparse import sys #from skimage import io,data #11.19 by wj #import shutil #11.27 by wj file from os import listdir #11.28 by wj 上述导入模块有三个来源:一是views.py源文件、二是从demo中拷贝过来、三是为了后面读写文件操作 # Create your views here. class UserForm(forms.Form): username = forms.CharField() headImg = forms.FileField() #直接从demo中拷贝来的 CLASSES = ('__background__', 'aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor') NETS = {'vgg16': ('VGG16', 'VGG16_faster_rcnn_final.caffemodel'), 'zf': ('ZF', 'ZF_faster_rcnn_final.caffemodel')} def vis_detections(im, class_name, dets, thresh=0.5): """Draw detected bounding boxes.""" inds = np.where(dets[:, -1] >= thresh)[0] if len(inds) == 0: return im = im[:, :, (2, 1, 0)] fig, ax = plt.subplots(figsize=(12, 12)) ax.imshow(im, aspect='equal') for i in inds: bbox = dets[i, :4] score = dets[i, -1] ax.add_patch( plt.Rectangle((bbox[0], bbox[1]), bbox[2] - bbox[0], bbox[3] - bbox[1], fill=False, edgecolor='red', linewidth=3.5) ) ax.text(bbox[0], bbox[1] - 2, '{:s} {:.3f}'.format(class_name, score), bbox=dict(facecolor='blue', alpha=0.5), fontsize=14, color='white') ax.set_title(('{} detections with ' 'p({} | box) >= {:.1f}').format(class_name, class_name, thresh), fontsize=14) plt.axis('off') plt.tight_layout() plt.draw() plt.savefig('test.png') #图片处理后保存下来 def demo(net, image_name): """Detect object classes in an image using pre-computed object proposals.""" # Load the demo image #im_file = os.path.join(cfg.DATA_DIR, 'demo', image_name) im_file ='E:\\deep learning\\py-faster-rcnn-master\\tools\\mysite2\\upload\\000001.jpg' #读取该路径下的000001.jpg图片,每次上传图片之前都清空upload文件夹,保存新的图片命名成000001.jpg im = cv2.imread(im_file) # Detect all object classes and regress object bounds #timer = Timer() by wj 11.3 #timer.tic() by wj 11.3 scores, boxes = im_detect(net, im) #timer.toc() by wj 11.3 #print ('Detection took {:.3f}s for ' by wj 11.3 #'{:d} object proposals').format(timer.total_time, boxes.shape[0]) by wj 11.3 # Visualize detections for each class CONF_THRESH = 0.8 NMS_THRESH = 0.3 for cls_ind, cls in enumerate(CLASSES[1:]): cls_ind += 1 # because we skipped background cls_boxes = boxes[:, 4*cls_ind:4*(cls_ind + 1)] cls_scores = scores[:, cls_ind] dets = np.hstack((cls_boxes, cls_scores[:, np.newaxis])).astype(np.float32) keep = nms(dets, NMS_THRESH) dets = dets[keep, :] vis_detections(im, cls, dets, thresh=CONF_THRESH) def parse_args_test(): """Parse input arguments.""" parser = argparse.ArgumentParser(description='Faster R-CNN demo') parser.add_argument('--gpu', dest='gpu_id', help='GPU device id to use [0]', default=0, type=int) parser.add_argument('--cpu', dest='cpu_mode', help='Use CPU mode (overrides --gpu)', action='store_true') parser.add_argument('--net', dest='demo_net', help='Network to use [vgg16]', choices=NETS.keys(), default='zf') args = parser.parse_args() return args def register(request): if request.method == "POST": uf = UserForm(request.POST,request.FILES) #print sys.path if uf.is_valid(): #获取表单信息 username = uf.cleaned_data['username'] headImg = uf.cleaned_data['headImg'] #stand for dir or photo ?? request.FILES['file'] acquire photo ? #写入数据库 user = User() user.username = username user.headImg = headImg user.save() a=listdir('E:\\deep learning\\py-faster-rcnn-master\\tools\\mysite2\\upload') #11.28 by wj old_file_path=os.path.join('E:\\deep learning\\py-faster-rcnn-master\\tools\\mysite2\\upload',a[0]) #11.28 by wj new_file_path='E:\\deep learning\\py-faster-rcnn-master\\tools\\mysite2\\upload\\000001.jpg' #11.28 by wj os.rename(old_file_path, new_file_path) #11.28 by wj 将保存下来的图片改名成000001.jpg #shutil.copyfile('E:\deep learning\py-faster-rcnn-master\tools\mysite2\upload\000456.jpg','E:\deep learning\py-faster-rcnn-master\tools\mysite2\photo\000456.jpg') #shutil.copy(r'E:\deep learning\py-faster-rcnn-master\tools\mysite2\upload\000456.jpg','E:\deep learning\py-faster-rcnn-master\tools\mysite2\photo\000456.jpg') #io.imsave('E://deep learning//py-faster-rcnn-master//tools//mysite2//photo//000456.jpg',headImg) #11.19 wj #E://deep learning//py-faster-rcnn-master//tools//mysite2//photo//000456.jpg #return HttpResponse('upload ok!') #can change it to show photos by wj look related showing measures #if __name__ == '__main__': cfg.TEST.HAS_RPN = True # Use RPN for proposals #args = parse_args_test() #args=Namespace(cpu_mode=False, demo_net='zf', gpu_id=0) #prototxt = os.path.join(cfg.MODELS_DIR, NETS[args.demo_net][0], # 'faster_rcnn_alt_opt', 'faster_rcnn_test.pt') prototxt ='E:\\deep learning\\py-faster-rcnn-master\\models\\pascal_voc\\ZF\\faster_rcnn_alt_opt\\faster_rcnn_test.pt' #caffemodel = os.path.join(cfg.DATA_DIR, 'faster_rcnn_models', #NETS[args.demo_net][1]) caffemodel ='E:\\deep learning\\py-faster-rcnn-master\\data\\faster_rcnn_models\\ZF_faster_rcnn_final.caffemodel' #if not os.path.isfile(caffemodel): #raise IOError(('{:s} not found.\nDid you run ./data/script/' #'fetch_faster_rcnn_models.sh?').format(caffemodel)) by wj 17.11.8 #if args.cpu_mode: caffe.set_mode_cpu() #else: #caffe.set_mode_gpu() #caffe.set_device(args.gpu_id) #cfg.GPU_ID = args.gpu_id net = caffe.Net(prototxt, caffemodel, caffe.TEST) #print '\n\nLoaded network {:s}'.format(caffemodel) by wj 17.11.8 # Warmup on a dummy image im = 128 * np.ones((300, 500, 3), dtype=np.uint8) for i in xrange(2): _, _= im_detect(net, im) #im_names = ['000456.jpg', '000542.jpg', '001150.jpg', by wj 11.3 # '001763.jpg', '004545.jpg'] boy wj 11.3 im_names = ['000001.jpg'] #固定处理名为000001.jpg的图片 for im_name in im_names: #print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' by wj 17.11.8 #print 'Demo for data/demo/{}'.format(im_name) by wj 17.11.8 #print args how to change this demo(net, im_name) #plt.savefig('test.png') #plt.show() os.remove(new_file_path) #11.28 by wj 在上传新的图片前清空upload文件夹,是每次demo处理时upload里只有一张名为000001.jpg图片 #os.remove('E:\\deep learning\\py-faster-rcnn-master\\tools\\mysite2\\test.jpg') #return HttpResponse('upload ok!') #11.29 by wj imagepath ='E:\\deep learning\\py-faster-rcnn-master\\tools\\mysite2\\test.png' image_data = open(imagepath,"rb").read() return HttpResponse(image_data,content_type="image/png") else: uf = UserForm() return render_to_response('register.html',{'uf':uf})
(5)创建模板文件
在mysite2/disk/目录下创建templates文件夹,接着在mysite2/disk/templates/目录下创建register.html 文件
添加内容如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title></title> </head> <body> <h1>faster_rcnn</h1> <form method="post" enctype="multipart/form-data" > {{uf.as_p}} <input type="submit" value="ok"/> </form> </body> </html>
不用按参考blog中提到的设置模板路径,Django1.8版能够自动找到
(6)设置URL
打开mysite2\mysite2\urls.py
from django.conf.urls import include, url from django.contrib import admin from disk import views as disk_views urlpatterns = [ url(r'^admin/', include(admin.site.urls)), #url(r'^disk/$', disk_views.register), url(r'^$', disk_views.register), ]
(7)启动服务
cmd模式下cd到Django工程mysite2(第一级mysite2)的路径,输入命令Python manage.py runserver 启动服务器,有可能会抛出相应错误,具体解决办法见参考blog,正常成功情况下应显示如下界面,并能上传图片到自己新建的upload文件夹。(upload文件夹需要新建,路径参考下面截图)
Django最主要的几个文件是urls.py、views.py、html、models.py文件,在这里我简要介绍一下上述代码的执行过程
首先,我们来看urls.py文件
重点看我标注的这一句,urls文件表明当用户访问http://127.0.0.1:8000/ 时将调用views.py中定义的register函数
接着,我们看一下html文件内容
学过html相关概念的人应该能读懂这段,但这里有句{{uf.as_p}}让人很难理解意思,uf是建立的user数据库,用户输入后将在这里填充相关数据。当显示登录界面时,请在浏览器工具栏—工具----查看源代码可以看到网页信息如下,比较上下区别,就可以弄懂啦!
接下来关注views.py视图函数,这里定义了一些Django工程中的核心函数。(下图只包含了部分内容)
这里我主要想讲解一下这段代码的执行顺序,当我们输入网址登录网页时,这时request.method还不是post方式,所以执行的是else下的代码,返回了一个html文件,并且在原始文件中{{uf.as_p}}填充了uf的一些输入要求,比如type,这可以在上面的源文件中看到。render_to_response() 的第一个参数必须是要使用的模板名称。 如果要给定第二个参数,那么该参数必须是为该模板创建 Context 时所使用的字典。之后,当我们输入了username、选择图片后点击OK,这时将变成post方式,执行if语句,返回httpresponse对象,显示upload ok,这时文件夹upload里就会保存刚才上传的图片。至此以form表单方式上传文件机制介绍完了,实际上还有更简单的文件上传机制,比如文件流的方式,只是当时我没调通,所以没有细究。除此以外,将选择的图片经过demo处理后需要再在网页上显示处理结果,这里我投机取巧找到一个文件流的显示方式,具体见代码,返回了一个httpresponse对象。才疏学浅,完成的较为粗糙,点击这里可下载完整代码,提取码1qh1,py-faster-rcnn工程请参考本人这篇blog。
四、本文faster rcnn demo程序的适应性修改与关键地方讲解
现在服务器、后台能够接受到用户传来的图片,所以我们很自然的想到下一步任务就是把demo的关键处理代码拷贝到Django工程下的views.py文件(前面已经给出完整的views.py)。因此需要修改一些地方,faster_rcnn的模块调用要理顺。首先需要将E:\deep learning\py-faster-rcnn-master\tools中的_init_paths.py文件修改成如下图,并拷贝到如下路径,主要是为了使添加上述代码后的views.py执行时能找到faster_rcnn的相关文件,为方便处理,我直接给出了相应模块、py文件的完整路径。其中os.join函数是个拼接路径函数,路径的正确格式也是我打断点调试才知道的。
# -------------------------------------------------------- # Fast R-CNN # Copyright (c) 2015 Microsoft # Licensed under The MIT License [see LICENSE for details] # Written by Ross Girshick # -------------------------------------------------------- """Set up paths for Fast R-CNN.""" import os.path as osp import sys import os def add_path(path): if path not in sys.path: sys.path.insert(0, path) #this_dir = osp.dirname(__file__) #this_dir = os.getcwd() # Add caffe to PYTHONPATH #caffe_path = osp.join(this_dir, '..', 'caffe-fast-rcnn', 'python') # E:\deep learning\py-faster-rcnn-master\caffe-fast-rcnn\python caffe_path = 'E:\\deep learning\\py-faster-rcnn-master\\caffe-fast-rcnn\\python' #caffe_path = osp.join(this_dir, '..','..','..', 'caffe-fast-rcnn', 'python') #caffe_path = osp.join(this_dir, '/../../..', 'caffe-fast-rcnn', 'python') add_path(caffe_path) # Add lib to PYTHONPATH #lib_path = osp.join(this_dir, '..', 'lib') #E:\deep learning\py-faster-rcnn-master\lib lib_path ='E:\\deep learning\\py-faster-rcnn-master\\lib' #lib_path = osp.join(this_dir, '..','..','..', 'lib') #lib_path = osp.join(this_dir, '/../../..', 'lib') add_path(lib_path)
关于views.py,我想在这里补充一下我投机取巧的地方,一是一些关键地方,比如模型文件、图片等的路径我直接给出了完整路径,并且代码的确很粗糙。另外,利用form表单上传图片我在后台不知道如何取相应的图片,所以我采用的方法是:由于我知道图片会保存在upload文件夹里,每次将不同名字的图片保存后,我首先将图片改名成000001.jpg,这样就能被demo处理,处理完后生成test.png后清空upload文件夹里的图片,保存处理后的test.png显示在网页上。
另:Django工程是可以在pycharm中打断点调试的!!!具体debug调试可参考blog,在views.py打断点,用户在前端选择图片点ok后可以在pycharm中看到变量值。建议读者再进一步优化代码,同时有些绝对路径根据读者存放位置进行修改。