如何使用 OpenCV 和 PCL 在二维平面上投影红外图像

How to project IR image on a 2D plane using OpenCV and PCL

我有一个 Kinect,我正在使用 OpenCV 和点云库。我想将 IR 图像投影到 2D 平面上以进行叉车托盘检测。我该怎么做?

我正在尝试检测叉车中的托盘,这是一张图片:

RGB数据在哪里?您可以使用它来帮助检测。您不需要将图像投影到任何平面上来检测颗粒。基本上有2种检测方式

  1. 基于神经网络、模糊逻辑、机器学习等的非确定性

    此方法需要训练数据集来识别对象。选择合适的训练集和分类器 architecture/topology 需要很多经验。但除此之外,您不需要对其进行编程...因为通常一些现成的 lib/tool 仅用于配置和传递数据。

  2. 基于距离或相关系数的确定性

    我将从检测特定功能开始,例如:

    • 托盘有特定尺寸
    • 托盘有锋利的边缘和特定的几何形状深度数据
    • 托盘具有 特定颜色范围(淡黄色木材 +/- 照明和污垢)
    • 木材具有特定的纹理图案

    因此,为每个特征计算一些系数,对象与真实托盘的接近程度。然后只是对所有系数组合的距离进行阈值处理(可能加权,因为某些特征更稳健)。

我不使用 #1 方法,所以我会选择 #2。所以结合 RGB 和深度数据(它们必须完全匹配)。然后分割图像(基于深度和颜色)。之后对每个找到的对象进行分类,如果它是托盘...

[编辑1]

您的彩色图像与深度数据不对应。对齐的灰度图质量很差,深度数据图像也很差。深度数据是否以某种方式处理(失去精度)?如果你从不同的角度看你的数据:

你可以看到它有多差,所以我怀疑你是否可以使用深度数据进行检测...

PS。我使用 进行可视化。

唯一剩下的就是彩色图像,只检测颜色匹配的区域。然后检测特征并分类。图像中托盘的颜色几乎是白色的。这里HSV将颜色减少到基本的16种颜色(懒得分割)

您应该获得您的设置可能的托盘颜色范围,以简化检测。然后检查这些对象的大小、形状、面积、周长等特征...

[编辑2]

所以我将从图像预处理开始:

  1. 转换为 HSV
  2. 阈值仅像素接近调色板颜色

    我选择了(H=40,S=18,V>100)作为托盘颜色。我的 HSV 范围是每个通道 <0,255>,因此 Hue 角度差只能是 <-180deg,+180deg> 最大值,这对应于我范围内的 <-128,+128>

  3. 移除太细的区域

    只需扫描所有水平和垂直线数随后设置的像素,如果尺寸太小,将它们重新着色为黑色...

这是结果:

左边是原图(缩小后适合本页),中间是颜色阈值结果,最后是过滤掉小区域。您可以使用阈值和调色板颜色来改变行为以满足您的需要。

此处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;

有关 picturecolor 的说明,请参见 。或者查看我的任何 DIP/CV 标记的答案。现在代码注释得很好而且简单明了,但只需要添加:

你可以忽略pic2东西它只是上面发布的图像所以我不需要手动打印屏幕并合并绘画中的子结果......为了提高稳健性你应该添加动态范围增强(因此阈值对于任何输入图像都具有相同的条件)。此外,您还应该比较单一颜色(如果存在更多木材类型的托盘)。

现在你应该分割或标记区域

  1. 遍历整个图像
  2. 使用托盘颜色找到第一个像素集
  3. 用一些不同于设置托盘颜色的不同 ID 颜色填充该区域

    我使用黑色 0x00000000 space 和白色 0x00FFFFFF 作为调色板像素颜色。所以使用ID={1,2,3,4,5...}。还要记住填充像素的数量(即您的区域),因此您不需要再次计算它。您也可以在填充时直接计算边界框。

  4. 计算和比较特征

    您需要尝试不止一张图片。找出哪些属性有利于检测。我会选择周长与面积比。和/或边界框大小...可以通过简单地选择所有具有适当ID颜色的邻近黑色像素的像素来提取周长。

另见类似内容Fracture detection in hand using image proccessing

祝你好运,玩得开心......