【发布时间】:2015-09-17 06:56:39
【问题描述】:
我正在尝试为 使用少量内存的二进制图像(单色)(边界框左上和右下点的坐标)制作 blob 查找算法(需要因为图像的大分辨率)在 C++ 上。
有OpenCV之类的工具,但是它有很多过滤器,如果你想检测二进制图像中的每个blob,它太慢了,还有CvBlobsLib但是支持已经过时了(最后版本早于 5 年),我无法为 Visual Studio 2013 设置它(它必须用 Cmake 编译,并且会出错)。在维基百科中有两种类型的算法——“一次的一个分量”和“两次通过”connected-component,但它们都使用标签,这意味着你将有另一个二维整数数组,但这需要很多时间由于 int 的大小(4 字节),我们需要 int,因为图像大小和超过 65535 个标签的可能性(很短)。如果它甚至很短,它将减少两倍的内存,这又是很多。我发现了一个用 C quicblobsalgol 编写的“quickblob”,但我无法从源代码运行它(但 exe 运行正常),试图分析代码,我得到了一些东西,但它背后的整个想法仍然含糊不清我,所以我也尝试了类似 floodFill 算法和类似“disjoined-set data structure” link 来保存 blob,这意味着理论上使用的内存是由 blob 的数量定义的(单个黑色像素不被识别为斑点)。这是 C++ 代码:
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <math.h>
#define ROWS 4000
#define COLS 4000
#define BLOBS 1000000
using namespace std;
void floodFillAlgorithm(short(&arr)[ROWS][COLS]);
int recurciveMarkBlob(short(&arr)[ROWS][COLS], int **ptr_labels, int i, int j, int group);
int main(){
short arr[ROWS][COLS];
srand((unsigned int)time(0)); // use current time as seed for random generator
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
arr[i][j] = rand() % 2;
}
}
/*for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
cout << arr[i][j] << '\t';
}
cout << '\n';
}*/
floodFillAlgorithm(arr);
cout << '\n';
cout << '\n';
/*for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
cout << arr[i][j] << '\t';
}
cout << '\n';
}*/
system("PAUSE");
return 0;}
void floodFillAlgorithm(short(&arr)[ROWS][COLS])
{
int group = 0;
int **ptr_labels;
ptr_labels = (int **)malloc(BLOBS * sizeof(int*));
if (ptr_labels == 0)
{
printf("ERROR: Out of memory\n");
}
for (int i = 0; i < BLOBS; i++)
{
ptr_labels[i] = NULL;
}
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
if (arr[i][j] == 1)
{
recurciveMarkBlob(arr, ptr_labels,i, j, ++group);
arr[i][j] = 1;
}
}
}
int count = 0;
for (int i = 0; i < BLOBS; i++)
{
if (ptr_labels[i] != NULL)
{
count++;
//cout << "Label: " << i << " ; X1: " << ptr_labels[i][0] << " ; Y1: " << ptr_labels[i][1] << " ; X2: " << ptr_labels[i][2] << " ; Y2: " << ptr_labels[i][3] << " ; X3: " << ptr_labels[i][4] << " ; Y3: " << ptr_labels[i][5] << " ; POINTS: " << ptr_labels[i][6] << endl;
}
}
cout << "Count: " << count << endl;
system("PAUSE");
for (int i = 0; i < BLOBS; i++)
{
if (ptr_labels[i] != NULL)
{
free(ptr_labels[i]);
}
}
free(ptr_labels);
}
int recurciveMarkBlob(short(&arr)[ROWS][COLS], int **ptr_labels, int i, int j, int group)
{
//cout << " i : " << i << " j: " << j << endl;
if (j != 0)
{
if ((arr[i][j] == arr[i][j - 1]) && (arr[i][j - 1] == 1))
{
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j - 1;
ptr_labels[group][1] = i;
ptr_labels[group][2] = j;
ptr_labels[group][3] = i;
ptr_labels[group][4] = j;
ptr_labels[group][5] = i;
ptr_labels[group][6] = 2; // taken points (area) for current shape
}
else
{
if (ptr_labels[group][0] > j - 1)
{
ptr_labels[group][0] = j - 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i, j - 1, group);
arr[i][j] = 1;
}
}
if (j != COLS - 1)
{
if ((arr[i][j] == arr[i][j + 1]) && (arr[i][j + 1] == 1))
{
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j;
ptr_labels[group][1] = i;
ptr_labels[group][2] = j + 1;
ptr_labels[group][3] = i;
ptr_labels[group][4] = j;
ptr_labels[group][5] = i;
ptr_labels[group][6] = 2; // taken points (area) for current shape
}
else
{
if (ptr_labels[group][2] < j + 1)
{
ptr_labels[group][2] = j + 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i, j + 1, group);
arr[i][j] = 1;
}
}
if (i != 0)
{
if ((arr[i][j] == arr[i - 1][j]) && (arr[i - 1][j] == 1))
{
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j;
ptr_labels[group][1] = i - 1;
ptr_labels[group][2] = j;
ptr_labels[group][3] = i;
ptr_labels[group][4] = j;
ptr_labels[group][5] = i;
ptr_labels[group][6] = 2; // taken points (area) for current shape
}
else
{
if (ptr_labels[group][1] > i - 1)
{
ptr_labels[group][1] = i - 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i - 1, j, group);
arr[i][j] = 1;
}
}
if (i != ROWS - 1)
{
if ((arr[i][j] == arr[i + 1][j]) && (arr[i + 1][j] == 1))
{
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j;
ptr_labels[group][1] = i;
ptr_labels[group][2] = j;
ptr_labels[group][3] = i + 1;
ptr_labels[group][4] = j;
ptr_labels[group][5] = i;
ptr_labels[group][6] = 2; // taken points (area) for current shape
}
else
{
if (ptr_labels[group][3] < i + 1)
{
ptr_labels[group][3] = i + 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i + 1, j, group);
arr[i][j] = 1;
}
}
if ((i != 0) && (j != 0))
{
if ((arr[i][j] == arr[i - 1][j - 1]) && (arr[i - 1][j - 1] == 1))
{
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j - 1;
ptr_labels[group][1] = i - 1;
ptr_labels[group][2] = j;
ptr_labels[group][3] = i;
ptr_labels[group][4] = j;
ptr_labels[group][5] = i;
ptr_labels[group][6] = 2; // taken points (area) for current shape
}
else
{
if (ptr_labels[group][0] > j - 1)
{
ptr_labels[group][0] = j - 1;
}
if (ptr_labels[group][1] > i - 1)
{
ptr_labels[group][1] = i - 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i - 1, j - 1, group);
arr[i][j] = 1;
}
}
if ((i != 0) && (j != COLS - 1))
{
//cout << "i: " << i << " ; j: " << j << endl;
if ((arr[i][j] == arr[i - 1][j + 1]) && (arr[i - 1][j + 1] == 1))
{
//cout << "i: " << i << " ; j: " << j << endl;
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j;
ptr_labels[group][1] = i - 1;
ptr_labels[group][2] = j + 1;
ptr_labels[group][3] = i;
ptr_labels[group][4] = j;
ptr_labels[group][5] = i;
ptr_labels[group][6] = 2; // taken points (area) for current shape
//cout << "Label: " << group << " ; X1: " << ptr_labels[group][0] << " ; Y1: " << ptr_labels[group][1] << " ; X2: " << ptr_labels[group][2] << " ; Y2: " << ptr_labels[group][3] << endl;
}
else
{
if (ptr_labels[group][2] < j + 1)
{
ptr_labels[group][2] = j + 1;
}
if (ptr_labels[group][1] > i - 1)
{
ptr_labels[group][1] = i - 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i - 1, j + 1, group);
arr[i][j] = 1;
}
}
if ((i != ROWS - 1) && (j != 0))
{
if ((arr[i][j] == arr[i + 1][j - 1]) && (arr[i + 1][j - 1] == 1))
{
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j - 1;
ptr_labels[group][1] = i;
ptr_labels[group][2] = j;
ptr_labels[group][3] = i + 1;
ptr_labels[group][4] = j;
ptr_labels[group][5] = i;
ptr_labels[group][6] = 2; // taken points (area) for current shape
}
else
{
if (ptr_labels[group][0] > j - 1)
{
ptr_labels[group][0] = j - 1;
}
if (ptr_labels[group][3] < i + 1)
{
ptr_labels[group][3] = i + 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i + 1, j - 1, group);
arr[i][j] = 1;
}
}
if ((i != ROWS - 1) && (j != COLS - 1))
{
if ((arr[i][j] == arr[i + 1][j + 1]) && (arr[i + 1][j + 1] == 1))
{
if (ptr_labels[group] == NULL)
{
ptr_labels[group] = (int *)malloc(7 * sizeof(int*));
ptr_labels[group][0] = j;
ptr_labels[group][1] = i;
ptr_labels[group][2] = j + 1;
ptr_labels[group][3] = i + 1;
ptr_labels[group][4] = j; // x of pixel in black
ptr_labels[group][5] = i; // y of pixel in black
ptr_labels[group][6] = 2; // taken points (area) for current shape
}
else
{
if (ptr_labels[group][2] < j + 1)
{
ptr_labels[group][2] = j + 1;
}
if (ptr_labels[group][3] < i + 1)
{
ptr_labels[group][3] = i + 1;
}
ptr_labels[group][6]++;
}
arr[i][j] = 0;
recurciveMarkBlob(arr, ptr_labels, i + 1, j + 1, group);
arr[i][j] = 1;
}
}
/**/
arr[i][j] = 0;
return 0;
}
主要问题是为什么在 main 函数结束之前还有这么多 RAM 仍在使用中(147 MB)。 尾递归“recurciveMarkBlob()”使用值 i,j 的参数,组,动态分配内存,这就是为什么内存临时跳转到 600 MB(主要来自参数),在释放动态分配的内存后仍然需要 148 MB,图像为 4 000 x 4 000 x 2 字节 = 16 000 000 字节 = 16 MB。我已经阅读了有关“功能占用内存”here 的信息,但我仍然不明白为什么。如果有人可以用汇编代码解释发生了什么,这种情况是否正常。 我使用的是发布模式 release vs debug
另外,每个人都可以提出快速和低内存占用算法来检测大型二进制图像的斑点。
【问题讨论】:
-
尝试使用opencv编译cvBlobLib!它易于使用。
-
对于分辨率为 9960 x 14040 的大图像,cvBlobLib 是否足够快,需要多少 RAM。您能否提供正确的链接以使用 Visual Studio 进行编译?对不起大写,我已经编辑了。
-
您是否至少实现了完整的 opencv 解决方案并对其进行了分析?你的问题中有很多错误的假设,而且你过早地优化了周围的东西。
-
我已经实现了opencv 2.4.11,但我可以
t add the plugin cvblobslib. I found out that I must compile it with Cmake, but it gives some problems, first it coudnt 找到“CMakeLists.txt”,链接后它是“CMakeLists.txt:14 (FIND_PACKAGE) 处的 CMake 错误:找到包配置文件:D:/opencv/sources/cmake/OpenCVConfig.cmake,但它将 OpenCV_FOUND 设置为 FALSE,因此包“OpenCV”被视为未找到。”
标签: algorithm memory recursion blob detect