利用TinyXML读取VOC2012数据集的XML标注文件裁剪出所有人体目标保存为文件

转载 2016年08月29日 09:51:19

转载自:利用TinyXML读取VOC2012数据集的XML标注文件裁剪出所有人体目标保存为文件 - Why So Serious? - 博客频道 - CSDN.NET  http://blog.csdn.net/masibuaa/article/details/16104717

PASCAL VOC目标检测数据集(The PASCAL Visual Object Classes)

http://pascallin.ecs.soton.ac.uk/challenges/VOC/


图片中的目标用XML文件标注,格式为:

[html] view plain copy
  1. <annotation>  
  2.     <folder>VOC2012</folder>  
  3.     <filename>2007_000346.jpg</filename>  
  4.     <source>  
  5.         <database>The VOC2007 Database</database>  
  6.         <annotation>PASCAL VOC2007</annotation>  
  7.         <image>flickr</image>  
  8.     </source>  
  9.     <size>  
  10.         <width>500</width>  
  11.         <height>375</height>  
  12.         <depth>3</depth>  
  13.     </size>  
  14.     <segmented>1</segmented>  
  15.     <object>  
  16.         <name>bottle</name>  
  17.         <pose>Unspecified</pose>  
  18.         <truncated>0</truncated>  
  19.         <difficult>0</difficult>  
  20.         <bndbox>  
  21.             <xmin>124</xmin>  
  22.             <ymin>107</ymin>  
  23.             <xmax>230</xmax>  
  24.             <ymax>343</ymax>  
  25.         </bndbox>  
  26.     </object>  
  27.     <object>  
  28.         <name>person</name>  
  29.         <pose>Unspecified</pose>  
  30.         <truncated>0</truncated>  
  31.         <difficult>0</difficult>  
  32.         <bndbox>  
  33.             <xmin>137</xmin>  
  34.             <ymin>78</ymin>  
  35.             <xmax>497</xmax>  
  36.             <ymax>375</ymax>  
  37.         </bndbox>  
  38.     </object>  
  39.     <object>  
  40.         <name>person</name>  
  41.         <pose>Unspecified</pose>  
  42.         <truncated>1</truncated>  
  43.         <difficult>0</difficult>  
  44.         <bndbox>  
  45.             <xmin>89</xmin>  
  46.             <ymin>202</ymin>  
  47.             <xmax>129</xmax>  
  48.             <ymax>247</ymax>  
  49.         </bndbox>  
  50.     </object>  
  51.     <object>  
  52.         <name>person</name>  
  53.         <pose>Frontal</pose>  
  54.         <truncated>1</truncated>  
  55.         <difficult>0</difficult>  
  56.         <bndbox>  
  57.             <xmin>72</xmin>  
  58.             <ymin>209</ymin>  
  59.             <xmax>111</xmax>  
  60.             <ymax>259</ymax>  
  61.         </bndbox>  
  62.     </object>  
  63. </annotation>  
对应的图片为:



所以如果想用这个数据集做某种目标识别的训练集的话,需要先从中裁出需要的目标。

下面这个程序就是这个目的,其中用到了TinyXML这个简单易用的XML解析器(XML入门)

