yolov3 批量处理图片获得检测框坐标

前言

yolov3实现检测,需要所有检测框的坐标实现定位。

在darknet-master项目下实现检测框坐标的获取

前提

系统:Windows
语言:C
项目:darknet-master
开发环境:VS 2019
脚本执行:Git

首先,我们要熟悉几个函数,这样可以更好地理解修改代码的原理
示例:

FILE* box_coordinate = fopen(output, "a+");
fprintf(box_coordinate, "Class:%s, Box: %d %d %d %d\n", names[class], left, right, top, bot);
fclose(box_coordinate);

解析:
FILE这个结构包含了文件操作的基本属性,对文件的操作都要通过这个结构的指针来进行,此种文件操作常用的函数见下表 函数 功能:
fopen() 打开流
fclose() 关闭流
fprintf() 按格式输出到流

1.fopen() fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen实现三个功能

为使用而打开一个流 把一个文件和此流相连接 给此流返回一个FILR指针
参数filename指向要打开的文件名,mode表示打开状态的字符串。

2.fclose() fclose()的功能就是关闭用fopen()打开的文件,其原型是:int fclose(FILE *fp);如果成功,返回0,失败返回EOF。

3.fprintf() 按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, …]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了。

一、找到函数

我们需要找到源码中画框的函数,这个函数中包含left, right, top, bot坐标信息,我们需要获取这些信息并写入到文本文件中。考虑到原函数有被多次调用,我们选择重构一个新的函数。进行画框的函数在darknet.sln里的image.c中,函数为draw_detections_v3。

我们真正需要修改的文件只有detector.c,image.c,image.h这三个文件。
在这里插入图片描述

二、重构函数

重构函数加入到image.c文件中,这里主要参考了文章1
因为要获取所有检测框坐标,所以对代码进行了如下修改。可以放心复制粘贴。

void draw_detections_in_txt(image im, char* filename, detection* dets, int num, float thresh, char** names, image** alphabet, int classes)
{
    int i, j;

    char* output = filename;
    //output = strcat(output, ".txt");
    //output = strcat("./", output); 
    //printf("PATH:%s", output); 
    int namecount = 0;
    for (namecount = strlen(filename) - 1; namecount >= 0; namecount--)
    {
        if ((filename[namecount] != 'j') && (filename[namecount] != 'p') && (filename[namecount] != 'g') && (filename[namecount] != '.'))
        {
            break;
        }
        else {
            output[namecount] = '\0';
        }
    }
    output = strcat(filename, ".txt");//将文件价里的.JPG文件名替换成.txt
    FILE* box_coordinate = fopen(output, "w+"); //在循环前打开流

    for (i = 0; i < num; ++i) {
        char labelstr[4096] = { 0 };
        int class = -1;
        for (j = 0; j < classes; ++j) {
            if (dets[i].prob[j] > thresh) {
                if (class < 0) {
                    strcat(labelstr, names[j]);
                    class = j;
                }
                else {
                    strcat(labelstr, ", ");
                    strcat(labelstr, names[j]);
                }
                printf("%s: %.0f%%\n", names[j], dets[i].prob[j] * 100);
            }
        }
        if (class >= 0) {
            int width = im.h * .006;

            /*
               if(0){
               width = pow(prob, 1./2.)*10+1;
               alphabet = 0;
               }
             */

             //printf("%d %s: %.0f%%\n", i, names[class], prob*100);
            int offset = class * 123457 % classes;
            float red = get_color(2, offset, classes);
            float green = get_color(1, offset, classes);
            float blue = get_color(0, offset, classes);
            float rgb[3];

            //width = prob*20+2;

            rgb[0] = red;
            rgb[1] = green;
            rgb[2] = blue;
            box b = dets[i].bbox;
            //printf("%f %f %f %f\n", b.x, b.y, b.w, b.h);

            int left = (b.x - b.w / 2.) * im.w;
            int right = (b.x + b.w / 2.) * im.w;
            int top = (b.y - b.h / 2.) * im.h;
            int bot = (b.y + b.h / 2.) * im.h;

            if (left < 0) left = 0;
            if (right > im.w - 1) right = im.w - 1;
            if (top < 0) top = 0;
            if (bot > im.h - 1) bot = im.h - 1;
            ///JiaXuejian asdded//
                //printf("%d %d %d %d\n", left, right, top, bot);
            ///

            //JiaXuejian added
            //FILE* fp;
            //if ((fp = fopen(output, "w+")) == NULL) {
            //    printf("wrong:\n");
            //}
            fprintf(box_coordinate, "Class:%s, Box: %d %d %d %d\n", names[class], left, right, top, bot);// 循环里将框坐标写入文件//"左部边框的位置:%d 顶部边框的位置:%d 右部边框的位置:%d 底部边框的位置:%d\n"
            ///

            draw_box_width(im, left, top, right, bot, width, red, green, blue);
            if (alphabet) {
                image label = get_label(alphabet, labelstr, (im.h * .03));
                draw_label(im, top + width, left, label, rgb);
                free_image(label);
            }
            if (dets[i].mask) {
                image mask = float_to_image(14, 14, 1, dets[i].mask);
                image resized_mask = resize_image(mask, b.w * im.w, b.h * im.h);
                image tmask = threshold_image(resized_mask, .5);
                embed_image(tmask, im, left, top);
                free_image(mask);
                free_image(resized_mask);
                free_image(tmask);
            }
            ///JiaXuejian added//
        // printf("%s:", label)
            printf("%d %d %d %d\n", left, right, top, bot);

        }
    }
    fclose(box_coordinate);//关闭流
}

