如何在滑动窗口对象检测中对True Negative进行分类?

时间:2013-04-29 05:15:42

标签: opencv machine-learning computer-vision object-detection

我正在从我的图像检测器算法中收集结果。基本上我所做的是,从一组图像(尺寸为320 x 480)开始,我会通过它运行一个64x128的滑动窗口,并且还可以在一些预定义的比例下运行。

我理解:

  • True Positives =当我检测到的窗口与地面实况(带注释的边界框)重叠(在定义的交叉点大小/质心内)时
  • 误报=当算法给出正面窗口时,它不在真实的事实中。
  • False Negatives =当我没有给出正窗口时,而地面实况注释表明有一个物体。

但是真正否定呢?这些真正的否定因为我的分类器给了我负面结果的所有窗口吗?这听起来很奇怪,因为我一次将一个小窗口(64x128)滑动4个像素,并且我在检测中使用了大约8个不同的比例。如果我这样做,那么每张图片都会有很多真正的底片。

或者我是否准备了一组纯负片图像(根本没有物体/人物),我只是滑过,如果每个图像中有一个或多个正面检测,我会将其视为假阴性,反之亦然?

这是一个示例图像(绿色作为基本事实)

Example image, not real result

6 个答案:

答案 0 :(得分:1)

我总是看到以下四个术语:

  • 假阴性;结果应该是积极的,但是是否定的。
  • 误报;结果应该是否定的,但是是积极的。
  • 真正的积极;结果应该是积极的,并且是积极的。
  • 真正的否定;结果应该是负面的并且是否定的。

在您的情况下,如果我理解正确,您正在尝试检测图像中是否有对象。因此,假阴性意味着存在一个对象(结果应为正)但算法未检测到它(因此返回为负)。真正的否定就是算法正确地说明它检查的区域持有一个对象。

您可以选择忽略负值,但这些可用于进一步训练您的算法(例如;使用查找两者的算法,而不是将未识别的所有内容设置为false)。

答案 1 :(得分:0)

AFAIK,真否定是一种场景,其中图像中存在一个对象,但没有在地面真相注释或模型预测中对其进行标记。

通常,二维物体检测系统仅使用两个数据,即地面真相注释和模型预测。但是,要找到True Negative案例,我们需要寻找地面实况注释的超集,其中包含有关图像中存在的所有类实例的信息(而不仅仅是我们模型中特定的实例)。

例如,拍摄给定的图像;如果我们对出于自动驾驶目的进行对象检测感兴趣,则可以考虑以下两个地面实况注释:

Super Set GT批注

  • 汽车(车辆)
  • 动物
  • house_window
  • 汉堡(可能会扔在路上)

自动驾驶GT注释

  • 汽车(车辆)
  • 动物

有了上述两个地面真相注释,就有可能计算出汉堡和窗户的真否定词。但是,我怀疑是否可以在没有超集注释的情况下计算出真实否定词。

答案 2 :(得分:0)

所有不是fn,fp或tp的矩形都是tn。

因此,真实负片(tn)的数量巨大,但详尽无遗。

上下文:通常,在对象检测中,所有包含tn的度量都将被忽略,因为tn会很多,这使得该度量难以使用。

答案 3 :(得分:0)

真否定词:这是一种背景预测,地面真相没有用于这些位置的框,并且也没有出现在预测中。

假否定词:地面真相有其框,但预测在该位置不包含任何框。

答案 4 :(得分:0)

通常,在对象检测任务中,我们不会寻找真阴性(TN)情况,因为算法告诉我们我们喜欢检测对象(不是非对象候选对象);相反,在分类任务中,我们旨在确定将每个实例视为负面还是正面。因此,自然地,我们将在分类任务中使用True Negative(TN)案例。 此外,还有更好,更兼容的对象检测任务措施。您可以参考平均平均精度(mAP)来评估对象检测算法。 请注意,mAP与简单的平均精度不同。您可以在以下位置找到有关此主题的更多信息: https://medium.com/@jonathan_hui/map-mean-average-precision-for-object-detection-45c121a31173

答案 5 :(得分:-1)

有一个很好的解释here。在维基中解释F1得分,here有助于衡量成功。

enter image description here

我试图编写一个计算F1得分的函数:

    /// <param name="realClasses">Class names that exists on the image. A class name may exists more than once.</param>
    /// <param name="foundClasses">Predicted class names. A class name may exists more than once.</param>
    private static void findPosNeg(List<string> realClasses, List<string> foundClasses, out int truePositive, out int falsePositive, out int falseNegative)
    {            
        Dictionary<string, int> dicReal = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase);
        Dictionary<string, int> dicFound = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase);
        #region fill dictionaries
        foreach (string className in realClasses)
        {
            if (!dicReal.ContainsKey(className))
                dicReal[className] = 1;
            else
                dicReal[className]++;
        }
        foreach (string className in foundClasses)
        {
            if (!dicFound.ContainsKey(className))
                dicFound[className] = 1;
            else
                dicFound[className]++;
        }
        #endregion

        truePositive = 0;
        falsePositive = 0;
        falseNegative = 0;
        foreach (string className in dicFound.Keys)
        {
            if (!dicReal.ContainsKey(className))
                falsePositive += dicFound[className];
            else
            {
                int found = dicFound[className];
                int real = dicReal[className];
                truePositive += Math.Min(found, real);
                if (real > found)
                    falseNegative += real - found;
                else if (found > real)
                    falsePositive += found - real;
            }
        }
        foreach (string className in dicReal.Keys)
            if (!dicFound.ContainsKey(className))
                falseNegative += dicReal[className];

    }
    /// <summary>
    /// Calculates F1Score ref:https://en.wikipedia.org/wiki/Precision_and_recall
    /// </summary>
    private static double calc_F1Score(int truePositive, int falsePositive, int falseNegative, out double precision, out double recall)
    {
        precision = (double)truePositive / ((double)truePositive + (double)falsePositive);
        recall = (double)truePositive / ((double)truePositive + (double)falseNegative);
        double div = (precision + recall);
        return (div != 0d) ? 2d * precision * recall / div : 0d;
    }