SSD目标检测lmdb数据结构剖析

2024-04-20 01:32

本文主要是介绍SSD目标检测lmdb数据结构剖析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

SSD读取训练集是从LMDB中读取AnnotatedDatum结构的数据,在训练和测试之前,要将图片(img)和XML(label)数据存储为AnnotatedDatum结构,然后将数据经过序列化,存入到LMDB数据库中。训练和测试的时候直接从LMDB读取数据,经过反序列化获取AnnotatedDatum结构的数据,获得训练集的图片和XML数据。

可以参考ssd caffe目录包下的src/caffe/util/io.cpp, tools/convert_annoset.cpp,会对你理解数据结构有很大的作用。

也是C++ 强大的动态内存管理推波助澜。

AnnotatedData数据结构

message AnnotatedDataParameter {
  // Define the sampler.
  repeated BatchSampler batch_sampler = 1;
  // Store label name and label id in LabelMap format.
  optional string label_map_file = 2;
  // If provided, it will replace the AnnotationType stored in each
  // AnnotatedDatum.
  optional AnnotatedDatum.AnnotationType anno_type = 3;

}


一、LMDB数据库

  • LMDB的全称是Lightning Memory-Mapped
    Database,意为闪电般的内存映射数据库。它文件结构简单,一个文件夹,里面一个数据文件data.mdb,一个锁文件lock.mdb。数据随意复制,随意传输。它的访问简单,不需要运行单独的数据库管理进程,只要在访问数据的代码里引用LMDB库,访问时给文件路径即可。
  • Caffe引入数据库存放数据集,是为了减少IO开销。LMDB的整个数据库放在一个文件里,避免了文件系统寻址的开销。LMDB使用内存映射的方式访问文件,使得文件内寻址的开销非常小,使用指针运算就能实现。数据库单文件还能减少数据集复制/传输过程的开销。一个几万,几十万文件的数据集,不管是直接复制,还是打包再解包,过程都无比漫长而痛苦。LMDB数据库只有一个文件,传输介质有多块,就能复制多快,不会因为文件多而变得很慢。

    这里写图片描述


二、AnnotatedDatum数据结构

 以PASCAL VOC数据集为例,label为$CAFFE_ROOT/data/VOCdevkit/VOC2007/Annotations下的XML文件,图片为$CAFFE_ROOT/data/VOCdevkit/VOC2007/JPEGImages下的图片文件。

    这里写图片描述

  • SSD读取数据,要将label和图片封装到一个数据结构下,用的是AnnotatedDatum结构,定义如下:
// An extension of Datum which contains "rich" annotations.
message AnnotatedDatum {enum AnnotationType {BBOX = 0;}optional Datum datum = 1;// If there are "rich" annotations, specify the type of annotation.// Currently it only supports bounding box.// If there are no "rich" annotations, use label in datum instead.optional AnnotationType type = 2;// Each group contains annotation for a particular class.repeated AnnotationGroup annotation_group = 3;
}
  • AnnotatedDatum结构里面包含AnnotationGroup结构、Datum结构和AnnotationType。Datum结构用于存放图片信息,后面会说到;使用$CAFFE_ROOT/src/caffe/util/io.cpp里面定义的ReadXMLToAnnotatedDatum函数将XML文件信息存储到AnnotationGroup结构中,AnnotationGroup结构定义如下:
// Group of annotations for a particular label.
message AnnotationGroup {optional int32 group_label = 1;repeated Annotation annotation = 2;
}
  • AnnotationGroup结构包含group_label和Annotation结构,group_label根据$CAFFE_ROOT/data/VOC0712/labelmap_voc.prototxt进行转换,将object的name改为数字,Annotation结构定义如下:
// Annotation for each object instance.
message Annotation {optional int32 instance_id = 1 [default = 0];optional NormalizedBBox bbox = 2;
}
  • Annotation结构包含instance_id和NormalizedBBox结构,NormalizedBBox即为XML文件每个object里面bbox的四个坐标点(xmin,ymin,xmax,ymax)。

  这样XML文件的内容就存到了AnnotatedDatum结构里面。
  (以上结构的定义文件都存储在$CAFFE_ROOT/src/caffe/proto/caffe.proto中)


三、Datum数据结构

 AnnotatedDatum类里面包括Datum结构,用来存放图片数据。

  • Datum的定义:
message Datum {optional int32 channels = 1;optional int32 height = 2;optional int32 width = 3;// the actual image data, in bytesoptional bytes data = 4;optional int32 label = 5;// Optionally, the datum could also hold float data.repeated float float_data = 6;// If true data contains an encoded image that need to be decodedoptional bool encoded = 7 [default = false];
}

    channels、height和width为Datum数据的三个维度。byte_data和float_data是存放数据的地方,分别存放整数型和浮点型数据。图像数据一般是整形,放在byte_data里,特征向量一般是浮点型,放在float_data里。label存放数据的类别标签,是整数型。encoded标识数据是否需要被解码(里面有可能放的是JPEG或者PNG之类经过编码的数据)。

  • 使用$CAFFE_ROOT/src/caffe/util/io.cpp里面定义的ReadImageToDatum函数将图片数据存储到Datum结构中。先用OpenCV将图片读取为矩阵形式,获取图片的三维数据,将这些数据存储到Datum结构中。相关代码如下:
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;}
}

