参考文献依然是放前面:https://blog.csdn.net/caicaiatnbu/category_9096319.html
darknet版本: https://github.com/AlexeyAB/darknet,与原始的版本还是有一点区别的。
进入代码:
1.option_list.h:定义了一个结构体和11个函数
#ifndef OPTION_LIST_H
#define OPTION_LIST_H
#include "darknet.h"
#include "list.h"//解析一中的list.h文件
typedef struct{
char *key;
char *val;
int used;
} kvp;//定义了一个结构体kvp,包含了两个char型指针,一个int型指针
#ifdef __cplusplus
extern "C" {
#endif
list *read_data_cfg(char *filename);
int read_option(char *s, list *options);
void option_insert(list *l, char *key, char *val);
char *option_find(list *l, char *key);
char *option_find_str(list *l, char *key, char *def);
char *option_find_str_quiet(list *l, char *key, char *def);
int option_find_int(list *l, char *key, int def);
int option_find_int_quiet(list *l, char *key, int def);
float option_find_float(list *l, char *key, float def);
float option_find_float_quiet(list *l, char *key, float def);
void option_unused(list *l);
//typedef struct {
// int classes;
// char **names;
//} metadata;
//LIB_API metadata get_metadata(char *file);
#ifdef __cplusplus
}
#endif
#endif
2. option_list.c
整体操作就是对.data和.cfg文件做读取。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "option_list.h"
#include "utils.h"
#include "data.h"//新的头文件,先放一边,有需要去查看
//读文件,主要是.data和.cfg文件
list *read_data_cfg(char *filename)
{
FILE *file = fopen(filename, "r");//打开文件
if(file == 0) file_error(filename);
char *line;
int nu = 0;
list *options = make_list();//list.h中的初始化链表
while((line=fgetl(file)) != 0){//读取文件中的一行数据
++nu;
strip(line);//过滤掉字符数组中的' ' 和 '\t' 以及 '\n' 三种字符
switch(line[0]){
case '\0':
case '#':
case ';':
free(line);
break;
//以上代码段,是跳过那些没有有效信息的数据行
//下面是对有效信息做处理
default:
//读数据,并且将有效的复制信息放入链表中
if(!read_option(line, options)){
//如果没有有效信息,输出提示
fprintf(stderr, "Config file error line %d, could parse: %s\n", nu, line);
free(line);
}
break;
}
}
fclose(file);
return options;//返回数据信息
}
/*
metadata 是元数据,关于数据的数据或者叫做用来描述数据的数据或者叫做信息的信息。
比如,有一条学生信息记录,其中包括字段姓名(name)、年龄(age)、性别(male)、班级(class)等,那么name、age、male、class就是元数据。通过它们的描述,一条关于学生信息的数据记录就产生;
这里是读取.data文件,构建数据的相关元数据,比如名称,标签等
*/
metadata get_metadata(char *file)
{
metadata m = { 0 };
list *options = read_data_cfg(file);//获得有效的赋值信息
//data文件中names = data/bicycle.names
char *name_list = option_find_str(options, "names", 0);//找到key=="name"的对应值
if (!name_list) name_list = option_find_str(options, "labels", 0);//找到key=="labels"的对应值
if (!name_list) {
fprintf(stderr, "No names or labels found\n");
}//如果找不到信息,就报错提醒
else {
m.names = get_labels(name_list);
}//找到信息就放到元数据中
//data文件中classes= 21,获得类别数,放入元数据
m.classes = option_find_int(options, "classes", 2);
free_list(options);//释放临时空间
if(name_list) {
printf("Loaded - names_list: %s, classes = %d \n", name_list, m.classes);
}//输出读取的信息
return m;
}
//读取某一字符数组,若满足条件,插入到链表options中
int read_option(char *s, list *options)//read_data_cfg中用到的函数
{
size_t i;
size_t len = strlen(s);//字符串长度,做循环
char *val = 0;
for(i = 0; i < len; ++i){
if(s[i] == '='){//遇到等于号,就是data和cfg文件中的赋值语句
s[i] = '\0';//以等于号为分割线
val = s+i+1;//val为等于号右边的字符串
break;
}
}
if(i == len-1) return 0;//如果循环到最后也没有赋值信息,就返回0
char *key = s;//key为等于号左边的字符串
option_insert(options, key, val);//利用函数将内容插入到链表中
return 1;
}
//字符串的插入操作
void option_insert(list *l, char *key, char *val)
{
kvp* p = (kvp*)xmalloc(sizeof(kvp));//临时存储空间
p->key = key;
p->val = val;
p->used = 0;//值以结构体kvp的形式存放
list_insert(l, p);//list.c中的链表插入
}
// 链表遍历操作,打印kvp结构体标志位used 为0的数据,
void option_unused(list *l)
{
node *n = l->front;
while(n){
kvp *p = (kvp *)n->val;
if(!p->used){
fprintf(stderr, "Unused field: '%s = %s'\n", p->key, p->val);
}
n = n->next;
}
}
// 查找操作,获取指定key的val,没找到返回null.
char *option_find(list *l, char *key)
{
node *n = l->front;
while(n){//循环链表
// 需要注意结构体node的定义,val是 void类型指针,需要强制转换
kvp *p = (kvp *)n->val;//取链表值,刚刚read_options中存储的有效赋值信息
if(strcmp(p->key, key) == 0){//如果存储的key与需要的key相等
p->used = 1;//将标识符置1
return p->val;返回查找出来的值
}
n = n->next;
}
return 0;
}
// 查找操作,key为字符数组
char *option_find_str(list *l, char *key, char *def)
{
char *v = option_find(l, key);//查找key相应的值
if(v) return v;//如果找到了返回值
if(def) fprintf(stderr, "%s: Using default '%s'\n", key, def);//没找到输出信息提示
return def;
}
查找操作,key为字符数组,并且不给输出提醒
char *option_find_str_quiet(list *l, char *key, char *def)
{
char *v = option_find(l, key);
if (v) return v;
return def;
}
// 查找操作,key为可显示转换int类型字符数组
int option_find_int(list *l, char *key, int def)
{
char *v = option_find(l, key);
if(v) return atoi(v);
fprintf(stderr, "%s: Using default '%d'\n", key, def);
return def;
}
// 查找操作,key为可显示转换int类型字符数组,并且不给输出提醒
int option_find_int_quiet(list *l, char *key, int def)
{
char *v = option_find(l, key);
if(v) return atoi(v);
return def;
}
// 查找操作,key为可显示转换float类型字符数组,并且不给输出提醒
float option_find_float_quiet(list *l, char *key, float def)
{
char *v = option_find(l, key);
if(v) return atof(v);
return def;
}
// 查找操作,key为可显示转换float类型字符数组
float option_find_float(list *l, char *key, float def)
{
char *v = option_find(l, key);
if(v) return atof(v);
fprintf(stderr, "%s: Using default '%lf'\n", key, def);
return def;
}