RGB 数据在哪里?您可以使用它来帮助检测。您无需将图像投影到任何平面上即可检测颗粒。基本上有两种检测方式
-
基于神经网络、模糊逻辑、机器学习等的非确定性
这种方法需要一个训练数据集来识别对象。正确的训练集和分类器架构/拓扑选择需要大量经验。但除此之外,您不需要对其进行编程......因为通常使用一些现成的 lib/tool 只需配置和传递数据。
-
基于距离或相关系数的确定性
我将从检测特定功能开始,例如:
- 托盘具有特定尺寸
- 托盘具有锋利的边缘和特定几何形状深度数据中的形状
- 托盘具有特定范围的颜色(黄色木材 +/- 光照和污垢)
- 木材具有特定的纹理图案
因此,计算每个特征的一些系数,即物体与实际托盘的接近程度。然后将所有系数组合的距离设置为阈值(可能加权,因为某些特征更稳健)。
我不使用 #1 方法,所以我会选择 #2。所以结合 RGB 和深度数据(它们必须完全匹配)。然后分割图像(基于深度和颜色)。之后,为每个找到的对象分类是否是托盘...
[编辑1]
您的彩色图像与深度数据不对应。对齐的灰度质量很差,深度数据图像也很差。深度数据是否以某种方式处理(失去精度)?如果您从不同方面查看数据:
你可以看到它有多差,所以我怀疑你是否可以使用深度数据进行检测......
PS。我使用我的Align already captured rgb and depth images 进行可视化。
唯一剩下的是彩色图像,并仅检测具有匹配颜色的区域。然后检测特征并分类。图像中托盘的颜色几乎是白色。这里 HSV 将颜色减少到基本的 16 种颜色(懒得分割)
您应该通过您的设置获得托盘的颜色范围,以简化检测。然后检查这些对象的大小、形状、面积、周长等特征...
[编辑2]
所以我将从图像预处理开始:
- 转换为 HSV
-
仅阈值接近托盘颜色的像素
我选择了(H=40,S=18,V>100) 作为托盘颜色。我的 HSV 范围是每个通道的 <0,255>,因此 Hue 角度差只能是 <-180deg,+180deg> 最大值,对应于我的范围内的 <-128,+128>。
-
去除太薄的区域
只需扫描所有水平线和垂直线即可计算随后设置的像素,如果尺寸太小,请将它们重新着色为黑色...
这是结果:
左边是原始图像(缩小尺寸以便适合此页面),中间是颜色阈值结果,最后是小区域的过滤。您可以使用门槛和托盘颜色来改变行为以满足您的需求。
这里C++代码:
int tr_d=10; // min size of pallet [pixels[
int h,s,v,x,y,xx;
color c;
pic1=pic0;
pic1.pf=_pf_rgba;
pic2.resize(pic1.xs*3,pic1.ys); xx=0;
pic2.bmp->Canvas->Draw(xx,0,pic0.bmp); xx+=pic1.xs;
// [color selection]
for (y=0;y<pic1.ys;y++)
for (x=0;x<pic1.xs;x++)
{
// get color from image
c=pic0.p[y][x];
rgb2hsv(c);
// distance to white-yellowish color in HSV (H=40,S=18,V>100)
h=c.db[picture::_h]-40;
s=c.db[picture::_s]-18;
v=c.db[picture::_v];
// hue is cyclic angular so use only shorter angle
if (h<-128) h+=256;
if (h>+128) h-=256;
// abs value
if (h< 0) h=-h;
if (s< 0) s=-s;
// treshold close colors
c.dd=0;
if (h<25)
if (s<25)
if (v>100)
c.dd=0x00FFFFFF;
pic1.p[y][x]=c;
}
pic2.bmp->Canvas->Draw(xx,0,pic1.bmp); xx+=pic1.xs;
// [remove too thin areas]
for (y=0;y<pic1.ys;y++)
for (x=0;x<pic1.xs;)
{
for ( ;x<pic1.xs;x++) if ( pic1.p[y][x].dd) break; // find set pixel
for (h=x;x<pic1.xs;x++) if (!pic1.p[y][x].dd) break; // find unset pixel
if (x-h<tr_d) for (;h<x;h++) pic1.p[y][h].dd=0; // if too small size recolor to zero
}
for (x=0;x<pic1.xs;x++)
for (y=0;y<pic1.ys;)
{
for ( ;y<pic1.ys;y++) if ( pic1.p[y][x].dd) break; // find set pixel
for (h=y;y<pic1.ys;y++) if (!pic1.p[y][x].dd) break; // find unset pixel
if (y-h<tr_d) for (;h<y;h++) pic1.p[h][x].dd=0; // if too small size recolor to zero
}
pic2.bmp->Canvas->Draw(xx,0,pic1.bmp); xx+=pic1.xs;
有关picture 和color 的说明,请参见how to extract the borders of an image (OCT/retinal scan image)。或者查看我的任何 DIP/CV 标记答案。现在代码注释很好,很简单,但只需要添加:
您可以忽略pic2 的东西,它只是上面发布的图像,所以我不需要手动打印屏幕并将子结果合并到绘画中...为了提高鲁棒性,您应该增加动态范围的增强(因此阈值有任何输入图像的相同条件)。此外,您应该与单色进行比较(如果存在更多木托盘)。
现在您应该对区域进行分割或标记
- 循环浏览整个图像
- 找到第一个带有托盘颜色的像素集
-
用一些不同于设置托盘颜色的不同 ID 颜色填充该区域
我使用黑色0x00000000 空格和白色0x00FFFFFF 作为调色板像素颜色。所以使用ID={1,2,3,4,5...}。还要记住填充像素的数量(即您的区域),因此您不需要再次计算它。您也可以在填充时直接计算边界框。
-
计算和比较特征
您需要尝试不止一张图片。找出哪些属性有利于检测。我会选择周长与面积比。和/或边界框大小...可以通过简单地选择所有具有适当ID颜色的相邻黑色像素的像素来提取周长。
另见类似Fracture detection in hand using image proccessing
祝你好运,玩得开心......