[cpp] view plain copy
  1. #include <iostream>  
  2. #include <fstream>  
  3. #include <opencv2/core/core.hpp>  
  4. #include <opencv2/highgui/highgui.hpp>  
  5. #include <opencv2/imgproc/imgproc.hpp>  
  6. #include <opencv2/objdetect/objdetect.hpp>  
  7. #include <opencv2/ml/ml.hpp>  
  8.   
  9. #include <tinyxml.h>  
  10.   
  11. using namespace std;  
  12. using namespace cv;  
  13.   
  14. int CropImageCount=0;//裁剪出来的人体图片个数  
  15.   
  16. /** 
  17. * 通过根节点和节点名查找所有指定节点,结果放到节点数组NodeVector中 
  18. * @param pRootEle xml文件的根节点 
  19. * @param strNodeName 要查询的节点名 
  20. * @param NodeVector 查询到的节点指针数组 
  21. * @return 找到至少一个相应节点,返回true;否则false 
  22. */  
  23. bool GetAllNodePointerByName(TiXmlElement* pRootEle, string strNodeName, vector<TiXmlElement*> &NodeVector)  
  24. {  
  25.     //如果NodeName等于根节点名,加入NodeVector数组  
  26.     if(strNodeName == pRootEle->Value())  
  27.     {  
  28.         NodeVector.push_back(pRootEle);//添加到数组末尾  
  29.         //这里根据VOC Annotation的XML文件格式,认为相同节点名的节点不会有父子关系,所以所有相同节点名的节点都在同一级别上  
  30.         //只要找到第一个,剩下的肯定在它的兄弟节点里面  
  31.         for(TiXmlElement * pElement = pRootEle->NextSiblingElement(); pElement; pElement = pElement->NextSiblingElement())  
  32.             if(strNodeName == pElement->Value())  
  33.                 NodeVector.push_back(pElement);  
  34.         return true;  
  35.     }  
  36.     TiXmlElement * pEle = pRootEle;  
  37.     for(pEle = pRootEle->FirstChildElement(); pEle; pEle = pEle->NextSiblingElement())  
  38.     {  
  39.         //递归处理子节点,获取节点指针  
  40.         if(GetAllNodePointerByName(pEle,strNodeName,NodeVector))  
  41.             return true;  
  42.     }  
  43.     return false;//没找到  
  44. }  
  45.   
  46. /** 
  47. * 根据目标名过滤目标节点数组,删除所有目标名不是objectName的元素 
  48. * @param NodeVector 要操作的TiXmlElement元素指针数组 
  49. * @param objectName 指定的目标名,删除所有目标名不是objectName的元素 
  50. * @return 过滤后目标数组为空,返回false;否则返回true 
  51. */  
  52. bool FiltObject(vector<TiXmlElement*> &NodeVector, string objectName)  
  53. {  
  54.     TiXmlElement * pEle = NULL;  
  55.     vector<TiXmlElement *>::iterator iter = NodeVector.begin();//数组的迭代器  
  56.     for(; iter != NodeVector.end();)  
  57.     {  
  58.         pEle = * iter;//第i个元素  
  59.         //若目标名不是objectName,删除此节点  
  60.         if( objectName != pEle->FirstChildElement()->GetText() )  
  61.         {  
  62.             //cout<<"删除的目标节点:"<<pEle->FirstChildElement()->GetText() <<endl;  
  63.             iter = NodeVector.erase(iter);//删除目标名不是objectName的,返回下一个元素的指针  
  64.         }  
  65.         else  
  66.             iter++;  
  67.     }  
  68.     if( 0 == NodeVector.size())//过滤后目标数组为空,说明不包含指定目标  
  69.         return false;  
  70.     else   
  71.         return true;  
  72. }  
  73.   
  74. /** 
  75. * 根据每个目标的BoundingBox,剪裁图像,保存为文件 
  76. * @param img 图像 
  77. * @param NodeVector 目标节点数组 
  78. */  
  79. void CropImage(Mat img, vector<TiXmlElement*> NodeVector)  
  80. {  
  81.     int xmin,ymin,xmax,ymax;//从目标节点中读出的包围盒参数  
  82.     char fileName[256];//剪裁后的图片和其水平翻转图片的文件名  
  83.   
  84.     //遍历目标数组  
  85.     vector<TiXmlElement *>::iterator iter = NodeVector.begin();//数组的迭代器  
  86.     for(; iter != NodeVector.end(); iter++)  
  87.     {  
  88.         //遍历每个目标的子节点  
  89.         TiXmlElement *pEle = (*iter)->FirstChildElement();//第i个元素的第一个孩子  
  90.         for(; pEle; pEle = pEle->NextSiblingElement())  
  91.         {  
  92.             //找到包围盒"bndbox"节点  
  93.             if(string("bndbox") == pEle->Value())  
  94.             {  
  95.                 TiXmlElement * pCoord= pEle->FirstChildElement();//包围盒的第一个坐标值  
  96.                 //依次遍历包围盒的4个坐标值,放入整型变量中  
  97.                 for(; pCoord; pCoord = pCoord->NextSiblingElement())  
  98.                 {  
  99.                     if(string("xmin") == pCoord->Value())  
  100.                         xmin = atoi(pCoord->GetText());//xmin  
  101.                     if(string("ymin") == pCoord->Value())  
  102.                         ymin = atoi(pCoord->GetText());//ymin  
  103.                     if(string("xmax") == pCoord->Value())  
  104.                         xmax = atoi(pCoord->GetText());//xmax  
  105.                     if(string("ymax") == pCoord->Value())  
  106.                         ymax = atoi(pCoord->GetText());//ymax  
  107.                 }  
  108.                 //cout<<"xmin:"<<xmin<<","<<"ymin:"<<ymin<<","<<"xmax:"<<xmax<<","<<"ymax:"<<ymax<<endl;;  
  109.                 //根据读取的包围盒坐标设置图像ROI  
  110.                 Mat imgROI = img(Rect(xmin,ymin,xmax-xmin,ymax-ymin));  
  111.                 resize(imgROI,imgROI,Size(64,128));//缩放为64*128大小  
  112.                 sprintf(fileName,"person%06d.jpg",++CropImageCount);//生成剪裁图片的文件名  
  113.                 imwrite(fileName,imgROI);//保存文件  
  114.                 flip(imgROI,imgROI,1);//水平翻转  
  115.                 memset(fileName,0x00,sizeof(fileName));  
  116.                 sprintf(fileName,"person%06d.jpg",++CropImageCount);//生成剪裁图片的水平翻转图片的文件名  
  117.                 imwrite(fileName,imgROI);//保存文件  
  118.             }  
  119.         }  
  120.     }  
  121. }  
  122.   
  123. /** 
  124. * 根据XML文件,从图像中剪裁出objectName目标 
  125. * @param XMLFile XML文件名 
  126. * @param img 对应的图像 
  127. * @param objectName 目标名 
  128. * @return 若图像中包含objectName目标,返回true;否则返回false 
  129. */  
  130. bool CropImageAccordingToXML(string XMLFile, Mat img, string objectName)  
  131. {  
  132.     TiXmlDocument * pDoc = new TiXmlDocument();//创建XML文档  
  133.     pDoc->LoadFile(XMLFile.c_str());//装载XML文件  
  134.     vector<TiXmlElement*> nodeVector;//节点数组  
  135.   
  136.     //查找所有节点名是object的节点,即目标节点,结果放到节点数组nodeVector中  
  137.     iffalse == GetAllNodePointerByName(pDoc->RootElement(), "object", nodeVector) )//未找到指定目标  
  138.         return false;  
  139.     //cout<<"所有目标个数:"<<nodeVector.size()<<endl;  
  140.   
  141.     //过滤节点数组,删除所有节点名不是objectName的节点  
  142.     iffalse == FiltObject(nodeVector,objectName) )//目标数组中没有指定目标  
  143.         return false;  
  144.     //cout<<"过滤后的目标个数:"<<nodeVector.size()<<endl;  
  145.   
  146.     //根据每个目标的BoundingBox,剪裁图像,保存为文件  
  147.     CropImage(img,nodeVector);  
  148. }  
  149.   
  150.   
  151. int main()  
  152. {  
  153.     int fileCount=0;//文件个数  
  154.     Mat src;  
  155.     string XMLName,ImgName;//XML文件名和对应的图片文件名  
  156.     //ifstream fin("VOC2012AnnotationsXMLList.txt");//打开XML文件列表  
  157.     ifstream fin("subset.txt");  
  158.     //ifstream fin("test.txt");  
  159.   
  160.     //读取XML文件列表  
  161.     while(getline(fin,XMLName))  
  162.     {  
  163.         cout<<"处理:"<<XMLName<<endl;  
  164.         ImgName = "D:\\DataSet\\VOCtrainval_11-May-2012\\VOCdevkit\\VOC2012\\JPEGImages\\" + XMLName + ".jpg";  
  165.         XMLName = "D:\\DataSet\\VOCtrainval_11-May-2012\\VOCdevkit\\VOC2012\\Annotations\\" + XMLName + ".xml";  
  166.         src = imread(ImgName);  
  167.         CropImageAccordingToXML(XMLName,src,"person");//根据XML标注文档,从图像src中剪裁出所有person目标,保存为文件  
  168.     }  
  169.   
  170.     system("pause");  
  171. }  

