Object Detection(1):RCNN实践

前段时间做的都是classification的工作。这周有时间,正好研究一下很感兴趣的object detection。目前得出的结果都是基于RBG大神在13年所提出的开创性工作——R-CNN。这一结构可以看作是将CNN应用到Object Detection领域的开山之作。在ImageNet/VOC/MSCOCO上所有顶尖的方法都是基于这个结构或其变种,可见其影响之大。

今天我们就来学习一下这篇论文(arxiv.org/abs/1311.2524)

首先放几张我实验的结果图:




怎么样?是不是觉得非常有趣?如果你也想识别你自己的图片的话,就继续往下看吧!最后会提供识别的代码供大家参考!

一.论文解读

首先我们先分析一下这篇R-CNN论文.文章指出近几年的Object Detection的performance遇到了一个瓶颈,在这篇文章提出了两个很重要的观点:

1.将CNN结构应用到提取出来的区域;

2.针对标记数据很少的问题,利用辅助训练集如ImageNet的预训练再进行fine-tuning


论文发表的2014年,DPM已经进入瓶颈期,即使使用复杂的特征和结构得到的提升也十分有限。本文将深度学习引入检测领域,一举将PASCAL VOC上的检测率从35.1%提升到53.7%。CNN的结构在2012的ImageNet大赛中取得了非常好的结果,于是,CNN的分类结果能多大程度的应用到object detection领域就成了大家关注的焦点问题。这篇文章就这个问题提出了一个解决方案:

1.首先基于原始图像生成种类独立的区域,这些区域构成了我们detector的候选检测集

2.对第一步提取的所有区域应用CNN结构,得到一个固定长度的特征向量

3.使用特定的SVM分类器对第二步的特征向量进行分类


文中的这张图非常形象的解释了这一过程。

当然文中还有许多其他技术的使用,如对类别判定的分类器训练以及位置精修,对这些技术这里暂时不做分析,RGB大神的代码是开源的,对这些部分感兴趣的可以对应寻找:

GitHub - rbgirshick/rcnn: R-CNN: Regions with Convolutional Neural Network Features

二.识别过程

这部分我们分析上图的细节实现部分:

1.首先是提取候选区域(大约2k个):论文中采用的是Selective Search方法,可以生成很多用于目标检测的候选区域.github.com/sergeyk/sele代码在这里,主要是matlab代码,不过里面有python的接口。我们clone到本地,然后在matlab中打开整个项目,然后运行demo.m,等待编译运行完毕后,在windows下可以看到这张图:


类似的还有很多张,都是该算法从图像中提取出来的候选区域,下面我们测试一下其Python接口,打开selective_search.py,首先尝试直接运行一下,果然得到了一个错误:


熟悉Linux的马上就会发现,这个目录是Linux下的,当然这个程序本来就是运行在LInux中的,我们只需要把/dev/null改成null就不会报这个错了,改完之后再试着运行一下,T_T


又报了另一个错,这下子必须得看程序了:

# Form the MATLAB script command that processes images and write to
# temporary results file.
f, output_filename = tempfile.mkstemp(suffix='.mat')
os.close(f)
fnames_cell = '{' + ','.join("'{}'".format(x) for x in image_fnames) + '}'
command = "{}({}, '{}')".format(cmd, fnames_cell, output_filename)
print(command)

# Execute command in MATLAB.
mc = "matlab -nojvm -r \"try; {}; catch; exit; end; exit\"".format(command)
pid = subprocess.Popen(
        shlex.split(mc), stdout=open('null', 'w'), cwd=script_dirname)
retcode = pid.wait()
if retcode != 0:
    raise Exception("Matlab script did not exit successfully!")

我们看一下程序核心部分,首先程序生成一个临时.mat文件,然后再python中调用matlab命令行,调用selective_search将生成的box保存到临时生成的mat文件中,然后再读入这个.mat文件读取其中box的数据,这下上面的错误信息就明显了:这个.mat文件是空的

retcode = pid.wait()

后来才发现问题出现在这里,windows下这一行貌似不起作用,程序并不会等待调用matlab的进程执行完毕,就直接执行下面的程序了,所以自然会出现上述错误了,后来又找了很多办法都解决不了,最后只能采用一个笨方法,

time.sleep(5)

在执行上述代码行下面加一行,让主程序在这里停留5s等待命令行完成,这样程序终于运行成功了 ^_^

然后我们把整个项目拷贝到PythonPath中,便于后面在程序中直接调用

2.计算CNN特征:这里直接使用了caffe model下RGB大神训练出来的模型:caffe/models/bvlc_reference_rcnn_ilsvrc13 at master · BVLC/caffe · GitHub,配置文件也是caffe官方提供的deploy.prototxt,基本与CaffeNet一致,只是最后将fc8修改成了fc-rcnn:


caffe这里使用全连接层替换了原文中使用的SVM作为探测器

