faster rcnn:assert (boxes[:, 2] >= boxes[:, 0]).all()分析塈VOC2007 xml坐标定义理解

在进行faster rcnn训练的时候,报了一个断言错误

File “/py-faster-rcnn/tools/../lib/datasets/imdb.py”, line 108, in append_flipped_images assert (boxes[:, 2] >= boxes[:, 0]).all() AssertionError

参照这篇文章,找到了问题的原因,是矩形标注的问题: 《解决faster-rcnn中训练时assert(boxes[:,2]>=boxes[:,0]).all()的问题》

解决问题的办法

这篇博客 《解决faster-rcnn中训练时assert(boxes[:,2]>=boxes[:,0]).all()的问题》 中对于问题的发生的原因说得比较明白,但对于决问题提出的办法却未必可取,文中提供了三个方法,对于方法2,3不做讨论,这取决于自己的实际需要。但方法1我认为却是不可取的,以下截图是方法1的说明:

意思就是当x2<x1时,直接将x1置为0

附append_flipped_images代码

    def append_flipped_images(self):
        num_images = self.num_images
        widths = self._get_widths()
        for i in xrange(num_images):
            boxes = self.roidb[i]['boxes'].copy()
            oldx1 = boxes[:, 0].copy()
            oldx2 = boxes[:, 2].copy()
            boxes[:, 0] = widths[i] - oldx2 - 1
            boxes[:, 2] = widths[i] - oldx1 - 1
            assert (boxes[:, 2] >= boxes[:, 0]).all()
            entry = {'boxes' : boxes,
                     'gt_overlaps' : self.roidb[i]['gt_overlaps'],
                     'gt_classes' : self.roidb[i]['gt_classes'],
                     'flipped' : True}
            self.roidb.append(entry)
        self._image_index = self._image_index * 2

这个办法很粗暴,相当于修改了标注矩形的尺寸和位置, 纯粹是为了消除Asser错误而写的,治标不治本。 就我个人而言,我没有采用文中的任何办法, 我的原则是非万不得已,尽量不修改第三方的代码,因为我的数据集xml文件是我自己用java写的工具生成的,所以我修改了我生成xml文件的代码,标注矩形的坐标按VOC2007的要求写是1-based的就能解决这个问题。 在解决这个问题的过程中也搞清楚了,VOC2007 xml标注格式中矩形坐标的定义方式。

0-based

如上文所说,通过py-faster-rcnn/lib/datasets/pascal_voc.py的_load_pascal_annotation函数中,下面这段代码,可以知道,VOC2007 的矩形标注坐标是以1为基准的(1-based),而我们在处理图像坐标都是0起始的(0-based)。 所以在这里才要对从xml文件中读取的xmin,ymin,xmax,ymax 统统减1将坐标变为我们做数据处理时所需要的0-based坐标。

# py-faster-rcnn/lib/datasets/pascal_voc.py (line 207)
            # Make pixel indexes 0-based
            x1 = float(bbox.find('xmin').text) - 1
            y1 = float(bbox.find('ymin').text) - 1
            x2 = float(bbox.find('xmax').text) - 1
            y2 = float(bbox.find('ymax').text) - 1
            cls = self._class_to_ind[obj.find('name').text.lower().strip()]
            boxes[ix, :] = [x1, y1, x2, y2]
            gt_classes[ix] = cls
            overlaps[ix, cls] = 1.0
            seg_areas[ix] = (x2 - x1 + 1) * (y2 - y1 + 1)

xmin,ymin,xmax,ymax的含义

对于一个矩形(x,y,w,h)定义,xmin,ymin,xmax,ymax的准确含义是什么呢?, xmin,ymin一看就明白,我们理解它为矩形的左上角坐标(x,y),那么xmax,ymax是什么呢? 根据上面的python代码最后一行,就可以推断应该是:

xmax=x+w-1,ymax=y+h-1

之前一直被java.swt.RectangularShape中的getMaxX(),getMaxY()方法误导,少减了1: 以下是java.swt.RectangularShape中getMaxX()方法的实现代码

    public double getMaxX() {
        return getX() + getWidth();
    }

因为这个想当然的错误理解,只是少减了个1,在做训练数据集的时候走了一些弯路:当标注矩形的边与图像的边缘重合的时候,也会产生标题中的Assert断言错误。 所以生成xml时,矩形坐标的计算应该如下java代码:

