对齐已捕获的 rgb 和深度图像
Align already captured rgb and depth images
我正在尝试使用 MATLAB 对齐两张图像 - 一张 rgb 和另一张深度。请注意,我为此检查了几个地方 - 例如 here , here which requires a kinect device, and here here which says that camera parameters are required for calibration. I was also suggested to use EPIPOLAR GEOMETRY to match the two images though I do not know how. The dataset I am referring to is given in rgb-d-t face dataset。一个这样的例子如下所示:
基本事实基本上意味着指定感兴趣的面部区域的边界框已经提供,我使用它们仅裁剪面部区域。 matlab代码如下图所示:
I = imread('1.jpg');
I1 = imcrop(I,[218,198,158,122]);
I2 = imcrop(I,[243,209,140,108]);
figure, subplot(1,2,1),imshow(I1);
subplot(1,2,2),imshow(I2);
裁剪后的两张rgb和depth图如下:
有什么方法可以 register/allign 图片。我从中得到了暗示
here 其中已在 rgb 和深度图像上使用基本的 sobel 运算符来生成边缘图,然后需要生成关键点以进行匹配。两个图像的边缘图都是在这里生成的。
.
但是它们太吵了,我认为我们无法对这些图像进行关键点匹配。
有人可以在 matlab 中推荐一些算法来做同样的事情吗?
序幕
这个答案是基于我之前的答案:
- Does Kinect Infrared View Have an offset with the Kinect Depth View
我手动裁剪你的输入图像,所以我将颜色和深度图像分开(因为我的程序需要它们分开。这可能会导致几个像素的微小偏移变化。而且因为我没有深度(深度图像是 8bit
仅由于灰度 RGB) 然后我使用的深度精度非常差见:
所以我的结果受到了所有这些负面影响。无论如何,这是您需要做的:
确定两个图像的 FOV
所以找到一些在两张图片上都可见的可测量特征。尺寸越大,结果越准确。例如我选择这些:
形成点云或网格
我使用深度图像作为参考,所以我的点云在其 FOV 中。因为我没有距离,而是 8bit
值,所以我通过乘以常数将其转换为某个距离。所以我扫描整个深度图像,并为我在点云阵列中创建点的每个像素。然后将 dept 像素坐标转换为彩色图像 FOV 并复制其颜色。像这样的东西(在 C++ 中):
picture rgb,zed; // your input images
struct pnt3d { float pos[3]; DWORD rgb; pnt3d(){}; pnt3d(pnt3d& a){ *this=a; }; ~pnt3d(){}; pnt3d* operator = (const pnt3d *a) { *this=*a; return this; }; /*pnt3d* operator = (const pnt3d &a) { ...copy... return this; };*/ };
pnt3d **xyz=NULL; int xs,ys,ofsx=0,ofsy=0;
void copy_images()
{
int x,y,x0,y0;
float xx,yy;
pnt3d *p;
for (y=0;y<ys;y++)
for (x=0;x<xs;x++)
{
p=&xyz[y][x];
// copy point from depth image
p->pos[0]=2.000*((float(x)/float(xs))-0.5);
p->pos[1]=2.000*((float(y)/float(ys))-0.5)*(float(ys)/float(xs));
p->pos[2]=10.0*float(DWORD(zed.p[y][x].db[0]))/255.0;
// convert dept image x,y to color image space (FOV correction)
xx=float(x)-(0.5*float(xs));
yy=float(y)-(0.5*float(ys));
xx*=98.0/108.0;
yy*=106.0/119.0;
xx+=0.5*float(rgb.xs);
yy+=0.5*float(rgb.ys);
x0=xx; x0+=ofsx;
y0=yy; y0+=ofsy;
// copy color from rgb image if in range
p->rgb=0x00000000; // black
if ((x0>=0)&&(x0<rgb.xs))
if ((y0>=0)&&(y0<rgb.ys))
p->rgb=rgb2bgr(rgb.p[y0][x0].dd); // OpenGL has reverse RGBorder then my image
}
}
其中 **xyz
是我的点云二维阵列分配的深度图像分辨率。 picture
是我在 DIP 中的形象 class 所以这里有一些相关成员:
xs,ys
是以像素为单位的图像分辨率
p[ys][xs]
是作为 DWORD dd; BYTE db[4];
并集的图像直接像素访问,因此我可以将颜色作为单个 32 位变量或每个颜色通道单独访问。
rgb2bgr(DWORD col)
只需将颜色通道从 RGB 重新排序为 BGR.
渲染它
我为此使用 OpenGL 所以这里是代码:
glBegin(GL_QUADS);
for (int y0=0,y1=1;y1<ys;y0++,y1++)
for (int x0=0,x1=1;x1<xs;x0++,x1++)
{
float z,z0,z1;
z=xyz[y0][x0].pos[2]; z0=z; z1=z0;
z=xyz[y0][x1].pos[2]; if (z0>z) z0=z; if (z1<z) z1=z;
z=xyz[y1][x0].pos[2]; if (z0>z) z0=z; if (z1<z) z1=z;
z=xyz[y1][x1].pos[2]; if (z0>z) z0=z; if (z1<z) z1=z;
if (z0 <=0.01) continue;
if (z1 >=3.90) continue; // 3.972 pre vsetko nad .=3.95m a 4.000 ak nechyti vobec nic
if (z1-z0>=0.10) continue;
glColor4ubv((BYTE* )&xyz[y0][x0].rgb);
glVertex3fv((float*)&xyz[y0][x0].pos);
glColor4ubv((BYTE* )&xyz[y0][x1].rgb);
glVertex3fv((float*)&xyz[y0][x1].pos);
glColor4ubv((BYTE* )&xyz[y1][x1].rgb);
glVertex3fv((float*)&xyz[y1][x1].pos);
glColor4ubv((BYTE* )&xyz[y1][x0].rgb);
glVertex3fv((float*)&xyz[y1][x0].pos);
}
glEnd();
需要添加OpenGL粗略的初始化和相机设置等。这里是未对齐的结果:
对齐
如果您注意到我向 copy_images()
添加了 ofsx,ofsy
个变量。这是相机之间的偏移量。我通过 1
像素在箭头按键上更改它们,然后调用 copy_images
并呈现结果。这样我很快就手动找到了偏移量:
如您所见,x 轴偏移量为 +17
像素,y 轴偏移量为 +4
像素。为了更好地看到深度,这里是侧视图:
希望能有点帮助
好吧,在阅读了很多博客之后,我已经尝试这样做了。我仍然不确定我做的是否正确。如果发现不妥之处,请随时发表评论。为此,我使用了可以在此处找到的 mathworks fex 提交:ginputc 函数。
matlab代码如下:
clc; clear all; close all;
% no of keypoint
N = 7;
I = imread('2.jpg');
I = rgb2gray(I);
[Gx, Gy] = imgradientxy(I, 'Sobel');
[Gmag, ~] = imgradient(Gx, Gy);
figure, imshow(Gmag, [ ]), title('Gradient magnitude')
I = Gmag;
[x,y] = ginputc(N, 'Color' , 'r');
matchedpoint1 = [x y];
J = imread('2.png');
[Gx, Gy] = imgradientxy(J, 'Sobel');
[Gmag, ~] = imgradient(Gx, Gy);
figure, imshow(Gmag, [ ]), title('Gradient magnitude')
J = Gmag;
[x, y] = ginputc(N, 'Color' , 'r');
matchedpoint2 = [x y];
[tform,inlierPtsDistorted,inlierPtsOriginal] = estimateGeometricTransform(matchedpoint2,matchedpoint1,'similarity');
figure; showMatchedFeatures(J,I,inlierPtsOriginal,inlierPtsDistorted);
title('Matched inlier points');
I = imread('2.jpg'); J = imread('2.png');
I = rgb2gray(I);
outputView = imref2d(size(I));
Ir = imwarp(J,tform,'OutputView',outputView);
figure; imshow(Ir, []);
title('Recovered image');
figure,imshowpair(I,J,'diff'),title('Difference with original');
figure,imshowpair(I,Ir,'diff'),title('Difference with restored');
第 1 步
我使用 sobel 边缘检测器来提取深度和 rgb 图像的边缘,然后使用阈值来获取边缘图。我将主要只处理梯度幅度。这给了我两张图片:
第 2 步
接下来我使用 ginput
或 ginputc
函数在两张图像上标记关键点。点之间的对应关系是我事先建立的。我尝试使用 SURF
功能,但它们在深度图像上效果不佳。
步骤 3
利用estimategeometrictransform
得到变换矩阵tform
,然后利用这个矩阵恢复移动图像的原始位置。下一组图片讲述了这个故事。
当然,我仍然相信,如果更明智地选择任一图像中的关键点,结果可以进一步改善。我也认为@Specktre 方法更好。我只是注意到,与问题相比,我在答案中使用了单独的图像对。两张图片都来自同一个数据集,可在此处找到 vap rgb-d-t dataset.
我正在尝试使用 MATLAB 对齐两张图像 - 一张 rgb 和另一张深度。请注意,我为此检查了几个地方 - 例如 here , here which requires a kinect device, and here here which says that camera parameters are required for calibration. I was also suggested to use EPIPOLAR GEOMETRY to match the two images though I do not know how. The dataset I am referring to is given in rgb-d-t face dataset。一个这样的例子如下所示:
基本事实基本上意味着指定感兴趣的面部区域的边界框已经提供,我使用它们仅裁剪面部区域。 matlab代码如下图所示:
I = imread('1.jpg');
I1 = imcrop(I,[218,198,158,122]);
I2 = imcrop(I,[243,209,140,108]);
figure, subplot(1,2,1),imshow(I1);
subplot(1,2,2),imshow(I2);
裁剪后的两张rgb和depth图如下:
有什么方法可以 register/allign 图片。我从中得到了暗示 here 其中已在 rgb 和深度图像上使用基本的 sobel 运算符来生成边缘图,然后需要生成关键点以进行匹配。两个图像的边缘图都是在这里生成的。
但是它们太吵了,我认为我们无法对这些图像进行关键点匹配。
有人可以在 matlab 中推荐一些算法来做同样的事情吗?
序幕
这个答案是基于我之前的答案:
- Does Kinect Infrared View Have an offset with the Kinect Depth View
我手动裁剪你的输入图像,所以我将颜色和深度图像分开(因为我的程序需要它们分开。这可能会导致几个像素的微小偏移变化。而且因为我没有深度(深度图像是 8bit
仅由于灰度 RGB) 然后我使用的深度精度非常差见:
所以我的结果受到了所有这些负面影响。无论如何,这是您需要做的:
确定两个图像的 FOV
所以找到一些在两张图片上都可见的可测量特征。尺寸越大,结果越准确。例如我选择这些:
形成点云或网格
我使用深度图像作为参考,所以我的点云在其 FOV 中。因为我没有距离,而是
8bit
值,所以我通过乘以常数将其转换为某个距离。所以我扫描整个深度图像,并为我在点云阵列中创建点的每个像素。然后将 dept 像素坐标转换为彩色图像 FOV 并复制其颜色。像这样的东西(在 C++ 中):picture rgb,zed; // your input images struct pnt3d { float pos[3]; DWORD rgb; pnt3d(){}; pnt3d(pnt3d& a){ *this=a; }; ~pnt3d(){}; pnt3d* operator = (const pnt3d *a) { *this=*a; return this; }; /*pnt3d* operator = (const pnt3d &a) { ...copy... return this; };*/ }; pnt3d **xyz=NULL; int xs,ys,ofsx=0,ofsy=0; void copy_images() { int x,y,x0,y0; float xx,yy; pnt3d *p; for (y=0;y<ys;y++) for (x=0;x<xs;x++) { p=&xyz[y][x]; // copy point from depth image p->pos[0]=2.000*((float(x)/float(xs))-0.5); p->pos[1]=2.000*((float(y)/float(ys))-0.5)*(float(ys)/float(xs)); p->pos[2]=10.0*float(DWORD(zed.p[y][x].db[0]))/255.0; // convert dept image x,y to color image space (FOV correction) xx=float(x)-(0.5*float(xs)); yy=float(y)-(0.5*float(ys)); xx*=98.0/108.0; yy*=106.0/119.0; xx+=0.5*float(rgb.xs); yy+=0.5*float(rgb.ys); x0=xx; x0+=ofsx; y0=yy; y0+=ofsy; // copy color from rgb image if in range p->rgb=0x00000000; // black if ((x0>=0)&&(x0<rgb.xs)) if ((y0>=0)&&(y0<rgb.ys)) p->rgb=rgb2bgr(rgb.p[y0][x0].dd); // OpenGL has reverse RGBorder then my image } }
其中
**xyz
是我的点云二维阵列分配的深度图像分辨率。picture
是我在 DIP 中的形象 class 所以这里有一些相关成员:xs,ys
是以像素为单位的图像分辨率p[ys][xs]
是作为DWORD dd; BYTE db[4];
并集的图像直接像素访问,因此我可以将颜色作为单个 32 位变量或每个颜色通道单独访问。rgb2bgr(DWORD col)
只需将颜色通道从 RGB 重新排序为 BGR.
渲染它
我为此使用 OpenGL 所以这里是代码:
glBegin(GL_QUADS); for (int y0=0,y1=1;y1<ys;y0++,y1++) for (int x0=0,x1=1;x1<xs;x0++,x1++) { float z,z0,z1; z=xyz[y0][x0].pos[2]; z0=z; z1=z0; z=xyz[y0][x1].pos[2]; if (z0>z) z0=z; if (z1<z) z1=z; z=xyz[y1][x0].pos[2]; if (z0>z) z0=z; if (z1<z) z1=z; z=xyz[y1][x1].pos[2]; if (z0>z) z0=z; if (z1<z) z1=z; if (z0 <=0.01) continue; if (z1 >=3.90) continue; // 3.972 pre vsetko nad .=3.95m a 4.000 ak nechyti vobec nic if (z1-z0>=0.10) continue; glColor4ubv((BYTE* )&xyz[y0][x0].rgb); glVertex3fv((float*)&xyz[y0][x0].pos); glColor4ubv((BYTE* )&xyz[y0][x1].rgb); glVertex3fv((float*)&xyz[y0][x1].pos); glColor4ubv((BYTE* )&xyz[y1][x1].rgb); glVertex3fv((float*)&xyz[y1][x1].pos); glColor4ubv((BYTE* )&xyz[y1][x0].rgb); glVertex3fv((float*)&xyz[y1][x0].pos); } glEnd();
需要添加OpenGL粗略的初始化和相机设置等。这里是未对齐的结果:
对齐
如果您注意到我向
copy_images()
添加了ofsx,ofsy
个变量。这是相机之间的偏移量。我通过1
像素在箭头按键上更改它们,然后调用copy_images
并呈现结果。这样我很快就手动找到了偏移量:如您所见,x 轴偏移量为
+17
像素,y 轴偏移量为+4
像素。为了更好地看到深度,这里是侧视图:
希望能有点帮助
好吧,在阅读了很多博客之后,我已经尝试这样做了。我仍然不确定我做的是否正确。如果发现不妥之处,请随时发表评论。为此,我使用了可以在此处找到的 mathworks fex 提交:ginputc 函数。
matlab代码如下:
clc; clear all; close all;
% no of keypoint
N = 7;
I = imread('2.jpg');
I = rgb2gray(I);
[Gx, Gy] = imgradientxy(I, 'Sobel');
[Gmag, ~] = imgradient(Gx, Gy);
figure, imshow(Gmag, [ ]), title('Gradient magnitude')
I = Gmag;
[x,y] = ginputc(N, 'Color' , 'r');
matchedpoint1 = [x y];
J = imread('2.png');
[Gx, Gy] = imgradientxy(J, 'Sobel');
[Gmag, ~] = imgradient(Gx, Gy);
figure, imshow(Gmag, [ ]), title('Gradient magnitude')
J = Gmag;
[x, y] = ginputc(N, 'Color' , 'r');
matchedpoint2 = [x y];
[tform,inlierPtsDistorted,inlierPtsOriginal] = estimateGeometricTransform(matchedpoint2,matchedpoint1,'similarity');
figure; showMatchedFeatures(J,I,inlierPtsOriginal,inlierPtsDistorted);
title('Matched inlier points');
I = imread('2.jpg'); J = imread('2.png');
I = rgb2gray(I);
outputView = imref2d(size(I));
Ir = imwarp(J,tform,'OutputView',outputView);
figure; imshow(Ir, []);
title('Recovered image');
figure,imshowpair(I,J,'diff'),title('Difference with original');
figure,imshowpair(I,Ir,'diff'),title('Difference with restored');
第 1 步
我使用 sobel 边缘检测器来提取深度和 rgb 图像的边缘,然后使用阈值来获取边缘图。我将主要只处理梯度幅度。这给了我两张图片:
第 2 步
接下来我使用 ginput
或 ginputc
函数在两张图像上标记关键点。点之间的对应关系是我事先建立的。我尝试使用 SURF
功能,但它们在深度图像上效果不佳。
步骤 3
利用estimategeometrictransform
得到变换矩阵tform
,然后利用这个矩阵恢复移动图像的原始位置。下一组图片讲述了这个故事。
当然,我仍然相信,如果更明智地选择任一图像中的关键点,结果可以进一步改善。我也认为@Specktre 方法更好。我只是注意到,与问题相比,我在答案中使用了单独的图像对。两张图片都来自同一个数据集,可在此处找到 vap rgb-d-t dataset.