总括laravel假数据填充步骤,全栈开发

  1. 概念好模型 xxx.php
  2. 概念好数据变化的平整 database/factories/XxxlFactory.php
  3. 写入生成数据的代码,控制好转变的数码数目,对转移后的数额做出修改 database/seeds/XxxTableSeeder.php
  4. 注册

对数据做增查改删(CRUD)是交互式网络选用的为主职能。对于用户,大家只提供了前三项操作;而对博文,四项操作大家的施用都要提供。

摘要: 什么是光阴连串数据   什么是光阴系列(提姆e
Series,以下简称时序)数据?从概念上的话,就是一串按时间维度索引的数量。用描述性的言语来表明什么是时序数据,一句话来说,正是那类数据描述了某些被度量的重头戏在贰个时光范围内的各样日子点上的度量值。

本项目地址:caffe/ssd

(对于模型中隐藏 $hidden 的字段,须求选用 makeVisible()
方法来权且截至 hidden, 放置写入数据库时出错)

开创博文的模型

如本类别其次片段所说的,博文应该有如下数据:

  • slug:为后端为每篇博文自动生成的独一字符串,用于数据Curry的查询。假如你对这些概念不熟习,请阅读这一维基百科页面
  • title:标题
  • body:大家的博客平台选择马克down编辑器,所以body里储存的是本篇博文的马克down文本
  • description:对本篇博文的一小段介绍
  • favoritesCount:获得的点赞数
  • tagList:标签列表
  • author:我,为其公共消息对象

咱俩先来为地点的多寡新建Mongoose方式,并将其登记为可用的模子。新建models/Article.js文件,写入:

const mongoose = require('mongoose');
const uniqueValidator = require('mongoose-unique-validator');
const slug = require('slug');

const ArticleSchema = new mongoose.Schema({
  slug: {type: String, lowercase: true, unique: true},
  title: String,
  description: String,
  body: String,
  favoritesCount: {type: Number, default: 0},
  tagList: [{type: String}],
  author: {type: mongoose.Schema.Types.ObjectId, ref: 'User'}
}, {timestamps: true});

ArticleSchema.plugin(uniqueValidator, {message: 'is already taken'});

mongoose.model('Article', ArticleSchema);

就如用户情势里平等,大家那里运用了mongoose-unique-validator来验证slug是唯一的。

下面的代码已经导入了slug包。接下来,大家要定义一个新办法,使用那一个包来生成博文slug。为了确认保障slug的唯一性,大家会在原标题生成的字符串后再加上八个随机字符。

ArticleSchema.plugin(uniqueValidator, {message: 'is already taken'});

// +++
ArticleSchema.methods.slugify = function() {
  this.slug = slug(this.title) + '-' + (Math.random() * Math.pow(36, 6) | 0).toString(36);
};
// +++

mongoose.model('Article', ArticleSchema);

如何时候调用这么些方法吗?每当一篇新博文创建后照旧是一篇已有博文的标题产生变动后,往数据库保存的时候,大家须求调用那么些主意生成新的slug。

笔者们得以凭借Mongoose中间件来在上述的场所自动调用slugify方法。

models/Article.js加盟以下代码:

// +++
ArticleSchema.pre('validate', function (next) {
  if (!this.slug || this.isModified('title'))
    this.slugify();
  return next();
});
// +++

mongoose.model('Article', ArticleSchema);

slug的更动应该爆发总括laravel假数据填充步骤,全栈开发。在Mongoose检验数据在此之前,不然没有slug字段,检验必然失利。那也是地点代码中pre'validate'美高梅开户网址,发挥的意趣。

除此以外注意,那里回调函数中的this针对的是当前的博文对象;因而,定义Mongoose中间件时也不可能用箭头函数。

末段,我们还索要加上1个办法,重回博文的JSON对象。不要忘了插足Mongoose自动创立的createAtupdateAt这两条数据。

// +++
ArticleSchema.methods.toJSONFor = function (user) {
  return {
    slug: this.slug,
    title: this.title,
    description: this.description,
    body: this.body,
    createdAt: this.createdAt,
    updatedAt: this.updatedAt,
    tagList: this.tagList,
    favoritesCount: this.favoritesCount,
    author: this.author.toProfileJSONFor(user)
  };
};
// +++

ArticleSchema.pre('validate', ...);