3.区域分类:这里参考了caffe官方的RCNN-detection教程和pycaffe下的detect.py:

import numpy as np
import pandas as pd
import time
import matplotlib.pyplot as plt
import os

import caffe

CROP_MODES = ['list', 'selective_search']
COORD_COLS = ['ymin', 'xmin', 'ymax', 'xmax']


def detect(pretrained_model,model_def,mean_file,input_file,gpu=True):
    mean=None
    if mean_file:
        mean = np.load(mean_file)
if mean.shape[1:] != (1, 1):
            mean = mean.mean(1).mean(1)
    channel_swap = [2,1,0]

if gpu:
        caffe.set_mode_gpu()
print("GPU mode")
else:
        caffe.set_mode_cpu()
print("CPU mode")

# Make detector.
    detector = caffe.Detector(model_def, pretrained_model, mean=mean,
raw_scale=255.0,channel_swap=channel_swap,context_pad=16)

# Load input.
    t = time.time()
print("Loading input...")
if input_file.lower().endswith('txt'):
with open(input_file) as f:
            inputs = [_.strip() for _ in f.readlines()]
elif input_file.lower().endswith('csv'):
        inputs = pd.read_csv(input_file, sep=',', dtype={'filename': str})
        inputs.set_index('filename', inplace=True)
else:
raise Exception("Unknown input file type: not in txt or csv.")

# Detect.
    detections = detector.detect_selective_search(inputs)
print("Processed {} windows in {:.3f} s.".format(len(detections),
                                                     time.time() - t))

# Collect into dataframe with labeled fields.
    df = pd.DataFrame(detections)
    df.set_index('filename', inplace=True)
    df[COORD_COLS] = pd.DataFrame(
data=np.vstack(df['window']), index=df.index, columns=COORD_COLS)
del(df['window'])

with open('det_synset_words.txt', 'r') as f:
        labels_df = pd.DataFrame([{'synset_id': l.strip().split(' ')[0],
'name': ' '.join(l.strip().split(' ')[1:]).split(',')[0]}
for l in f.readlines()])

for filename in inputs:
        spec_df=df.loc[os.path.abspath(filename)]
        predictions_df = pd.DataFrame(np.vstack(spec_df.prediction.values), columns=labels_df['name'])
        max_s=predictions_df.max(0)
        max_s.sort_values(ascending=False,inplace=True)
print(max_s[:10])

        i = predictions_df[max_s.index[0]].argmax()
        j = predictions_df[max_s.index[1]].argmax()

        im = plt.imread(filename)
        currentAxis = plt.gca()

        det = spec_df.iloc[i]
        coords = (det['xmin'], det['ymin']), det['xmax'] - det['xmin'], det['ymax'] - det['ymin']
        currentAxis.add_patch(plt.Rectangle(*coords, fill=False, edgecolor='r', linewidth=3))
        currentAxis.text(det['xmin'], det['ymin'], max_s.index[0],
bbox=dict(facecolor='blue', alpha=0.5),
fontsize=10, color='white')

        det = spec_df.iloc[j]
        coords = (det['xmin'], det['ymin']), det['xmax'] - det['xmin'], det['ymax'] - det['ymin']
        currentAxis.add_patch(plt.Rectangle(*coords, fill=False, edgecolor='b', linewidth=3))
        currentAxis.text(det['xmin'], det['ymin'], max_s.index[1],
bbox=dict(facecolor='blue', alpha=0.5),
fontsize=10, color='white')

        plt.axis('off')
        plt.imshow(im)
        plt.show()


if __name__=='__main__':
    pretrained_model='../../models/bvlc_reference_rcnn_ilsvrc13/bvlc_reference_rcnn_ilsvrc13.caffemodel'
    model_def='../../models/bvlc_reference_rcnn_ilsvrc13/deploy.prototxt'
    mean_file='../../models/ilsvrc_2012_mean.npy'
    detect(pretrained_model,model_def,mean_file,'det_input.txt')

总体思路就是用selective_search提取出接近2k个候选区域,然后将这些候选区域输入caffe的CNN中,进行一遍forward操作后,然后将最优的几个结果在图像中画出来

三.实验

我们用上述代码进行一些测试,跑出结果只需要对应修改最后几行,修改文件路径即可,detect函数的最后一个参数是输入文件:


里面存放要处理的文件路径名,程序支持一次处理大量图片,但由于前述第二部分windows下的那个bug,图片数量很多时可能需要你手动调整sleep的时长

实验结果图在文章开头部分已经放过了,感兴趣的也可以自己进行测试,我这里只是将可能性最高的两种结果框出来了。

四.总结

RCNN开启了CNN应用于目标检测的大门,后面这一领域快速发展,SPPNet ,Fast RCNN还有近期的Faster RCNN,不仅大大提高了准确率,而且处理速度也飞快提升,Faster RCNN已经可以做到实时处理了。后面有时间会继续分析这一系列论文!

没有更多推荐了,返回首页