cv::connectedComponentsWithStats 在 OpenCV 3.2.0 中有时会与 gcc 6.2 一起崩溃
cv::connectedComponentsWithStats in OpenCV 3.2.0 sometimes crashes with gcc 6.2
使用这个简单的独立演示:
#include <opencv2/opencv.hpp>
#include <iostream>
int main(int argc, char *argv[]) {
// unsigned char data[] = {1, 0, 1}; // crashes
unsigned char data[] = {1, 1, 0}; // does not crash
cv::Mat1b testImage = cv::Mat1b(3, 1, data);
cv::Mat labeledImage;
cv::Mat stats;
cv::Mat centroids;
int neighborhood = 8;
int componentCount = cv::connectedComponentsWithStats(
testImage, labeledImage, stats, centroids, neighborhood);
std::cout << "componentCount: " << componentCount << std::endl;
return EXIT_SUCCESS;
}
在 gcc 5.4 中,它适用于两个 'data' 值。使用 gcc 6.2,它适用于 {1,1,0}
但使用 data = {1,0,0}
:
转储它
======= Memory map: ========
00400000-00407000 r-xp 00000000 08:01 15214967 /home/doria/build/Examples/c++/OpenCV/Bug/Bug
00606000-00607000 rw-p 00006000 08:01 15214967 /home/doria/build/Examples/c++/OpenCV/Bug/Bug
020b2000-0216c000 rw-p 00000000 00:00 0 [heap]
7f2608000000-7f2608021000 rw-p 00000000 00:00 0
7f2608021000-7f260c000000 ---p 00000000 00:00 0
7f260cc1d000-7f260cc24000 r-xp 00000000 08:01 10883576 /lib/x86_64-linux-gnu/librt-2.23.so
7f260cc24000-7f260ce23000 ---p 00007000 08:01 10883576 /lib/x86_64-linux-gnu/librt-2.23.so
7f260ce23000-7f260ce24000 r--p 00006000 08:01 10883576 /lib/x86_64-linux-gnu/librt-2.23.so
7f260ce24000-7f260ce25000 rw-p 00007000 08:01 10883576 /lib/x86_64-linux-gnu/librt-2.23.so
7f260ce25000-7f260ce28000 r-xp 00000000 08:01 10883446 /lib/x86_64-linux-gnu/libdl-2.23.so
有什么想法吗?
我可以用 Visual Studio 2015 (vc14 x64) 重现这个错误。
问题似乎符合 352 of connectedcomponents.cpp:
//A quick and dirty upper bound for the maximimum number of labels.
const size_t Plength = img.rows*img.cols / 4;
LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT)* Plength);
对于您的测试图像,此 PLength
的计算结果为 0
:
Plength = (3*1)/4 = 0
所以 *P
有零个元素。
但是,算法中有几个地方有这个赋值:
P[lunique] = lunique;
和 lunique
的值为 >0
。所以这会导致堆损坏有时。
解决方法应该是提供更好的上限估计 Plength
。
我对错误负责...叹息。
问题是该算法在图像上以 2x2 块工作。标签的最大数量是每个块一个。不幸的是,如果图像有奇数行 and/or 列,则块数的估计是错误的。所以要解决这个问题,我们应该这样做:
const size_t Plength = ((img.rows + 1) / 2) * ((img.cols + 1) / 2);
我们今天将为此向 OpenCV 提交拉取请求。加上一组改进的测试。顺便说一句,我们还在等待算法的并行版本(多核)被包括在内。
我们已经在 11 月提交了 pull request 算法的并行版本(多核),它也修复了错误。
您可以在 OpenCV 3.3 中找到固定版本,自 2017 年 6 月以来。此外,它还包括并行版本。
使用这个简单的独立演示:
#include <opencv2/opencv.hpp>
#include <iostream>
int main(int argc, char *argv[]) {
// unsigned char data[] = {1, 0, 1}; // crashes
unsigned char data[] = {1, 1, 0}; // does not crash
cv::Mat1b testImage = cv::Mat1b(3, 1, data);
cv::Mat labeledImage;
cv::Mat stats;
cv::Mat centroids;
int neighborhood = 8;
int componentCount = cv::connectedComponentsWithStats(
testImage, labeledImage, stats, centroids, neighborhood);
std::cout << "componentCount: " << componentCount << std::endl;
return EXIT_SUCCESS;
}
在 gcc 5.4 中,它适用于两个 'data' 值。使用 gcc 6.2,它适用于 {1,1,0}
但使用 data = {1,0,0}
:
======= Memory map: ========
00400000-00407000 r-xp 00000000 08:01 15214967 /home/doria/build/Examples/c++/OpenCV/Bug/Bug
00606000-00607000 rw-p 00006000 08:01 15214967 /home/doria/build/Examples/c++/OpenCV/Bug/Bug
020b2000-0216c000 rw-p 00000000 00:00 0 [heap]
7f2608000000-7f2608021000 rw-p 00000000 00:00 0
7f2608021000-7f260c000000 ---p 00000000 00:00 0
7f260cc1d000-7f260cc24000 r-xp 00000000 08:01 10883576 /lib/x86_64-linux-gnu/librt-2.23.so
7f260cc24000-7f260ce23000 ---p 00007000 08:01 10883576 /lib/x86_64-linux-gnu/librt-2.23.so
7f260ce23000-7f260ce24000 r--p 00006000 08:01 10883576 /lib/x86_64-linux-gnu/librt-2.23.so
7f260ce24000-7f260ce25000 rw-p 00007000 08:01 10883576 /lib/x86_64-linux-gnu/librt-2.23.so
7f260ce25000-7f260ce28000 r-xp 00000000 08:01 10883446 /lib/x86_64-linux-gnu/libdl-2.23.so
有什么想法吗?
我可以用 Visual Studio 2015 (vc14 x64) 重现这个错误。
问题似乎符合 352 of connectedcomponents.cpp:
//A quick and dirty upper bound for the maximimum number of labels.
const size_t Plength = img.rows*img.cols / 4;
LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT)* Plength);
对于您的测试图像,此 PLength
的计算结果为 0
:
Plength = (3*1)/4 = 0
所以 *P
有零个元素。
但是,算法中有几个地方有这个赋值:
P[lunique] = lunique;
和 lunique
的值为 >0
。所以这会导致堆损坏有时。
解决方法应该是提供更好的上限估计 Plength
。
我对错误负责...叹息。
问题是该算法在图像上以 2x2 块工作。标签的最大数量是每个块一个。不幸的是,如果图像有奇数行 and/or 列,则块数的估计是错误的。所以要解决这个问题,我们应该这样做:
const size_t Plength = ((img.rows + 1) / 2) * ((img.cols + 1) / 2);
我们今天将为此向 OpenCV 提交拉取请求。加上一组改进的测试。顺便说一句,我们还在等待算法的并行版本(多核)被包括在内。
我们已经在 11 月提交了 pull request 算法的并行版本(多核),它也修复了错误。
您可以在 OpenCV 3.3 中找到固定版本,自 2017 年 6 月以来。此外,它还包括并行版本。