源码下载,环境为VS2010 + OpenCV2.4.4 + TinyXML2.6.2

http://download.csdn.net/detail/masikkk/6547823

编译好的TinyXML2.6.2:

http://download.csdn.net/detail/masikkk/6547809


识别MNIST数据集之(一):读取数据

MINIST读数据

TensorFlow学习笔记(二十四)自制TFRecord数据集 读取、显示及代码详解

在跑通了官网的mnist和cifar10数据之后,笔者尝试着制作自己的数据集,并保存,读入,显示。 TensorFlow可以支持cifar10的数据格式, 也提供了标准的TFRecord 格式,而关于...

数据集与标注等工具

~~因为不太会使用OpenCV、matlab工具,所以在找一些比较简单的工具。 . .一、NLP标注工具BRATBRAT是一个基于web的文本标注工具,主要用于对文本的结构化标注,用BRAT生成的...

将fddb标注转换为VOC格式标注

https://github.com/imistyrain/fddb-windows/blob/master/showannotations/fddbannotation.py

python 处理pascal voc数据 读取xml文件

Pascal VOC数据的annotation是xml文件,要利用xml文件里的标注信息裁剪出数据~~

VOC数据提取自己需要的类生成XML标签

公开数据集VOC里面有20类,若小伙伴需要提取特定的类别供深度学习训练的话,可以参考博主的这篇博客,如有不正,欢迎指出。 注意:此python程序经测试VOC2007有效,其他年份的数据只需对程序稍作...
  • samylee
  • samylee
  • 2017年03月13日 16:00
  • 999

VOC各年数据转YOLO格式

为了方便增加YOLO训练数据量,博主将VOC各年数据利用python程序转成了YOLO格式,希望小伙伴可以借鉴一二,如有不正,欢迎指出。 注意:1、可根据需求转成自己的类型,对程序稍作修改即可 ...
  • samylee
  • samylee
  • 2017年03月13日 09:20
  • 970

C++ 读取VOC XML文件

采用C++ 、TinyXML库解析标准VOC XML标记文件

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

RCNN系列实验的PASCAL VOC数据集格式设置

我们在做RCNN系列的实验时,往往需要把数据集的格式设置为和PASCAL VOC数据集一样的格式,其实当然也可以修改读取数据的代码,只是这样更为麻烦,自己的数据格式变了又得修改。 首先以VOC200...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:利用TinyXML读取VOC2012数据集的XML标注文件裁剪出所有人体目标保存为文件
举报原因:
原因补充:

(最多只允许输入30个字)