FCN制作自己的数据集并训练和测试

前言

这篇博客记录的是如何制作自己的数据集,并使用FCN模型训练数据,前提要搭建caffe框架,可以参考这篇博客,我制作的数据集是仿照voc2012数据集来在做的

制作图像标签

这一部分是最难的部分,在制作标签之前要搞清楚你的图像共分为几类

  1. 调整图像尺寸
    网上很多写的代码,但是我试了都不成功,于是自己写了一个matlab代码,可以将整个文件夹图片缩成256*256大小,我图片的命名规则是1,2,3,4……如果你图像不是这样命名的话就不能使用。如果谁有更好的代码麻烦告知一二。

    ObjDir = 'D:\image1\';%将被改变的图像地址,称为目标地址
    OtpDir = 'D:\image2\';%输出图像地址,称为输出地址
    for i = 1:101 %我的图片是101张
        bgFile = [ObjDir,num2str(i),'.jpg'];%这句话读取目标地址里面的格式为jpg的图片
        bgFile = imread(bgFile);%把图片读成matlab认识的,类型为:图片
        img = imresize(bgFile,[256,256]);%调整大小到高256,长256
        filename=[num2str(i),'.jpg'];%输出的图片名称
        path=fullfile(OtpDir,filename);%输出的路径
        imwrite(img,path,'jpg');%以jpg格式输出出去
    end
    
  2. 制作索引图(即标签)
    这就是最难也是最烦的部分,很多博客都说用labelme工具制作标签,这工具确实方便,但是我试了之后才发现会出现问题,比如说第一张图片有汽车,有小猫,这是两个不同的类将会标注为两个不同的颜色,如果第二张图片没有汽车只有小猫的话,那这张图片小猫将会和汽车标注成同一张颜色。可能我这样解释会有点蒙,你可以参考labelme安装json批量转化数据两篇博客试试,有人解释说是因为labelme的版本变高自动生成颜色,但是并没有给出解决办法,于是在这一步的操作我选择了使用photoshop工具。
    对应的voc数据集颜色类别为:

    类别名称 R G B
    background 0 0 0 背景
    aeroplane 128 0 0 飞机
    bicycle 0 128 0
    bird 128 128 0
    boat 0 0 128
    bottle 128 0 128 瓶子
    bus 0 128 128 大巴
    car 128 128 128
    cat 64 0 0 猫
    chair 192 0 0
    cow 64 128 0
    diningtable 192 128 0 餐桌
    dog 64 0 128
    horse 192 0 128
    motorbike 64 128 128
    person 192 128 128
    pottedplant 0 64 0 盆栽
    sheep 128 64 0
    sofa 0 192 0
    train 128 192 0
    tvmonitor 0 64 128 显示器

这里有21个类别,因为我的图片只有4类加上背景共5类,所以只用到了前五中颜色。如下面的图是我是做的标签,我是将所有一类放在一起制作的,这样不容易乱,但是在训练数据的时候,要将所有图片打乱顺序,以免出现训练效果差的结果。(下面有好的方法不用打乱图像顺序)
在这里插入图片描述
用ps制作成的图像保存为png格式,这时你的图片是24位的,接下来需要将图像改为8位的,下面是matlab代码可以将整个文件夹的图片改成8位。

