我有一个 Kinect ,我正在使用 OpenCV 和点云库。我想将 IR 图像投影到 2D 平面上,以便进行叉车托盘检测。我该怎么办?
我试图检测叉车中的托盘是一张图片:
答案 0 :(得分:1)
RGB 数据在哪里?您可以使用它来帮助检测。您无需将图像投影到任何平面上以检测颗粒。基本上有两种用于检测的方法
基于神经网络,模糊逻辑,机器学习等的非确定性
此方法需要训练数据集来识别对象。适当的训练集和分类器架构/拓扑选择需要很多经验。但除此之外你不需要对它进行编程......因为通常使用一些随时可用的lib /工具来配置和传递数据。
基于距离或相关系数的确定性
我会从检测特定功能开始:
因此,为每个特征计算一些系数,该对象与真实托盘的接近程度。然后只计算所有系数组合的距离(可能加权,因为某些特征更稳健)。
我不使用#1 方法,所以我会选择#2 。因此,结合 RGB 和深度数据(它们必须完全匹配)。然后分割图像(基于深度和颜色)。之后,对于每个找到的对象进行分类,如果它是托盘......
<强> [EDIT1] 强>
您的彩色图像与深度数据不对应。对齐的灰度级质量差,深度数据图像也很差。是否以某种方式处理深度数据(失去精度)?如果您从不同方面查看数据:
你可以看到它有多糟糕,所以我怀疑你可以使用深度数据进行检测......
PS。我使用Align already captured rgb and depth images进行可视化。
唯一剩下的就是彩色图像和仅检测颜色匹配的区域。然后检测功能并进行分类。图像中托盘的颜色几乎是白色。这里HSV将颜色减少到基本的16种颜色(懒得分段)
您应该通过设置获得托盘的颜色范围,以便轻松检测。然后检查这些对象的大小,形状,面积,周长......
<强> [EDIT2] 强>
所以我将从Image预处理开始:
阈值仅接近托盘颜色的像素
我选择(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
祝你好运,玩得开心......