值得提出的是,author一行,大家用到了事先为用户模型定义的toProfileJSONFor(user)方法。

终极,大家供给在后端应用中运作方面包车型地铁本子,不然之后的中间件不可能使用Article模型。

app.js文件里进入一行代码:

require('./models/User');
// +++
require('./models/Article');
// +++
require('./config/passport');

到此博文模型就成立完成了。我们接下去要做的就是添加增查改删博文的路由及相应的中间件。

哪些是光阴系列数据

SSD: Single Shot MultiBox Detector

By Wei
Liu,
Dragomir
Anguelov,
Dumitru
Erhan,
Christian
Szegedy,
Scott
Reed,
Cheng-Yang
Fu,
Alexander C. Berg.

为博文操作新建路由对象

跟以前的手续一样,我们首先要为博文的拥有操作(其跟ULANDL都将是/api/articles)新建一个Router对象。

新建文件/routes/api/articles.js,写入:

const router = require('express').Router();
const passport = require('passport');
const mongoose = require('mongoose');
const Article = mongoose.model('Article');
const User = mongoose.model('User');
const auth = require('../auth');

module.exports = router;

一致地,那几个路由索要注册到API的主路由上。打开routes/api/index.js,加入:

router.use('/profiles', require('./profiles'));
// +++
router.use('/articles', require('./articles'));
// +++

路由对象建好了,也注册到主路由上了,接下去就该兑现具体的中间件了。

  什么是时刻类别(提姆e
Series,以下简称时序)数据?从概念上来说,就是一串按时间维度索引的数量。用描述性的言语来分解如何是时序数据,简单来讲,就是这类数据描述了某些被衡量的重视点在1个小时限制内的各种时间点上的度量值。
  对时序数据举办建模的话,会包涵四个基本点片段,分别是:主体,时间点和度量值。套用这套模型,你会发觉你在平日工作生活中,无时无刻不在接触着那类数据。

简介

SSD是运用单个互连网展开物体格检查测职分的碰面框架.
你能够选取本代码练习/评估物体格检查测职务. 越多细节请见 arXiv
paper
以及
slide.

美高梅开户网址 1

MultiBox

System VOC2007 test mAP FPS (Titan X) Number of Boxes Input resolution
Faster R-CNN (VGG16) 73.2 7 ~6000 ~1000 x 600
YOLO (customized) 63.4 45 98 448 x 448
SSD300* (VGG16) 77.2 46 8732 300 x 300
SSD512* (VGG16) 79.8 19 24564 512 x 512

美高梅开户网址 2

测试对照

Note: SSD300\ and SSD512* are the latest models. Current code should
reproduce these results.*

新建博文

新建博文的端点为POST /api/articles,而且唯有登录的用户才能进行,所以供给身份验证。

routes/api/articles.js投入如下代码:

// +++
const loadCurrentUser = require('./user').loadCurrentUser;

const respondArticle = (req, res, next) => {
  return res.json({article: res.locals.article.otJSONFor(res.locals.res)});
}

router.post('/', auth.required, loadCurrentUser, (req, res, next) => {
  const article = new Article(req.body.article);
  article.author = res.locals.user;
  return article.save().then(() => {
    res.locals.article = article;
    return next();
  }).catch(next);
}, respondArticle);
// +++

module.exports = router;

假如您是三个投保人,某只股票的股票价格就是一类时序数据,其记录着每个时刻点该股票的股票价格。
如果你是2个运行人士,监察和控制数据是一类时序数据,例如对于机械的CPU的监察数据,正是记录着每一种时间点机器上CPU的实际上消耗值。
  这些世界是由数量整合的,在这么些世界上设有的种种物体,每时每刻都在发生着数量。而对那些多少的掘进和行使,在这几个时期,正在默默的改观人们的生活格局。例如通过可穿戴设备对私家健康的保管,正是通过设备源源采撷你的私有健康数据,例如心跳、体温等等,收集完数据后套用模型测算来评估你的健康度。
  借使您的视野和设想空间丰硕大,你会发现你能够挖掘并运用的数据充斥在您所生存的环境中。那个能够爆发多少的指标,会席卷你的无绳电话机、汽车、空气调节、冰橱等等。当前比较炎热的物联网的核心思想,其实正是创设三个得以让具有物体生产数量并打通其价值的网络。而因而这么些互联网采访的数据,便是超人的时序数据。
  时序数据用于描述一个实体在历史的年华维度上的情形变化音讯,而对此时序数据的解析,正是尝试驾驭并把控其变化的规律的进度。随着物联网、大数目和人工智能技术的发展,时序数据也呈2个发生式的增强。而为了更好的支撑那类数据的贮存和分析,在市镇上衍生出了五花八门的新兴的数据库产品。那类数据库产品的发明都以为着解决古板关系型数据库在时序数据存款和储蓄和剖析上的供不应求和症结,那类产品被联合归类为时序数据库。