dirs=dir('D:\24-testlabel\*.png');
for n=1:numel(dirs)
     strname=strcat('D:\24-testlabel\',dirs(n).name);
     img=imread(strname);
     x=rgb2ind(img,map);
     newname=strcat('D:\8-testlabel\',dirs(n).name);
     imwrite(x,map,newname,'png');
end

转化完成后在Python中检查一下图片的格式。
在命令窗口输入idle(前提你装了python),输入

import PIL.Image
import numpy as np
img = PIL.Image.open(D:/8-testlabel/1l.png')
np.unique(img)

如果输出为如下,则说明标签制作成功。

array([0, 1, 2], dtype=uint8)

训练数据集

  1. benchmark数据集下载地址:benchmark数据集
    VOC2012数据集下载地址:VOC2012数据集
    benchmark数据集是用来存放训练的数据,VOC2012数据集用来存放测试数据。
  2. 进入fcn-master/data目录,新建sbdd文件夹(如果没有),将benchmark解压到sbdd中,进入dataset文件夹,你将看到如图所示五个文件,cls是用来存放索引图(标签),img用来存放训练数据(原训练图像),train.txt用来存放训练数据的名称,val.txt用来存放验证集的名称(这里并没有用到)。
    在这里插入图片描述
    将你的训练图片复制到img文件夹下,图片标签复制到cls文件夹下,将你训练图片的名称写入到train.txt文件中,如下图所示
    在这里插入图片描述
    因为打乱图片顺序比较麻烦,所以可以将图片名称顺序打乱,这样方便的多。
    进入cls文件夹,这里原本需要存放mat格式的文件,但是制作mat文件有点麻烦,参考了网上的资料,修改代码,使得这里也可以直接存放索引图。
    方式如下:
    修改fcn目录下的voc_layers.py
#    def load_label(self, idx):
#        """
#        Load label image as 1 x height x width integer array of label indices.
#        The leading singleton dimension is required by the loss.
#        """
#        import scipy.io
#        mat = scipy.io.loadmat('{}/cls/{}.mat'.format(self.sbdd_dir, idx))
#        label = mat['GTcls'][0]['Segmentation'][0].astype(np.uint8)
#        label = label[np.newaxis, ...]
#        return label

    def load_label(self, idx):
        """
        Load label image as 1 x height x width integer array of label indices.
        The leading singleton dimension is required by the loss.
        """
        im = Image.open('{}/cls/{}.png'.format(self.sbdd_dir, idx))
        label = np.array(im, dtype=np.uint8)
        label = label[np.newaxis, ...]
        return label

测试集的制作简单一写,进入VOC2012,进入JPEGImages文件夹,里面存放测试用的原图,然后进入SegmentationClass,里面存放测试用的索引图,最后进入ImageSets/Segmentation,新建seg11valid.txt的文件,它和train.txt的性质一样,存放测试用的图片名。
到此,数据集就准备完成了。

  1. 修改网络参数
    (1)下载VGG16的预训练模型VGG_ILSVRC_16_layers_deploy.prototxt并放在FCN源码文件夹中的ilsvrc-nets文件夹下
    在这里插入图片描述
    (2)进入fcn-master目录下,将所有py文件全部复制到voc-fcn32s(这里用voc-fcn32s模型训练数据),新建snapshot文件夹。
    在这里插入图片描述
    (3)打开solve.py文件
    为了避免运行程序时候出现no module named caffe ,在代码中包含import caffe的py文件的第一行加入

    import sys  
    sys.path.append('C:/caffe/caffe-master/python')
    

    其中,C:/caffe/caffe-master/python为你下载的caffe源码中python文件夹的路径
    (4)修改solve.py文件

    ```
    import caffe
    import surgery, score
    
    import numpy as np
    import os
    import sys
    sys.path.append('C:/caffe/caffe-master/python')
    
    try:
       import setproctitle
       setproctitle.setproctitle(os.path.basename(os.getcwd()))
    except:
       pass
    
    #weights = '../ilsvrc-nets/vgg16-fcn.caffemodel'
    vgg_weights = '../ilsvrc-nets/vgg16-fcn.caffemodel'
    vgg_proto = '../ilsvrc-nets/VGG_ILSVRC_16_layers_deploy.prototxt'
    weights = '../ilsvrc-nets/vgg16-fcn.caffemodel'
    
    # init
    #caffe.set_device(int(sys.argv[1]))               
    caffe.set_mode_gpu()
    caffe.set_device(0)
    
    #solver = caffe.SGDSolver('solver.prototxt')
    #solver.net.copy_from(weights)
    solver = caffe.SGDSolver('solver.prototxt')
    vgg_net=caffe.Net(vgg_proto,vgg_weights,caffe.TRAIN)
    surgery.transplant(solver.net,vgg_net)
    del vgg_net
    
    
    # surgeries
    interp_layers = [k for k in solver.net.params.keys() if 'up' in k]
    surgery.interp(solver.net, interp_layers)
    
    # scoring
    val = np.loadtxt('D:/caffe/caffe-master/fcn-master/data/pascal/VOCdevkit/VOC2012/ImageSets/Segmentation/seg11valid.txt', dtype=str)       #根据你电脑自己的路径修改
    
    for _ in range(25):
       solver.step(4000)
       score.seg_tests(solver, False, val, layer='score')
    ```
    

(5)solver.prototxt文件修改

	```
	train_net: "train.prototxt"
	test_net: "val.prototxt"
	test_iter: 2    #因为我的图片少,所以这里测试图片参数就写少一点,如果图片多的话可以使用默认参数
	# make test net, but don't invoke it from the solver itself
	test_interval: 999999999
	display: 20
	average_loss: 20
	lr_policy: "fixed"
	# lr for unnormalized softmax
	base_lr: 1e-10
	# high momentum
	momentum: 0.99
	# no gradient accumulation
	iter_size: 1
	max_iter: 100000
	weight_decay: 0.0005
	snapshot: 4000
	snapshot_prefix: "snapshot1/train"
	test_initialization: false
	```

(6)修改训练,测试文件参数
用vs2013打开train.prototxt文件,根据自己电脑的路径代码修改为:

param_str: "{\'sbdd_dir\': \'D:/caffe/caffe-master/fcn-master/data/sbdd/benchmark/benchmark_RELEASE/dataset\', \'seed\': 1337, \'split\': \'train\', \'mean\': (104.00699, 116.66877, 122.67892)}"

所有num_output 为21 的地方都修改为自己分类数 + 1 (加的1是背景)
用vs2013打开val.prototxt文件,根据自己电脑的路径代码修改为:

param_str: "{\'voc_dir\': \'D:/caffe/caffe-master/fcn-master/data/pascal/VOCdevkit/VOC2012\', \'seed\': 1337, \'split\': \'seg11valid\', \'mean\': (104.00699, 116.66877, 122.67892)}"

所有num_output 为21 的地方都修改为自己分类数 + 1 (加的1是背景)
到此所有工作准备完成了,接下来开始训练数据
(7)训练数据
开cmd命令窗口,将目录指定到voc-fcn32s路径下,输入

python.exe  solve.py

如下图所示
在这里插入图片描述
(8)单张测试
在fcn-32s文件夹中找到infer.py文件,修改代码为

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
import caffe
import vis
import sys
sys.path.append('D:/caffe/caffe-master/python')

# the demo image is "2007_000129" from PASCAL VOC

# load image, switch to BGR, subtract mean, and make dims C x H x W for Caffe
im = Image.open('D:/caffe/caffe-master/fcn-master/voc-fcn32s/data/1.jpg')  #可以自己创建路径
in_ = np.array(im, dtype=np.float32)
in_ = in_[:,:,::-1]
in_ -= np.array((104.00698793,116.66876762,122.67891434))
in_ = in_.transpose((2,0,1))

# load net
#net = caffe.Net('voc-fcn8s/deploy.prototxt', 'voc-fcn8s/fcn8s-heavy-pascal.caffemodel', caffe.TEST)
net = caffe.Net('D:/caffe/caffe-master/fcn-master/voc-fcn32s/deploy.prototxt', 'D:/caffe/caffe-master/fcn-master/voc-fcn32s/snapshot/train_iter_100000.caffemodel', caffe.TEST)
# shape for input (data blob is N x C x H x W), set data
net.blobs['data'].reshape(1, *in_.shape)
net.blobs['data'].data[...] = in_
# run net and take argmax for prediction
net.forward()
out = net.blobs['score'].data[0].argmax(axis=0)


# visualize segmentation in PASCAL VOC colors
voc_palette = vis.make_palette(21)
out_im = Image.fromarray(vis.color_seg(out, voc_palette))
out_im.save('data/output3.png')
masked_im = Image.fromarray(vis.vis_seg(im, out, voc_palette))
masked_im.save('data/visualization3.jpg')

fcn-32s和fcn-16s是没有deploy文件,很多博客都是说参考train.prototxt创建deploy文件,我就是按照这样的方法,但是根本不能正确测试图片,这让我一度怀疑自己的方向是不是错的,走了很多弯路。后来我找到别人的deploy文件,直接下载复制到对应为文件夹下就行。
deploy下载地址:deploy.prototxt

至此所有的工作已完成,在这探索的过程真的很心酸,所以想把过程记录下来以方便以后的学习。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章