嵌入式平台上的斑点检测,内存受限
Blob detection on embedded platform, memory restricted
我有一个带 1MB RAM 和 1MB ROM 的 STM32H7 MCU。我需要在最大尺寸为 1280x1024 的二进制图像数组上制作斑点检测算法。
我搜索了斑点检测算法,发现它们主要分为两类,LINK:
- 基于标签传播的算法(一次一个组件):
他们首先搜索一个未标记的对象像素,用新标签标记该像素;然后,在后面的处理中,它们将相同的标签传播到连接到该像素的所有对象像素。演示代码看起来像这样:
void setLabels(){
int m=2;
for(int y=0; y<height; y++){
for(int x=0; x<width; x++){
if(getPixel(x,y) == 1) compLabel(x,y,m++);
}
}
}
void compLabel(int i, int j,int m){
if(getPixel(i,j)==1){
setPixel(i,j,m); //assign label
compLabel(i-1,j-1,m);
compLabel(i-1,j,m);
compLabel(i-1,j+1,m);
compLabel(i,j-1,m);
compLabel(i,j+1,m);
compLabel(i+1,j-1,m);
compLabel(i+1,j,m);
compLabel(i+1,j+1,m);
}
}
- 基于标签等效解析(Two-pass)的算法:它们包括两个步骤:在第一步中,他们为每个对象像素分配一个临时标签。在第二步中,他们将分配给每个对象的所有临时标签(称为等效标签)整合为一个唯一的标签,称为代表标签,并用其代表标签替换每个对象像素的临时标签。
第一种算法的缺点是它对原始像素周围的所有像素使用递归调用。怕在STM32上因为栈有限会造成hard fault错误。
第二种算法的缺点是它需要大量内存用于标记图像。例如,对于最大。 1280x1024 的分辨率和最大。标签数量 255(0 表示无标签),图像标签大小为 1.25MB。远远超过我们可用的数量。
我正在寻找有关如何进行的一些建议。如何在不占用大量内存的情况下获取图像中所有斑点的中心坐标和面积信息?任何帮助表示赞赏。我认为第二种算法不在画面中,因为没有可用的内存。
您首先必须使用缩放内核检查您的图像,以将您的图像缩放回可以处理的图像。 4:1 或 9:1 是很好的可能性。或者你将不得不获得更多的内存。因为这种情况似乎不可行。位访问并不是很快,并且会降低您的效率,我什至认为您不需要那么大的图像。 (至少这是我在视觉系统方面的经验)
然后您可以将像素存储在直接 unsigned char
数组中,该数组可以使用您命名的第一个方法进行标记。它不一定是递归过程。您还可以确定一个 blob 是否被重新标记为另一个 blob 并设置一个标志以再次执行此操作。
这使得外部可见函数有一个 while
循环成为可能,它可以在不创建大堆栈的情况下不断调用您的标签函数。
然后通过遍历图像并计算每个标记的斑点的像素实例来确定区域。
通过计算moments of a blob and then calculating the center of mass可以找到某个斑点的中心。这是一些相当复杂的数学运算,所以不要气馁,虽然它是一个苹果,但它是一个很好的解决方案。
(小提示:你可以从 OpenCV 中获取 C++ 代码并查看 their code 以了解它是如何完成的)
我有一个带 1MB RAM 和 1MB ROM 的 STM32H7 MCU。我需要在最大尺寸为 1280x1024 的二进制图像数组上制作斑点检测算法。
我搜索了斑点检测算法,发现它们主要分为两类,LINK:
- 基于标签传播的算法(一次一个组件): 他们首先搜索一个未标记的对象像素,用新标签标记该像素;然后,在后面的处理中,它们将相同的标签传播到连接到该像素的所有对象像素。演示代码看起来像这样:
void setLabels(){
int m=2;
for(int y=0; y<height; y++){
for(int x=0; x<width; x++){
if(getPixel(x,y) == 1) compLabel(x,y,m++);
}
}
}
void compLabel(int i, int j,int m){
if(getPixel(i,j)==1){
setPixel(i,j,m); //assign label
compLabel(i-1,j-1,m);
compLabel(i-1,j,m);
compLabel(i-1,j+1,m);
compLabel(i,j-1,m);
compLabel(i,j+1,m);
compLabel(i+1,j-1,m);
compLabel(i+1,j,m);
compLabel(i+1,j+1,m);
}
}
- 基于标签等效解析(Two-pass)的算法:它们包括两个步骤:在第一步中,他们为每个对象像素分配一个临时标签。在第二步中,他们将分配给每个对象的所有临时标签(称为等效标签)整合为一个唯一的标签,称为代表标签,并用其代表标签替换每个对象像素的临时标签。
第一种算法的缺点是它对原始像素周围的所有像素使用递归调用。怕在STM32上因为栈有限会造成hard fault错误。 第二种算法的缺点是它需要大量内存用于标记图像。例如,对于最大。 1280x1024 的分辨率和最大。标签数量 255(0 表示无标签),图像标签大小为 1.25MB。远远超过我们可用的数量。
我正在寻找有关如何进行的一些建议。如何在不占用大量内存的情况下获取图像中所有斑点的中心坐标和面积信息?任何帮助表示赞赏。我认为第二种算法不在画面中,因为没有可用的内存。
您首先必须使用缩放内核检查您的图像,以将您的图像缩放回可以处理的图像。 4:1 或 9:1 是很好的可能性。或者你将不得不获得更多的内存。因为这种情况似乎不可行。位访问并不是很快,并且会降低您的效率,我什至认为您不需要那么大的图像。 (至少这是我在视觉系统方面的经验)
然后您可以将像素存储在直接 unsigned char
数组中,该数组可以使用您命名的第一个方法进行标记。它不一定是递归过程。您还可以确定一个 blob 是否被重新标记为另一个 blob 并设置一个标志以再次执行此操作。
这使得外部可见函数有一个 while
循环成为可能,它可以在不创建大堆栈的情况下不断调用您的标签函数。
然后通过遍历图像并计算每个标记的斑点的像素实例来确定区域。
通过计算moments of a blob and then calculating the center of mass可以找到某个斑点的中心。这是一些相当复杂的数学运算,所以不要气馁,虽然它是一个苹果,但它是一个很好的解决方案。
(小提示:你可以从 OpenCV 中获取 C++ 代码并查看 their code 以了解它是如何完成的)