为什么积分图像包含额外的零行和零列?
why the integral-image contains extra row and column of zeros?
我正在学习如何使用带有 Java API 的 opencv 来使用积分图像,并且我创建了一个测试来显示使用积分图像之前和使用之后的灰度图像。灰度图像为 10 x 10,当我将其转换为积分图像时
我发现它是 11 x 11,带有额外的零行和额外的零列,如下面的输出所示。
请告诉我为什么积分图像包含额外的零行和零列?
代码:
public static void main(String[] args) {
MatFactory matFactory = new MatFactory();
FilePathUtils.addInputPath(path_Obj);
Mat bgrMat = matFactory.newMat(FilePathUtils.getInputFileFullPathList().get(0));
Mat gsImg = SysUtils.rgbToGrayScaleMat(bgrMat);
Log.D(TAG, "MainClas", "gsImg.dump(): " + gsImg.dump());
Mat integralMat = new Mat();
Imgproc.integral(gsImg, integralMat, CvType.CV_32F);
Log.D(TAG, "MainClas", "sumMat.dump(): " + integralMat.dump());
}
OutPut:
1: Debug: MainClass -> MainClas: gsImg.dump(): [2, 1, 7, 5, 1, 11, 2, 7, 9, 11;
1, 2, 0, 0, 3, 20, 17, 5, 7, 8;
4, 8, 0, 2, 6, 30, 31, 5, 2, 2;
39, 43, 47, 44, 38, 62, 60, 37, 37, 39;
27, 29, 52, 52, 47, 75, 67, 59, 58, 63;
25, 21, 49, 51, 51, 78, 64, 66, 76, 80;
40, 36, 50, 46, 41, 56, 42, 45, 47, 49;
13, 17, 20, 15, 9, 20, 15, 19, 12, 11;
17, 13, 8, 5, 4, 7, 13, 20, 17, 17;
2, 4, 7, 9, 8, 6, 6, 7, 7, 8]
2: Debug: MainClass -> MainClas: sumMat.dump(): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 2, 3, 10, 15, 16, 27, 29, 36, 45, 56;
0, 3, 6, 13, 18, 22, 53, 72, 84, 100, 119;
0, 7, 18, 25, 32, 42, 103, 153, 170, 188, 209;
0, 46, 100, 154, 205, 253, 376, 486, 540, 595, 655;
0, 73, 156, 262, 365, 460, 658, 835, 948, 1061, 1184;
0, 98, 202, 357, 511, 657, 933, 1174, 1353, 1542, 1745;
0, 138, 278, 483, 683, 870, 1202, 1485, 1709, 1945, 2197;
0, 151, 308, 533, 748, 944, 1296, 1594, 1837, 2085, 2348;
0, 168, 338, 571, 791, 991, 1350, 1661, 1924, 2189, 2469;
0, 170, 344, 584, 813, 1021, 1386, 1703, 1973, 2245, 2533]
这是预期的行为。请注意,OpenCV 中的积分图像 sum(X,Y)
定义为 (see documentation here) 原始图像中索引小于、sum_(x < X, y < Y)
、不小于或等于的像素之和整体形象。因此 sum(0,0)
例如将是零像素的总和,定义为 0。这也是生成的总和图像比原始图像多一个行和列的原因。
这样做的原因是它可以更容易地计算图像块的总和等,并在它们包含顶部 and/or 左边框时以统一的方式处理它们。
有两个原因。
第一个是纯数学的。假设您有一排 3 个数字(像素)。它产生了多少可能的累计和?答案是 4。您可以取前 0 个像素、第 1 个像素、第 2 个像素或所有 3 个像素的总和。不同和的数量是4:(0,1,2,3)。 4 正好是 3+1。等效地,宽度为 10 的图像将为每一行产生 11 个总和,而大小为 10x10 的图像将产生 11x11 个总和。
第二个原因是为了简化编程。积分图像用于计算图像中任何可能矩形的总和,仅需 4 个动作(2 个角的总和减去其他 2 个角)。角之间的距离恰好等于要求和的矩形的大小。例如,如果您的矩形宽度为 5 个像素,那么您可以在索引 im[i][j]
和 im[i][j+5]
处访问积分图像。但是,如果您的矩形覆盖了整个图像的宽度或高度,这可能会产生一个索引,该索引会超出数组 1。这就是为什么积分图像以比图像大 1x1 的大小存储的原因
注:可以将积分图像存储在与图像大小相同的数组中。但是随后对数组的访问会慢得多,因为需要测试索引是否越界。访问索引[-1]处的积分图像必须被检测并产生0的和,并且访问索引>宽度将自动return整个宽度的和。
OpenCV主要由于速度原因实现了较大的积分图像。矩形和的计算只需要4次+或-运算和4次指针运算。只要请求的矩形在图像内具有合法坐标,就无需测试指针是否落在图像内
有些架构允许越界访问数组(在非法索引处)。例如 GPU 着色器。在这些架构上,积分图像可以以不同的方式实现(NxN 的大小而不是 N+1xN+1,甚至是总和的金字塔)
能否在openCV中手动去除积分图像中多余的列?
强烈不建议这样做! openCV 有一个内置代码以特定方式访问积分图像。如果您删除第一列,您可能会导致不可预测的计算。
此外 - 正如我所解释的,这个额外的行和列将 运行 时间增加了 10 倍(因为加法和减法是由 CPU 执行的比如果()条件)
请注意,积分图像是原始图像的完全不同表示。它不仅具有不同的大小 (N+1)x(N+1),而且具有不同的深度。您的原始图像可以是灰度图像(每个像素存储一个字节),而整体图像通常每个像素需要 4 个字节(因为许多像素的总和需要更大的数字)。所以无论如何,积分图像将比原始图像占用大约 4 倍的内存。由于 BPP(每像素位数)不同,您无法在原始图像中放入完整图像,所以为什么要被不同的宽度和高度所困扰
我正在学习如何使用带有 Java API 的 opencv 来使用积分图像,并且我创建了一个测试来显示使用积分图像之前和使用之后的灰度图像。灰度图像为 10 x 10,当我将其转换为积分图像时 我发现它是 11 x 11,带有额外的零行和额外的零列,如下面的输出所示。
请告诉我为什么积分图像包含额外的零行和零列?
代码:
public static void main(String[] args) {
MatFactory matFactory = new MatFactory();
FilePathUtils.addInputPath(path_Obj);
Mat bgrMat = matFactory.newMat(FilePathUtils.getInputFileFullPathList().get(0));
Mat gsImg = SysUtils.rgbToGrayScaleMat(bgrMat);
Log.D(TAG, "MainClas", "gsImg.dump(): " + gsImg.dump());
Mat integralMat = new Mat();
Imgproc.integral(gsImg, integralMat, CvType.CV_32F);
Log.D(TAG, "MainClas", "sumMat.dump(): " + integralMat.dump());
}
OutPut:
1: Debug: MainClass -> MainClas: gsImg.dump(): [2, 1, 7, 5, 1, 11, 2, 7, 9, 11;
1, 2, 0, 0, 3, 20, 17, 5, 7, 8;
4, 8, 0, 2, 6, 30, 31, 5, 2, 2;
39, 43, 47, 44, 38, 62, 60, 37, 37, 39;
27, 29, 52, 52, 47, 75, 67, 59, 58, 63;
25, 21, 49, 51, 51, 78, 64, 66, 76, 80;
40, 36, 50, 46, 41, 56, 42, 45, 47, 49;
13, 17, 20, 15, 9, 20, 15, 19, 12, 11;
17, 13, 8, 5, 4, 7, 13, 20, 17, 17;
2, 4, 7, 9, 8, 6, 6, 7, 7, 8]
2: Debug: MainClass -> MainClas: sumMat.dump(): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 2, 3, 10, 15, 16, 27, 29, 36, 45, 56;
0, 3, 6, 13, 18, 22, 53, 72, 84, 100, 119;
0, 7, 18, 25, 32, 42, 103, 153, 170, 188, 209;
0, 46, 100, 154, 205, 253, 376, 486, 540, 595, 655;
0, 73, 156, 262, 365, 460, 658, 835, 948, 1061, 1184;
0, 98, 202, 357, 511, 657, 933, 1174, 1353, 1542, 1745;
0, 138, 278, 483, 683, 870, 1202, 1485, 1709, 1945, 2197;
0, 151, 308, 533, 748, 944, 1296, 1594, 1837, 2085, 2348;
0, 168, 338, 571, 791, 991, 1350, 1661, 1924, 2189, 2469;
0, 170, 344, 584, 813, 1021, 1386, 1703, 1973, 2245, 2533]
这是预期的行为。请注意,OpenCV 中的积分图像 sum(X,Y)
定义为 (see documentation here) 原始图像中索引小于、sum_(x < X, y < Y)
、不小于或等于的像素之和整体形象。因此 sum(0,0)
例如将是零像素的总和,定义为 0。这也是生成的总和图像比原始图像多一个行和列的原因。
这样做的原因是它可以更容易地计算图像块的总和等,并在它们包含顶部 and/or 左边框时以统一的方式处理它们。
有两个原因。
第一个是纯数学的。假设您有一排 3 个数字(像素)。它产生了多少可能的累计和?答案是 4。您可以取前 0 个像素、第 1 个像素、第 2 个像素或所有 3 个像素的总和。不同和的数量是4:(0,1,2,3)。 4 正好是 3+1。等效地,宽度为 10 的图像将为每一行产生 11 个总和,而大小为 10x10 的图像将产生 11x11 个总和。
第二个原因是为了简化编程。积分图像用于计算图像中任何可能矩形的总和,仅需 4 个动作(2 个角的总和减去其他 2 个角)。角之间的距离恰好等于要求和的矩形的大小。例如,如果您的矩形宽度为 5 个像素,那么您可以在索引 im[i][j]
和 im[i][j+5]
处访问积分图像。但是,如果您的矩形覆盖了整个图像的宽度或高度,这可能会产生一个索引,该索引会超出数组 1。这就是为什么积分图像以比图像大 1x1 的大小存储的原因
注:可以将积分图像存储在与图像大小相同的数组中。但是随后对数组的访问会慢得多,因为需要测试索引是否越界。访问索引[-1]处的积分图像必须被检测并产生0的和,并且访问索引>宽度将自动return整个宽度的和。
OpenCV主要由于速度原因实现了较大的积分图像。矩形和的计算只需要4次+或-运算和4次指针运算。只要请求的矩形在图像内具有合法坐标,就无需测试指针是否落在图像内
有些架构允许越界访问数组(在非法索引处)。例如 GPU 着色器。在这些架构上,积分图像可以以不同的方式实现(NxN 的大小而不是 N+1xN+1,甚至是总和的金字塔)
能否在openCV中手动去除积分图像中多余的列?
强烈不建议这样做! openCV 有一个内置代码以特定方式访问积分图像。如果您删除第一列,您可能会导致不可预测的计算。
此外 - 正如我所解释的,这个额外的行和列将 运行 时间增加了 10 倍(因为加法和减法是由 CPU 执行的比如果()条件)
请注意,积分图像是原始图像的完全不同表示。它不仅具有不同的大小 (N+1)x(N+1),而且具有不同的深度。您的原始图像可以是灰度图像(每个像素存储一个字节),而整体图像通常每个像素需要 4 个字节(因为许多像素的总和需要更大的数字)。所以无论如何,积分图像将比原始图像占用大约 4 倍的内存。由于 BPP(每像素位数)不同,您无法在原始图像中放入完整图像,所以为什么要被不同的宽度和高度所困扰