四、Python读取LMDB

 为了加深理解,我用python写了一个读取LMDB数据的脚本,将存储在LMDB中的AnnotatedDatum结构中的图片和XML文件读取出来,获取object的name即label,并将图片用OpenCV显示,代码如下:

# -*- coding: utf-8 -*
import caffe
import lmdb
import numpy as np
import cv2
from caffe.proto import caffe_pb2lmdb_env = lmdb.open('/home/computer/wcaffe_test/examples/VOC0712/VOC0712_test_lmdb')lmdb_txn = lmdb_env.begin()                                 # 生成处理句柄
lmdb_cursor = lmdb_txn.cursor()                             # 生成迭代器指针
annotated_datum = caffe_pb2.AnnotatedDatum()                # AnnotatedDatum结构for key, value in lmdb_cursor:print keyannotated_datum.ParseFromString(value)datum = annotated_datum.datum                           # Datum结构grps = annotated_datum.annotation_group                 # AnnotationGroup结构type = annotated_datum.typefor grp in grps:xmin = grp.annotation[0].bbox.xmin * datum.width           # Annotation结构ymin = grp.annotation[0].bbox.ymin * datum.heightxmax = grp.annotation[0].bbox.xmax * datum.widthymax = grp.annotation[0].bbox.ymax * datum.heightprint "label:", grp.group_label                            # object的name标签print "bbox:", xmin, ymin, xmax, ymax                      # object的bbox标签label = datum.label                                      # Datum结构label以及三个维度   channels = datum.channelsheight = datum.heightwidth = datum.widthprint "label:", labelprint "channels:", channelsprint "height:", heightprint "width:", widthimage_x = np.fromstring(datum.data, dtype=np.uint8)      # 字符串转换为矩阵image = cv2.imdecode(image_x, -1)                        # decodecv2.imshow("image", image)                               # 显示图片if cv2.waitKey(1) & 0xFF == ord('q'):break

这篇关于SSD目标检测lmdb数据结构剖析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/918960

相关文章

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

烟火目标检测数据集 7800张 烟火检测 带标注 voc yolo

一个包含7800张带标注图像的数据集,专门用于烟火目标检测,是一个非常有价值的资源,尤其对于那些致力于公共安全、事件管理和烟花表演监控等领域的人士而言。下面是对此数据集的一个详细介绍: 数据集名称:烟火目标检测数据集 数据集规模: 图片数量:7800张类别:主要包含烟火类目标,可能还包括其他相关类别,如烟火发射装置、背景等。格式:图像文件通常为JPEG或PNG格式;标注文件可能为X

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

基于 YOLOv5 的积水检测系统:打造高效智能的智慧城市应用

在城市发展中,积水问题日益严重,特别是在大雨过后,积水往往会影响交通甚至威胁人们的安全。通过现代计算机视觉技术,我们能够智能化地检测和识别积水区域,减少潜在危险。本文将介绍如何使用 YOLOv5 和 PyQt5 搭建一个积水检测系统,结合深度学习和直观的图形界面,为用户提供高效的解决方案。 源码地址: PyQt5+YoloV5 实现积水检测系统 预览: 项目背景

JavaFX应用更新检测功能(在线自动更新方案)

JavaFX开发的桌面应用属于C端,一般来说需要版本检测和自动更新功能,这里记录一下一种版本检测和自动更新的方法。 1. 整体方案 JavaFX.应用版本检测、自动更新主要涉及一下步骤: 读取本地应用版本拉取远程版本并比较两个版本如果需要升级,那么拉取更新历史弹出升级控制窗口用户选择升级时,拉取升级包解压,重启应用用户选择忽略时,本地版本标志为忽略版本用户选择取消时,隐藏升级控制窗口 2.

《数据结构(C语言版)第二版》第八章-排序(8.3-交换排序、8.4-选择排序)

8.3 交换排序 8.3.1 冒泡排序 【算法特点】 (1) 稳定排序。 (2) 可用于链式存储结构。 (3) 移动记录次数较多,算法平均时间性能比直接插入排序差。当初始记录无序,n较大时, 此算法不宜采用。 #include <stdio.h>#include <stdlib.h>#define MAXSIZE 26typedef int KeyType;typedef char In

【408数据结构】散列 (哈希)知识点集合复习考点题目

苏泽  “弃工从研”的路上很孤独,于是我记下了些许笔记相伴,希望能够帮助到大家    知识点 1. 散列查找 散列查找是一种高效的查找方法,它通过散列函数将关键字映射到数组的一个位置,从而实现快速查找。这种方法的时间复杂度平均为(

[数据集][目标检测]血细胞检测数据集VOC+YOLO格式2757张4类别

数据集格式:Pascal VOC格式+YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2757 标注数量(xml文件个数):2757 标注数量(txt文件个数):2757 标注类别数:4 标注类别名称:["Platelets","RBC","WBC","sickle cell"] 每个类别标注的框数:

浙大数据结构:树的定义与操作

四种遍历 #include<iostream>#include<queue>using namespace std;typedef struct treenode *BinTree;typedef BinTree position;typedef int ElementType;struct treenode{ElementType data;BinTree left;BinTre