由于是C代码,所以需要在头文件中声明一下新增的函数,darknet-master中大部分的函数声明在image.h 文件中,打开该文件,在34行可以看到 draw_detections 的函数声明,所以我们要输入以下代码:

void draw_detections_in_txt(image im, char* filename, detection* dets, int num, float thresh, char** names, image** alphabet, int classes);

三、引用

我们需要找到引用draw_detections的地方,在detector.c中1690行,将其注释,增加新的重构函数的引用。

draw_detections_in_txt(im, input, dets, nboxes, thresh, names, alphabet, l.classes);

四、创建脚本文件

这里主要参考了文章2
在任意位置创建文本文件,另存为任意格式,文件名的后缀为.sh
打开git-bash
cd到脚本文件的路径下,执行以下命令

chmod +x script.sh
./script.sh

您可以将chmod更改为所需的可执行权限。

注意:chmod只需运行一次。如果要运行脚本,请运行./script.sh。script.sh为脚本文件的名字。

#在文件中写入
#! /bin/bash
sum=0
save_path="D:/darknet-master/build/darknet/x64/results_str/" #保存的地址
for file in D:/darknet-master/build/darknet/VOCdevkit2021/VOC2021/JPEGImages/*.jpg #图片所在的地址
do
    if test -f $file
    then
        let sum += 1
        #echo $file if file
        name=${file%.*}  #去掉.jpg的后缀
        #echo $name
        txtname=$name.txt #加上.txt的后缀
        #echo $txtname
        onlyname=${name##*/} #图片的名字a.jpg
        #echo $onlyname
        savename=$save_path$onlyname #图片保存的路径和名字
        #echo $savename
        ./darknet detect -i 0 yolov3-voc.cfg results_mine/yolov3-voc_last.weights $file -out $savename  #运行检测代码
        mv $txtname $save_path 
    fi
echo sum=$sum
done

五、成功截图

在这里插入图片描述

在这里插入图片描述

参考:

文章1
文章2


补充:

坐标是按照MFC:pic控件的矩形的left、right、top、bottom 坐标位置
left,top为左上角的点坐标

right,bottom为右下角的点坐标

转换一下为opencv常用的:

x=left

y=top

width=right-left

height=bottom-top

参考:

文章3

  • 1
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值