具有亚像素精度的图像处理
Image processing with sub pixel accuracy
我正在编写一个控制工业机械的用户界面程序。
该机是应用于电子生产行业的全自动联机丝网印刷机。该机器的确切用途是将焊膏印刷到裸露的 PCB 上。
该系统包括 2 个摄像头,它们构成了一个视觉系统,用于定位基准点并使机械所涉及的过程自动化。
我遇到的问题是我需要能够在从相机拍摄的图像中定位形状和物体,这很简单,但是 - 为了获得所需的精度,我需要能够以亚像素精度来做到这一点.
这两个摄像头组成一个双视觉摄像头,其中一个摄像头将向上看模板,另一个向下看 PCB。双视觉相机位于 X 和 Y 方向移动的移动托架上。PCB 被夹在 table 上,可以在 X、Y 和 theta 方向移动。视觉系统用于检测PCB位置和模板位置之间的差异,然后调整table使两者对齐。
编辑:
这是从现有 UI 程序截取的部分屏幕截图:
模板图像是顶部图像,PCB 是底部图像,这里的图像是灰度图像 - 在新系统中我正在查看使用颜色,但需要使用灰度图像。
注意: 当你阅读这篇文章时,你可能在想 "well why don't you just use whatever you use in the existing UI?" 现有的 UI 是用 VB6 编写的,我想移动一下远离,并且该程序的视觉方面是由第三方公司编写的.ocx,但已不存在。
我玩了 AForge.NET 一点点,发现它真的很容易使用,我能够用它来定位各种不同的形状并找到它们的中心,这很棒,但它没有'具有亚像素精度。然而,我可能会以此为起点,然后将子像素算法应用于单个中心像素甚至整个形状。
编辑:
这是从我使用 AForge 编写的测试程序中截取的示例图像:
红色轮廓和十字准线是我作为视觉辅助/实验添加的。这是用我可能使用的相机拍摄的,它的分辨率为 1280 x 1024,但是镜头不是我将使用的实际镜头,这就是图像略微 'fisheyed' 的原因。还有感兴趣的物体会比这更轻
在实际系统中,镜头会在模板和 PCB 上看到一个 10mm x 8mm 的正方形,这意味着每个像素将代表 7.8125um^2,但是我可以将 XYY table 移动 1.25 的增量嗯一次,如果我用相机看不到那些动作,那基本上就没用了。
我需要 1um(亚)像素精度。
有谁知道我可以用来做这件事的任何东西吗?我已经搜索了很长时间,但我似乎只找到了有关以亚像素精度渲染图像的信息。
或者,更好的是,有谁知道我可以自己写一些东西来做这件事吗?我什至不知道从哪里开始!
任何反馈将不胜感激。
新信息说明了很多...我认为您应该更关注粘贴应用的准确性,而不是托架位置的准确性。我敢打赌打印机的点尺寸和误差比 1 um 大得多,而且所需的精度取决于 PCB 的使用(布线和间隙宽度)。无论如何我会这样做:
线性化图像几何结构
您需要 de-fisheye 图片。由于您 camera/optics 设置将是固定的(尤其是焦点和到 PCB 的距离),您应该为每个 PCB 厚度制作一个棋盘网格的图像。然后创建将棋盘线性化为真实矩形的映射,以便在下一个过程之前丢弃偏差。
正常化照明条件
- 见
亚像素精度
图像的每个像素都是其区域内所有内容的集成。因此,如果我们知道任何边界 (background/foreground) 的 2 种颜色 (c0,c1
),那么我们就可以估计它们的 sub-pixel 位置。让我们从轴对齐的矩形开始。我是这样看的:
网格的每个正方形代表一个像素区域。 c0
是灰色,c1
是绿色。在相机图像中,您得到的最终颜色是每个像素内所有颜色的组合:
c = s0*c0 + s1*c1
其中 c
是最终像素颜色,s0,s1
是对应 <0,1>
范围内 c0,c1
颜色的区域,其中 s0+s1=1.0
。现在我们要计算 s0,s1
以获得 sub-pixel 精度。所以首先检测边界上的像素位置为以下之一:
- 水平边缘
- 竖边
- 角
这可以通过检查相邻像素来完成。 c0,c1
可以从具有饱和颜色的像素(所有邻居都具有相同的颜色)中获得这些像素位于内部区域。我会忽略角像素,因为它们的位置可以从最近的 H/V 边缘像素获得(不可能从上面的等式中获得两个 x,y 坐标)。所以现在对于每个 H、V 边只求解系统:
I. c = s0*c0 + s1*c1
II. s0 + s1 = 1.0;
计算 s0,s1
并且垂直边缘的边缘位置是其中之一:
x=x0 + pixel_size*s0 // if c0 is on the left
x=x0 + pixel_size*s1 // if c1 is on the left
水平边是这样的:
y=y0 + pixel_size*s0 // if c0 is on the top
y=y0 + pixel_size*s1 // if c1 is on the bottom
其中 x0,y0
是以像素为单位的像素左上角位置,坐标系是 x+
向右, y+
向下。如果您有不同的设置,只需更改方程式 ...
现在,如果你有非轴对齐的边缘,那么你需要计算斜率(一个轴需要多少像素才能在另一个轴上改变 dy/dx
。并相应地处理这些区域:
所以唯一改变的是从计算的 s0,s1
到实际边缘位置的转换。现在您需要计算 left/right 边或 up/down。如果您使用轴对齐示例中的方程式,那么您将获得像素中间的边缘位置。所以你只需将它的两侧的斜率移动 x +/- 0.5*dx/dy
或 y +/- 0.5*dy/dx
其中 dx,dy
是边缘斜率。
要获得 dx,dy
只需沿着边缘搜索完全饱和的像素,如果找到,则 (dx,dy)
是 2 个最接近的此类像素之间的距离...
[备注]
您可以在 booth 灰度和 RGB 上执行此操作。希望这能有所帮助。
我正在编写一个控制工业机械的用户界面程序。
该机是应用于电子生产行业的全自动联机丝网印刷机。该机器的确切用途是将焊膏印刷到裸露的 PCB 上。 该系统包括 2 个摄像头,它们构成了一个视觉系统,用于定位基准点并使机械所涉及的过程自动化。 我遇到的问题是我需要能够在从相机拍摄的图像中定位形状和物体,这很简单,但是 - 为了获得所需的精度,我需要能够以亚像素精度来做到这一点.
这两个摄像头组成一个双视觉摄像头,其中一个摄像头将向上看模板,另一个向下看 PCB。双视觉相机位于 X 和 Y 方向移动的移动托架上。PCB 被夹在 table 上,可以在 X、Y 和 theta 方向移动。视觉系统用于检测PCB位置和模板位置之间的差异,然后调整table使两者对齐。
编辑:
这是从现有 UI 程序截取的部分屏幕截图:
模板图像是顶部图像,PCB 是底部图像,这里的图像是灰度图像 - 在新系统中我正在查看使用颜色,但需要使用灰度图像。
注意: 当你阅读这篇文章时,你可能在想 "well why don't you just use whatever you use in the existing UI?" 现有的 UI 是用 VB6 编写的,我想移动一下远离,并且该程序的视觉方面是由第三方公司编写的.ocx,但已不存在。
我玩了 AForge.NET 一点点,发现它真的很容易使用,我能够用它来定位各种不同的形状并找到它们的中心,这很棒,但它没有'具有亚像素精度。然而,我可能会以此为起点,然后将子像素算法应用于单个中心像素甚至整个形状。
编辑:
这是从我使用 AForge 编写的测试程序中截取的示例图像:
红色轮廓和十字准线是我作为视觉辅助/实验添加的。这是用我可能使用的相机拍摄的,它的分辨率为 1280 x 1024,但是镜头不是我将使用的实际镜头,这就是图像略微 'fisheyed' 的原因。还有感兴趣的物体会比这更轻
在实际系统中,镜头会在模板和 PCB 上看到一个 10mm x 8mm 的正方形,这意味着每个像素将代表 7.8125um^2,但是我可以将 XYY table 移动 1.25 的增量嗯一次,如果我用相机看不到那些动作,那基本上就没用了。 我需要 1um(亚)像素精度。
有谁知道我可以用来做这件事的任何东西吗?我已经搜索了很长时间,但我似乎只找到了有关以亚像素精度渲染图像的信息。
或者,更好的是,有谁知道我可以自己写一些东西来做这件事吗?我什至不知道从哪里开始!
任何反馈将不胜感激。
新信息说明了很多...我认为您应该更关注粘贴应用的准确性,而不是托架位置的准确性。我敢打赌打印机的点尺寸和误差比 1 um 大得多,而且所需的精度取决于 PCB 的使用(布线和间隙宽度)。无论如何我会这样做:
线性化图像几何结构
您需要 de-fisheye 图片。由于您 camera/optics 设置将是固定的(尤其是焦点和到 PCB 的距离),您应该为每个 PCB 厚度制作一个棋盘网格的图像。然后创建将棋盘线性化为真实矩形的映射,以便在下一个过程之前丢弃偏差。
正常化照明条件
- 见
- 见
亚像素精度
图像的每个像素都是其区域内所有内容的集成。因此,如果我们知道任何边界 (background/foreground) 的 2 种颜色 (
c0,c1
),那么我们就可以估计它们的 sub-pixel 位置。让我们从轴对齐的矩形开始。我是这样看的:网格的每个正方形代表一个像素区域。
c0
是灰色,c1
是绿色。在相机图像中,您得到的最终颜色是每个像素内所有颜色的组合:c = s0*c0 + s1*c1
其中
c
是最终像素颜色,s0,s1
是对应<0,1>
范围内c0,c1
颜色的区域,其中s0+s1=1.0
。现在我们要计算s0,s1
以获得 sub-pixel 精度。所以首先检测边界上的像素位置为以下之一:- 水平边缘
- 竖边
- 角
这可以通过检查相邻像素来完成。
c0,c1
可以从具有饱和颜色的像素(所有邻居都具有相同的颜色)中获得这些像素位于内部区域。我会忽略角像素,因为它们的位置可以从最近的 H/V 边缘像素获得(不可能从上面的等式中获得两个 x,y 坐标)。所以现在对于每个 H、V 边只求解系统:I. c = s0*c0 + s1*c1 II. s0 + s1 = 1.0;
计算
s0,s1
并且垂直边缘的边缘位置是其中之一:x=x0 + pixel_size*s0 // if c0 is on the left x=x0 + pixel_size*s1 // if c1 is on the left
水平边是这样的:
y=y0 + pixel_size*s0 // if c0 is on the top y=y0 + pixel_size*s1 // if c1 is on the bottom
其中
x0,y0
是以像素为单位的像素左上角位置,坐标系是x+
向右,y+
向下。如果您有不同的设置,只需更改方程式 ...现在,如果你有非轴对齐的边缘,那么你需要计算斜率(一个轴需要多少像素才能在另一个轴上改变
dy/dx
。并相应地处理这些区域:所以唯一改变的是从计算的
s0,s1
到实际边缘位置的转换。现在您需要计算 left/right 边或 up/down。如果您使用轴对齐示例中的方程式,那么您将获得像素中间的边缘位置。所以你只需将它的两侧的斜率移动x +/- 0.5*dx/dy
或y +/- 0.5*dy/dx
其中dx,dy
是边缘斜率。要获得
dx,dy
只需沿着边缘搜索完全饱和的像素,如果找到,则(dx,dy)
是 2 个最接近的此类像素之间的距离...
[备注]
您可以在 booth 灰度和 RGB 上执行此操作。希望这能有所帮助。