// dom4j生成annotation xml的java代码片段(AnnRect为java.swt.Rectangle的子类)
    /**
     * 生成矩形描述对象,矩形坐标为1-base
     * @param rect
     * @return
     */
    private Element toElement(AnnRect rect) {
        Element obj = DocumentHelper.createElement("object");
        obj.addElement("name").addText(IadbHandler.iadb.getAnnNames().get(rect.annID));
        obj.addElement("pose").addText("Unspecified");
        obj.addElement("truncated").addText("0");
        obj.addElement("difficult").addText("0");
        // 生成以1为基准的矩形坐标(1-based)
        appendChildNodes(obj.addElement("bndbox"),
                createNode("xmin", rect.x + 1), 
                createNode("ymin", rect.y + 1), 
                createNode("xmax", rect.x + rect.width),
                createNode("ymax", rect.y + rect.height)
        );
        return obj;
    }

对caffe这样的深度学习模型,训练数据的矩形尺寸相差一个像素,有影响吗? 这个很难说,但我知道我的训练数据中有不少矩形是24x24的,对于这么小的矩形,尺寸相差一个像素,就可能损失了4%的信息量。 出于对训练数据质量的要求,我还是要讲究一下。

矩形越界

如果你已经注意到了上面的这个问题,已经将你的标注xml中的坐标统一为1-based坐标了,但在执行训练的时候还是会有上面的Assert错误,那么就要好好检查你的标注数据中,是不是有超出图像范围的矩形。如果有,一定要修正。

训练缓存清空

如果你确定没有越界的矩形却还是会报这个Assert错误,那么有可能是缓冲区中的数据乱了。 把py-faster-rcnn/data/cache中的文件和 py-faster-rcnn/data/VOCdevkit2007/annotations_cache中的文件统统删除(如果有的话),再来试试吧。我就因为这个问题被折腾了一天。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏专知

【干货】计算机视觉实战系列03——用Python做图像处理

【导读】专知成员Hui上一次为大家介绍Matplotlib的使用,包括绘图,绘制点和线,以及图像的轮廓和直方图,这一次为大家详细讲解Numpy工具包中的各种工具...

41510
来自专栏数据结构与算法

洛谷P1887 乘积最大3

题目描述 请你找出M个和为N的正整数,他们的乘积要尽可能的大。 输出字典序最小的一种方案。 输入输出格式 输入格式: 一行,两个正整数N,M 输出格式: M个...

3348
来自专栏数据结构与算法

07:矩阵归零消减序列和

07:矩阵归零消减序列和 总时间限制: 1000ms 内存限制: 65536kB描述 给定一个n*n的矩阵(3 <= n <= 100,元素的值都是非负整数...

3656
来自专栏前端儿

比较字母大小

任意给出两个英文字母,比较它们的大小,规定26个英文字母A,B,C.....Z依次从大到小。

630
来自专栏尾尾部落

[剑指offer] 数值的整数次方 [剑指offer] 数值的整数次方

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

653
来自专栏来自地球男人的部落格

浅谈Attention-based Model【源码篇】

源码不可能每一条都详尽解释,主要在一些关键步骤上加了一些注释和少许个人理解,如有不足之处,请予指正。 计划分为三个部分: 浅谈Attention-bas...

28110
来自专栏武培轩的专栏

迅雷2019秋招后台开发编程题题解

有红黑两种颜色的方块积木,红色代表正数A,黑色代表负数B。选出17块积木排成一排,使得任意相邻7块积木之和都小于0。如何挑选才能使17块积木之和最大,最大值是多...

1242
来自专栏机器学习和数学

[编程经验] Tensorflow中的共享变量机制小结

今天说一下tensorflow的变量共享机制,首先为什么会有变量共享机制? 这个还是要扯一下生成对抗网络GAN,我们知道GAN由两个网络组成,一个是生成器网络G...

7603
来自专栏祥子的故事

python | pandas | 移动窗口函数rolling

6155
来自专栏desperate633

LintCode 寻找缺失的数题目分析方法二 交换法

给出一个包含 0 .. N 中 N 个数的序列,找出0 .. N 中没有出现在序列中的那个数。

733

扫码关注云+社区