目录

  1. 安装
  2. 预备
  3. 训练/评估
  4. 模型
  5. 全新的数据集

从URL中收获博文slug

博文的查、改、删操作,都急需从数据库中经过其slug读取该博文的数码。就像上一讲获取用户名相同,大家能够在routes/api/articles.js中用router.param为路由定义二个拿走博文slug的参数中间件,如下:

// +++
router.param('slug', (req, res, next, slug) => {
  Article.findOne({slug})
    //.populate('author')
    .then(article => {
      if (!article)
        return res.status(404).json({errors: {slug: `no such slug: ${slug}`}});
      res.locals.article = article;
      return next();
    })
    .catch(next);
});
// +++

router.post('/', auth.required, loadCurrentUser, ...

每当该路由境遇的U奥迪Q5L中有和:slug相应的片段时,Express就会调用上述中间件,把截取到的数据传给第三个参数slug,然后从数据库中读取相应的博文,存给res.locals.article依旧重回404。

  从DB-Engines的数据库连串流行度趋势榜上得以见到,时序数据库(Time
Series DB)的流行度在前不久的两年内,一贯都是维持1个很高的增高势头。
  接下去小编会写几篇小说,分别来分析:
  1. 时序数据的基本概念,包罗模型、天性和中坚的询问和处理操作。
  2. 多少个流行开源时序数据库的底层达成分析
  3. Ali云表格存款和储蓄(TableStore)的时序数据存款和储蓄和计量化解方案

安装

  1. 下载代码。借使把Caffe克隆到目录$CAFFE_ROOT

  git clone https://github.com/weiliu89/caffe.git
  cd caffe
  git checkout ssd
  1. Build 代码. 按照 Caffe
    instruction
    安装
    必要的packages,然后build。

# 根据Caffe安装的方式修改Makefile.config。
cp Makefile.config.example Makefile.config
make -j8
# 确保include $CAFFE_ROOT/python到PYTHONPATH环境变量内.
make py
make test -j8
# 运行测试,可选   
make runtest -j8

翻看博文

端点为GET /api/articles/:slug,身份验证可有可无。

routes/api/articles.js中写入:

// +++
router.get('/:slug', auth.optional, loadCurrentUser, (req, res, next) => {
  res.locals.article.populate('author')
    .execPopulate()
    .then(() => next())
    .catch(next);
}, respondArticle);
// +++

Mongoose提供的populate()办法,允许三个文书档案(这里是个Article)读取关联的另一个文书档案(这里属于User)。

时间体系数据的特征

预备

  1. 下载 fully convolutional reduced (atrous)
    VGGNet.
    假如文件被下载到了$CAFFE_ROOT/models/VGGNet/目录

  2. 下载VOC2007和VOC2012数据集.
    对帕斯Carl VOC数据集的简介:

    美高梅开户网址 3

    pascal_voc2012_detection_table.jpg

假设下载到了`$HOME/data/`目录

  # 下载数据.
  cd $HOME/data
  wget http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar
  wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar
  wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtest_06-Nov-2007.tar
  # 解压数据.
  tar -xvf VOCtrainval_11-May-2012.tar
  tar -xvf VOCtrainval_06-Nov-2007.tar
  tar -xvf VOCtest_06-Nov-2007.tar

VOC 2006年的数量分为VOCtrainval和VOCtest多少个tar包,VOC
二〇一一年的数目只有VOCtrainval1个tar包,如下

美高梅开户网址 4

VOC0712的三个tar包

解压后,二零零六和二零一一两年的多寡在VOCdevkit目录的VOC2007VOC2012八个子目录中。各样子目录下,分别包蕴了四个文本夹,分别是Annotations
ImageSets JPEGImages SegmentationClass 以及
SegmentationObject。对于SSD的Object任务,需求利用Annotations中的xml标注文件,ImagesSets/Main/目录中的trainval.txttest.txt,以及JPEGImages目录下的图像。

美高梅开户网址 5

VOC2007解压

美高梅开户网址 6

VOC2012解压后

  1. 创建LMDB文件.

  cd $CAFFE_ROOT
  # Create the trainval.txt, test.txt, and test_name_size.txt in data/VOC0712/
  ./data/VOC0712/create_list.sh
  # 如有必要,可以按需修改create_data.sh文件.
  # 编码trainval和test原始图像,生成lmdb文件:
  #   - $HOME/data/VOCdevkit/VOC0712/lmdb/VOC0712_trainval_lmdb
  #   - $HOME/data/VOCdevkit/VOC0712/lmdb/VOC0712_test_lmdb
  # and make soft links at examples/VOC0712/
  ./data/VOC0712/create_data.sh

变迁的trainval.txt格式如图,文件内容是图像的路子和标注文件的路子,中间用空格分隔离:

美高梅开户网址 7

trainval.txt

生成的test_name_size.txt是测试图像的id heightwidth

美高梅开户网址 8

test_name_size.txt

末尾,生成trainval和test七个lmdb数据库,分别用来陶冶和测试SSD模型。

美高梅开户网址 9

voc0712 trainval and test lmdbs

trainval LMDB

美高梅开户网址 10

trainval lmdb

同时,在.../caffe/examples/VOC0712/路线下保存了上边八个lmdb数据库的链接,截图如下:

美高梅开户网址 11

voc0712_lmdb_link

变动博文

端点是PUT /api/articles/:slug,身份验证是必备的,请求体的数据会覆盖相应字段。其余,大家还需确定保障当前登录的用户必须是该博文的小编,不然重临403。

routes/api/articles.js中写入:

// +++
const checkAuthor = (req, res, next) => {
  if (!res.locals.user.equals(res.locals.article.author))
    return res.status(403).json({errors: {user: 'not the author'}});
  return next();
};

router.put('/:slug', auth.required, loadCurrentUser, checkAuthor,
  (req, res, next) => {
    ['title', 'description', 'body'].forEach(propName => {
      if (!req.body.article.hasOwnProperty(propName)) return;
      res.locals.article[propName] = req.body.article[propName];
    });
    res.locals.article.save()
      .then(() => next())
      .catch(next);
  }, respondArticle);
// +++

module.exports = router;

  对于时序数据的风味的剖析,会从数额的写入、查询和仓库储存这八个维度来阐释,通过对其性状的辨析,来演绎对时序数据库的基本要求。

训练/评估

  1. 陶冶你协调的模子并评估.

# 创建模型定义文件并保存模型训练快照到如下路径:
#   - $CAFFE_ROOT/models/VGGNet/VOC0712/SSD_300x300/
# and job file, log file, and the python script in:
#   - $CAFFE_ROOT/jobs/VGGNet/VOC0712/SSD_300x300/
# 保存当前评估结果到:
#   - $HOME/data/VOCdevkit/results/VOC2007/SSD_300x300/
# 120K次迭代之后,应该可以达到77.*的mAP.
python examples/ssd/ssd_pascal.py

借使不乐意本身演练模型,能够在here下载预磨炼好的模型.注意是用PASCAL
VOC数据集中磨练练的。

通过分析ssd_pascal.py的源码,可以知晓陶冶ssd模型须要多少个公文输入,分别是
train_data = "examples/VOC0712/VOC0712_trainval_lmdb"
test_data = "examples/VOC0712/VOC0712_test_lmdb"
name_size_file = "data/VOC0712/test_name_size.txt"
pretrain_model = "models/VGGNet/VGG_ILSVRC_16_layers_fc_reduced.caffemodel"
label_map_file = "data/VOC0712/labelmap_voc.prototxt"
train_net_file = "models/VGGNet/VOC0712/SSD_300x300/train.prototxt"
test_net_file = "models/VGGNet/VOC0712/SSD_300x300/test.prototxt"
deploy_net_file = "models/VGGNet/VOC0712/SSD_300x300/deploy.prototxt"
solver_file = "models/VGGNet/VOC0712/SSD_300x300/solver.prototxt"

其中,train_datatest_data是事先成立的LMDB数据库文件,用于陶冶和测试模型。name_size_file是以前创造的测试图像集的图像id和size文件,用于模型的测试。pretrain_model是base
network部分(VGG_16的卷积层)的预演习参数。label_map_file保存的是实体的name和label的投射文件,用于练习和测试。这三个公文是事先都准备好的.

背后的多个公文,train_net_file test_net_file
deploy_net_filesolver_file是在ssd_pascal.py本子中依据模型定义和练习方针参数自动生成的。例如,train_net_file,也就是train.prototxt,生成语句是shutil.copy(train_net_file, job_dir),具体的代码片段如下:

# Create train net.
net = caffe.NetSpec()
net.data, net.label = CreateAnnotatedDataLayer(train_data, batch_size=batch_size_per_device,
        train=True, output_label=True, label_map_file=label_map_file,
        transform_param=train_transform_param, batch_sampler=batch_sampler)

VGGNetBody(net, from_layer='data', fully_conv=True, reduced=True, dilated=True,
    dropout=False)

AddExtraLayers(net, use_batchnorm, lr_mult=lr_mult)

mbox_layers = CreateMultiBoxHead(net, data_layer='data', from_layers=mbox_source_layers,
        use_batchnorm=use_batchnorm, min_sizes=min_sizes, max_sizes=max_sizes,
        aspect_ratios=aspect_ratios, steps=steps, normalizations=normalizations,
        num_classes=num_classes, share_location=share_location, flip=flip, clip=clip,
        prior_variance=prior_variance, kernel_size=3, pad=1, lr_mult=lr_mult)

# Create the MultiBoxLossLayer.
name = "mbox_loss"
mbox_layers.append(net.label)
net[name] = L.MultiBoxLoss(*mbox_layers, multibox_loss_param=multibox_loss_param,
        loss_param=loss_param, include=dict(phase=caffe_pb2.Phase.Value('TRAIN')),
        propagate_down=[True, True, False, False])

with open(train_net_file, 'w') as f:
    print('name: "{}_train"'.format(model_name), file=f)
    print(net.to_proto(), file=f)
shutil.copy(train_net_file, job_dir)
  1. 利用新型模型快照评估模型.

  # 如果你需要对训练的模型进行评估,执行脚本:
  python examples/ssd/score_ssd_pascal.py
  1. 运用webcam录像头测试模型. 注意: 按 <kbd>esc</kbd> 结束.

  # 连接webcam摄像头和预训练的模型进行演示,运行:
  python examples/ssd/ssd_pascal_webcam.py

Here
体现了二个在
MSCOCO
数据集上陶冶的模型SSD500的演示录制.

  1. 查看
    examples/ssd_detect.ipynb
    或者
    examples/ssd/ssd_detect.cpp
    如何运用ssd模型检查和测试物体. 查看
    examples/ssd/plot_detections.py
    怎么样绘制 ssd_detect.cpp的检查和测试结果.

  2. 如果利用别的数据集中练习练, 请参考data/OTHE安德拉DATASET 领悟更加多细节.
    如今支撑COCO 和 ILSVQashqaiC2015数额集. 提议采纳
    examples/ssd.ipynb
    检查新的数据集是或不是吻合要求.

删除博文

端点为DELETE /api/articles/:slug,须求身份验证,不必要请求体。同上,大家须求检讨当前用户是或不是该博文的撰稿人。假使去除成功,大家回到状态码为204且无响应体的响应。

routes/api/articles.js中写入:

// +++
router.delete('/:slug', auth.required, loadCurrentUser, checkAuthor,
  (req, res, next) => {
    res.locals.article.remove()
      .then(() => res.sendStatus(204))
      .catch(next);
  });
// +++

module.exports = router;

到此,博文增查改删就全体兑现了。

多少写入的特征

模型

在分歧数额集上演习了模型以供下载. 为了复现杂谈Table
6中的结果,
每一个模型文件夹内都富含一个.caffemodel 文件, 几个.prototxt 文件,
以及python脚本文件.

  1. PASCAL VOC 模型:

    • 07+12:
      SSD300*,
      SSD512*
    • 07++12:
      SSD300*,
      SSD512*
    • COCO\[1\]:
      SSD300*,
      SSD512*
    • 07+12+COCO:
      SSD300*,
      SSD512*
    • 07++12+COCO:
      SSD300*,
      SSD512*
  2. COCO 模型:

    • trainval35k:
      SSD300*,
      SSD512*
  3. ILSVRC 模型:

    • trainval1:
      SSD300*,
      SSD500

写入平稳、持续、高并发高吞吐:时序数据的写入是相比稳定的,那点与应用数据差异,应用数据一般与利用的访问量成正比,而接纳的访问量平常存在波峰波谷。时序数据的发出平日是以二个定点的时光频率发生,不会受任何因素的钳制,其数据变化的进程是相对比较平稳的。时序数据是由每一个个体独立生成,所以当个体数量过多时,平日写入的面世和吞吐量都以比较高的,尤其是在物联网场景下。写入并发和吞吐量,可以省略的经过个人数量和数码生成频率来测算,例固然您有1000个村办以10秒的成效产生多少,则你平分每秒爆发的产出和写入量正是100。
写多读少:时序数据上95%-99%的操作都是写操作,是独立的写多读少的数目。那与其数量天性相关,例如监察和控制数据,你的监察和控制项可能很多,不过你真的去读的恐怕比较少,平常只会关怀多少个特定的首要指标依旧在一定的光景下才会去读数据。
实时写入如今变动的数量,无更新:时序数据的写入是实时的,且每回写入都是近些年变化的数码,那与其数额变动的特色有关,因为其数据变化是随着年华推进的,而新生成的多寡会实时的展开写入。数据写入无更新,在时间这些维度上,随着时光的递进,每一趟数据都是新数据,不会存在旧数据的换代,不过不清除人为的对数据做改进。

全新的数据集

在在此以前的训练/评估的首先部分,大家介绍了怎么着准备数据集:

  • dbname_trainval_lmdb
  • dbname_test_lmdb
  • test_name_size.txt
  • labelmap_dbname.prototxt
  • VGG_ILSVRC_16_layers_fc_reduced.caffemodel

崭新的数目代表分化的磨炼/测试图像,分裂的object name
label映射关系,不一样的互联网模型定义参数。首先,我们须要根据新的图像数据集生成模型的输入部分,也正是下边包车型大巴多少个文本。

  1. VGG_ILSVRC_16_layers_fc_reduced.caffemodel是预磨炼好的VGG_16的卷积层的参数,直接下载使用即可,这里不再介绍如何重新兵训练练VGG_15分类模型。

  2. labelmap_dbname.prototxt是标注文件中object的name和label的投射文件,一般项目不会太多,直接编写此文件即可。例如,三个可能的照耀文件:

    item {
      name: "none_of_the_above"
      label: 0
      display_name: "background"
    }
    item {
      name: "Car"
      label: 1
      display_name: "car"
    }
    item {
      name: "Bus"
      label: 2
      display_name: "bus"
    }
    item {
      name: "Van"
      label: 3
      display_name: "van"
    }
    ...
    
  3. test_name_size.txt文件保留了具备测试图像的id height
    width信息,由create_list.sh剧本完成创立。通过分析create_list.sh本子可见晓,该脚本共创造了多个txt文件,分别是trainval.txt
    test.txtdbname_name_size.txt

    • trainval.txttest.txt中,每一行保存了图像文件的门道和图像标注文件的门道,中间以空格分开。片段如下:

    VOC2012/JPEGImages/2010_003429.jpg VOC2012/Annotations/2010_003429.xml
    VOC2007/JPEGImages/008716.jpg VOC2007/Annotations/008716.xml
    VOC2012/JPEGImages/2009_004804.jpg VOC2012/Annotations/2009_004804.xml
    VOC2007/JPEGImages/005293.jpg VOC2007/Annotations/005293.xml
    

    注意,trainval中的顺序是乱糟糟的,test中的顺序不必打乱。

    • test_name_size.txt文本是由.../caffe/get_image_size次第生成的,其源码位于.../caffe/tools/get_image_size.cpp中。那段程序的效应是依照test.txt中提供的测试图像的路径音信和数据集根目录音信(两段路径拼合获得图像的相对路径),自动测算每张图像的heightwidthget_image_size.cpp中的核心代码段为:

    // Storing to outfile
    boost::filesystem::path root_folder(argv[1]);
    std::ofstream outfile(argv[3]);
    if (!outfile.good()) {
      LOG(FATAL) << "Failed to open file: " << argv[3];
    }
    int height, width;
    int count = 0;
    for (int line_id = 0; line_id < lines.size(); ++line_id) {
      boost::filesystem::path img_file = root_folder / lines[line_id].first;
      GetImageSize(img_file.string(), &height, &width);
      std::string img_name = img_file.stem().string();
      if (map_name_id.size() == 0) {
        outfile << img_name << " " << height << " " << width << std::endl;
      } else {
        CHECK(map_name_id.find(img_name) != map_name_id.end());
        int img_id = map_name_id.find(img_name)->second;
        outfile << img_id << " " << height << " " << width << std::endl;
      }
    
      if (++count % 1000 == 0) {
        LOG(INFO) << "Processed " << count << " files.";
      }
    }
    // write the last batch
    if (count % 1000 != 0) {
      LOG(INFO) << "Processed " << count << " files.";
    }
    outfile.flush();
    outfile.close();
    

    保存到test_name_size.txt中的内容片段如下:

    000001 500 353
    000002 500 335
    000003 375 500
    000004 406 500
    000006 375 500
    000008 375 500
    000010 480 354
    

    现在,trainval.txt
    test.txttest_name_size.txt的始末已经很清晰了,能够动用现成的代码程序,适当修改图像数据集名称和途径就可以创设那多少个文本。当然,也得以依照自个儿的编制程序喜好,重新编排脚本生成符合地点格式的txt文件即可。

  4. dbname_trainval_lmdb
    转移该数据库文件的程序为create_data.sh,其主导代码是实施python脚本.../caffe/scripts/create_annoset.py,该脚本须求事先准备的
    labelmap_dbname.prototxttrainval.txt
    作为输入,以及多少个可布署项。
    .../caffe/scripts/create_annoset.py本子的大旨代码是实行.../caffe/build/tools/convert_annoset程序。labelmap_dbname.prototxt

    trainval.txt就是为convert_annoset先后准备的,其源码在.../caffe/tools/convert_annoset.cpp中。创造并写入数据库的为主代码片段如下:

// 创建一个新的数据库
scoped_ptr<db::DB> db(db::GetDB(FLAGS_backend));
db->Open(argv[3], db::NEW);
scoped_ptr<db::Transaction> txn(db->NewTransaction());

// 把数据存储到数据库
std::string root_folder(argv[1]);
AnnotatedDatum anno_datum;
Datum* datum = anno_datum.mutable_datum();
int count = 0;
int data_size = 0;
bool data_size_initialized = false;

for (int line_id = 0; line_id < lines.size(); ++line_id) {
  bool status = true;
  std::string enc = encode_type;
  if (encoded && !enc.size()) {
    // Guess the encoding type from the file name
    string fn = lines[line_id].first;
    size_t p = fn.rfind('.');
    if ( p == fn.npos )
      LOG(WARNING) << "Failed to guess the encoding of '" << fn << "'";
    enc = fn.substr(p);
    std::transform(enc.begin(), enc.end(), enc.begin(), ::tolower);
  }
  filename = root_folder + lines[line_id].first;
  if (anno_type == "classification") {
    label = boost::get<int>(lines[line_id].second);
    status = ReadImageToDatum(filename, label, resize_height, resize_width,
        min_dim, max_dim, is_color, enc, datum);
  } else if (anno_type == "detection") {
    labelname = root_folder + boost::get<std::string>(lines[line_id].second);
    status = ReadRichImageToAnnotatedDatum(filename, labelname, resize_height,
        resize_width, min_dim, max_dim, is_color, enc, type, label_type,
        name_to_label, &anno_datum);
    anno_datum.set_type(AnnotatedDatum_AnnotationType_BBOX);
  }
  if (status == false) {
    LOG(WARNING) << "Failed to read " << lines[line_id].first;
    continue;
  }
  if (check_size) {
    if (!data_size_initialized) {
      data_size = datum->channels() * datum->height() * datum->width();
      data_size_initialized = true;
    } else {
      const std::string& data = datum->data();
      CHECK_EQ(data.size(), data_size) << "Incorrect data field size "
          << data.size();
    }
  }
  // 序列化
  string key_str = caffe::format_int(line_id, 8) + "_" + lines[line_id].first;

  // 把数据Put到数据库
  string out;
  CHECK(anno_datum.SerializeToString(&out));
  txn->Put(key_str, out);

  if (++count % 1000 == 0) {
    // Commit db
    txn->Commit();
    txn.reset(db->NewTransaction());
    LOG(INFO) << "Processed " << count << " files.";
  }// end if
}//end for
// 写入最后一个batch的数据
if (count % 1000 != 0) {
  txn->Commit();
  LOG(INFO) << "Processed " << count << " files.";
}

那段代码中最要害的一行是对ReadRichImageToAnnotatedDatum()格局的调用,将图像文件和标注消息一起写入到了anno_datum变量中,再系列化,提交到数据库缓存区,缓存到早晚数额的笔录后二次性写入数据库。

ReadRichImageToAnnotatedDatum()主意由Caffe提供,是caffe/src/util/io.cpp中定义的一个措施,该格局及其其调用的ReadImageToDatum方法和GetImageSize方法源码如下:

bool ReadImageToDatum(const string& filename, const int label,
    const int height, const int width, const int min_dim, const int max_dim,
    const bool is_color, const std::string & encoding, Datum* datum) {
  cv::Mat cv_img = ReadImageToCVMat(filename, height, width, min_dim, max_dim,
                                    is_color);
  if (cv_img.data) {
    if (encoding.size()) {
      if ( (cv_img.channels() == 3) == is_color && !height && !width &&
          !min_dim && !max_dim && matchExt(filename, encoding) ) {
        datum->set_channels(cv_img.channels());
        datum->set_height(cv_img.rows);
        datum->set_width(cv_img.cols);
        return ReadFileToDatum(filename, label, datum);
      }
      EncodeCVMatToDatum(cv_img, encoding, datum);
      datum->set_label(label);
      return true;
    }
    CVMatToDatum(cv_img, datum);
    datum->set_label(label);
    return true;
  } else {
    return false;
  }
}

void GetImageSize(const string& filename, int* height, int* width) {
  cv::Mat cv_img = cv::imread(filename);
  if (!cv_img.data) {
    LOG(ERROR) << "Could not open or find file " << filename;
    return;
  }
  *height = cv_img.rows;
  *width = cv_img.cols;
}

bool ReadRichImageToAnnotatedDatum(const string& filename,
    const string& labelfile, const int height, const int width,
    const int min_dim, const int max_dim, const bool is_color,
    const string& encoding, const AnnotatedDatum_AnnotationType type,
    const string& labeltype, const std::map<string, int>& name_to_label,
    AnnotatedDatum* anno_datum) {
  // Read image to datum.
  bool status = ReadImageToDatum(filename, -1, height, width,
                                 min_dim, max_dim, is_color, encoding,
                                 anno_datum->mutable_datum());
  if (status == false) {
    return status;
  }
  anno_datum->clear_annotation_group();
  if (!boost::filesystem::exists(labelfile)) {
    return true;
  }
  switch (type) {
    case AnnotatedDatum_AnnotationType_BBOX:
      int ori_height, ori_width;
      GetImageSize(filename, &ori_height, &ori_width);
      if (labeltype == "xml") {
        return ReadXMLToAnnotatedDatum(labelfile, ori_height, ori_width,
                                       name_to_label, anno_datum);
      } else if (labeltype == "json") {
        return ReadJSONToAnnotatedDatum(labelfile, ori_height, ori_width,
                                        name_to_label, anno_datum);
      } else if (labeltype == "txt") {
        return ReadTxtToAnnotatedDatum(labelfile, ori_height, ori_width,
                                       anno_datum);
      } else {
        LOG(FATAL) << "Unknown label file type.";
        return false;
      }
      break;
    default:
      LOG(FATAL) << "Unknown annotation type.";
      return false;
  }
}

能够看出在地点的章程中延续调用了io.cpp中的多少个章程ReadFileToDatumReadXMLToAnnotatedDatum,分别把图像和图像的标注XML写入到了anno_datum中。在那之中,图像保存到了anno_datummutable_datum中,XML标注音信被保存到了anno_datumanno_group->anno->bbox中,anno_group还保存了label等信息。

  1. dbname_test_lmdb
    4.dbname_trainval_lmdb
  2. 使用examples/ssd.ipynb核准下面生成的文本的科学

\[1\]We use
examples/convert_model.ipynb
to extract a VOC model from a pretrained COCO model.

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图