YOLOV3实战6:显示中文标签(YOLOV3中文标签)

一、番外说明

大家好,我是小P,今天在此给大家分享一下基于DarknetAB版本的YOLOV3如何生成和显示中文标签的方法,效果如下图所示,希望大家支持和喜欢。此外,对“目标检测/模型压缩/语义分割”感兴趣的小伙伴,欢迎加入QQ群 813221712 讨论交流,进群请看群公告!(可以点击如下连接直接加入!)
点击链接加入群聊【Object Detection】:https://jq.qq.com/?_wv=1027&k=5kXCXF8
在这里插入图片描述

二、资源下载

首先,本次教程所使用的模型为DarknetAB版本,其相对于官方原版作出了比较多的修改,最大的便利在于能方便地在Win10操作系统上运行,有兴趣地小伙伴可以研究研究,下载地址为:
https://github.com/AlexeyAB/darknet 在此,强烈推荐大家使用AB版本

三、详细操作

第一步:生成对应的标签图片

在此之前,先普及一点源码画标签的知识。假如,现在要往检测图片的某一位置绘制标签Person,则程序操作流程为:

首先,根据检测框的大小确定标签显示的大小(源码中为一组公式)
然后,根据标签中的字母拼接最终标签图,以Person为例讲解

在这里插入图片描述
如上图所示,源码的 darknet-master/data/labels 路径(有两个labels文件夹,Win10环境使用图中所示的labels文件夹,Ubuntu使用 darknet-master/data/labels 文件夹)下有对应大小不同的字母图片,其命名规则为:ASCII_大小 ,其中ASCII表示字母对应的ASCII值,这样处理是为了计算方便,大小是根据检测框大小计算得到的,假定现在Person标签的大小为5号,则程序会将Person标签分解为6个字母:‘P’ ‘e’ ‘r’ ‘s’ ‘o’ ‘n’ ,首先找到‘P’字母的5号图片,然后找到‘e’字母的5号图片将其拼接在’P’字母的右边…其它字母类似,如下图所示:
在这里插入图片描述

最后,将生成的标签图片覆盖到检测图片的正确位置,注意是覆盖,即像素值取代

?是不是很艰辛!明白了画标签的原理,要改就简单多了。现在,来生成中文标签所需的图片,这儿与原代码不同的是中文标签基于词语生成图片,如“行人”,则不拆分成“行”和“人”,主要是因为字母可以根据ASCII简便计算,但中文不行,当然,你也可以拆开来做,只是稍微复杂点,但这儿为了简单起见,就不拆开。生成标签的图片代码如下:

import os
import string
import pipes

font = 'futura-normal'
fileName=open("my.names",'r')
l=[label.lstrip().rstrip() for label in fileName.readlines()]

for i in range(8):
    index=0
    for word in l:
        os.system(
"convert -fill black -background white -bordercolor white -border 4  -font /usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf -pointsize %d label:\"%s\" \"%d_%s.png\"" % ((i+1)*12, word, i,index))
        index+=1

警告:本段代码只能在Ubuntu操作系统下运行,没有Ubuntu的小伙伴可以让别人替你生成好后拷贝过来
注意:你只需要将此段代码粘贴进任何一个.py文件,放到labels文件夹下面,在该文件夹下面运行即可。此外:你需要修改代码中的“my.names”为你的标签文件,运行的结果是:在labels文件夹下面生成了一系列标签图片,如下图所示(请确认你的结果正确):
在这里插入图片描述
此处:第一个数字表示大小,分为8个等级,0-7表示,第二个数字表示标签编号,和**.names文件对应。

第二步:修改部分代码
Step1 修改 src/image.c 中的部分代码

查找 get_label_v3函数的声明处,在其下面添加函数 get_label_v3_my ,采用添加不采用修改的方式主要是避免破坏源码,其它地方的修改类似,函数代码为:

image get_label_v3_my(image **characters, char *labelindex, int size)
{
    size = size / 10;
    if (size > 7) size = 7;
    image label = make_empty_image(0, 0, 0);
    int class,i=0,nlabels=1;
    int len=strlen(labelindex);
    for(i=0;i<len;i++)
    {
        if(labelindex[i]==',') ++nlabels;
    }
    for(i=0;i<nlabels;i++){
        class=atoi(labelindex);
        image l = characters[size][class];
        image n = tile_images(label, l, -size - 1 + (size + 1) / 2);
        free_image(label);
        label = n;
        labelindex=strchr(labelindex,',')+1;
    }
    image b = border_image(label, label.h*.25);
    free_image(label);
    return b;
}

添加代码过后,你的文件应该如下图所示,其中具体意义这里不进行讲解,感兴趣的小伙伴自行研究和修改
在这里插入图片描述

step2 修改对get_label_v3的调用为get_label_v3_my

找到 image.c 中的 draw_detections_v3函数。然后找到 if ( alphabet ) { … } 代码块,将其改为:

            if (alphabet) {
                char labelindex[100]= { 0 };
                char class[10]={0};
                sprintf(class,"%d",selected_detections[i].best_class);
                strcat(labelindex, class);
                int j;
                for (j = 0; j < classes; ++j) {
                    if (selected_detections[i].det.prob[j] > thresh && j != selected_detections[i].best_class) {                      
                        strcat(labelindex,", ");
                        sprintf(class,"%d",selected_detections[i].best_class);
                        strcat(labelindex, class);
                    }
                }
                image label = get_label_v3_my(alphabet, labelindex, (im.h*.03));
                draw_label(im, top + width, left, label, rgb);
                free_image(label);
            }

当然,这儿你也可以新建函数,然后改函数调用,从而避免破坏源码。此处修改是为了调用上面定义的函数

step3 在 image.c文件的 load_alphabet 函数下面添加如下函数:
image **load_labels(int classes)
{
    int i, j;
    const int nsize = 8;
    image** alphabets = (image**)calloc(nsize, sizeof(image*));
    for(j = 0; j < nsize; ++j){
        alphabets[j] = (image*)calloc(classes, sizeof(image));
        for(i = 0; i < classes; ++i){
            char buff[256];
            sprintf(buff, "data/labels/%d_%d.png", j, i);
            alphabets[j][i] = load_image_color(buff, 0, 0);
        }
    }
    return alphabets;
}

本函数的作用为将前面我们生成的标签图片加载进内存,保存在二维结构体数组中

step4 在src/image.h 的 image **load_alphabet();行下面添加下面行:
image **load_labels(int);

此行代码的作用为声明方法。

stpe5 修改 src/detector.c 中的函数调用,使之调用刚才添加的 load_labels

找到 test_detector 函数的定义,将 image **alphabet =load_alphabet(); 修改为:

image **alphabet = load_labels(names_size);
第三步:重新编译,直接回到根目录make即可

到此,教程完毕,其它诸如调节字体大小和框粗细的问题都可以在image.c函数中进行修改。本人对Darknet框架作了精细的研究,并进行了大量的注释,有感兴趣的小伙伴可以一起学习。
在这里插入图片描述

  • 10
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值