【代码阅读】darknet源码阅读(三):option_list.h 和 option_list.c

参考文献依然是放前面:https://blog.youkuaiyun.com/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;
}

 

### YOLO算法的C语言实现概述 YOLO(You Only Look Once)作为一种高效的目标检测算法,虽然通常由Python深度学习框架如TensorFlow或PyTorch实现,但也存在一些基于C语言的实现方式。这些实现主要用于嵌入式系统或其他资源受限环境下的目标检测任务[^1]。 一种常见的做法是借助开源项目Darknet,这是一个用纯C语言编写的轻量级神经网络框架,支持YOLO模型的训练与推理过程。Darknet不仅提供了完整的源码结构,还包含了详细的文档说明以及预训练好的权重文件下载链接。 以下是关于如何获取并使用Darknet进行YOLO开发的相关指导: --- ### Darknet中的YOLO实现 #### 安装步骤 要开始使用Darknet实现YOLO,请按照以下指南准备环境: 1. **克隆仓库**: 首先从GitHub上拉取最新的Darknet代码库。 ```bash git clone https://github.com/pjreddie/darknet.git cd darknet ``` 2. **编译程序**: 根据操作系统选择合适的Makefile配置选项后运行make命令完成编译工作。 ```bash make ``` 3. **下载预训练模型**: 如果不需要自己训练新模型的话可以直接下载官方提供的各种版本YOLO预训练权值。 ```bash wget https://pjreddie.com/media/files/yolov3.weights ``` #### 推理流程 当一切就绪之后就可以尝试加载测试图片执行简单的物体识别功能了。下面给出一段基础示例脚本展示具体调用形式: ```c #include "darknet.h" int main(int argc, char *argv[]) { list *options = read_data_cfg("cfg/coco.data"); char *name_list = option_find_str(options, "names", "data/names.list"); network net; load_network(&net, "cfg/yolov3.cfg", "yolov3.weights", 0); image im = load_image_color("dog.jpg", 0, 0); layer l = net.layers[net.n - 1]; float nms = .4; // Non-maximum suppression threshold. detection *dets = get_network_detections(net, im.w, im.h, l.classes, &nms); printf("\nDetections:\n\n"); print_detections(dets, l
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值