|
摘要 : 为检测SMT焊点的质量,提取焊点质量信息,研究了利用光学手段实测的SMT焊点的三维重建和显示技术,并且运用Visual C#.Net和OPENGL编制了一套软件。该软件可以利用SMT焊点的二维图像,通过三维重构算法计算出SMT焊点的表面高度离散点的数据集,即离散点云。对离散点云进行排序重组和三角网格化后,运用OpenGL 对三角网格进行消隐,设定法线、光照、材质和贴图的处理,重建SMT焊点的表面,由此获得SMT焊点的三维信息,利于分析焊点的质量信息。
关键词 : SMT焊点; 三维重建;OPENGL; Visual C#.Net;离散点云;三角网格化
0 引言 在无铅化进程中,焊点质量问题越来越受到人们的关注。相关的检测技术也是层出不穷。如Photonic公司采用光子结晶的CCD固体摄影元件技术,将该技术应用于焊点检测装置,可检测出不良焊点。英国X-Tek公司运用X射线穿透物体表面的原理,透视电子元件内部,从而达到检测和分析电子元件各种常见的焊点状况。但是以上技术都是二维检测为基础的,并且由于X射线仪器成本不菲,很难适应小企业的需求。又由于二维检测不能获得焊点在高度上的信息,所以本文提出了一种SMT焊点三维重构显示技术,即根据SMT焊点二维图像通过三维重构算法计算出SMT焊点表面离散点,通过对离散点云进行排序重组和三角网格化,运用OpenGL 对三角网格进行消隐,设定法线、光照、材质和贴图的处理,重构SMT焊点的表面,从而达到获得焊点三维信息和降低检测成本的目的。
文章中运用的OpenGL,即开放性图形库(Open Graphic Library) ,它并不是一种编程语言,而是一种API (Application Program2ming Interface ,应用程序编程接口) 。使用某种编程语言(如C#) 编写程序时,可以像调用其它API 函数一样调用OpenGL 库中的API 函数。使用OpenGL 的最大好处是它比射线跟踪程序要快好几个数量级。它使用由Silicon Graphics(SGI) 公司精心开发和优化的算法,此公司在计算机图形和动画领域是公认的业界领袖。Microsoft ,SGI ,IBM,DEC ,SUN ,HP 等在计算机市场中占主导地位的大公司都将OpenGL 作为自己的图形标准,从而使其成为新一代的三维图形工业标准[7]。
1 离散点的获取
要重构SMT焊点的三维形态,需要所有SMT焊点的表面点的坐标,即所有表面离散点的集合,即离散点云。我们通过三维重构算法获取点云数据。在Shape from Shading: A Survey一文中[6],列举了几种三维重构算法,本文在Tsai and Shah算法的基础上,改进了一种三维重构算法,并且通过编写程序,利用二维图像成功计算出SMT焊点表面点云数据[6]。
1.1 Tsai and Shah算法及改进[6]
本文中采用的Tsai的算法是目前几种主流的阴影恢复算法最快的,所以该算法具有在实时性的三维重建当中应用的光明前景。下面对Tsai and Shah算法的推导过程作一个简单的介绍。并对本文对Tsai and Shah算法所作的改进工作作简单的介绍。 Ping Sing Tsai 首先根据一种基于朗伯体漫反射模型的基本光照方程: (1) 其中E(x,y) 是像素在(x,y) 处的灰度值, ,τ是光照方向的,是光照的,然后用下面差分格式逼近 , (公式2) , (公式3) 其中Z(x,y)是(x,y)点处的高度值,把式
1. 2和1.3代入式1.1,然后重新定义一个函 数, 对上面的函数在给定的点 和给定的高度值用多元泰勒级数展开到一阶,

(公式5) 其中 ,(公式6) 上面的式子可以写成向量的形式 ,(公式7)
其中 ,

(公式8)
对一幅N×N的图像,就有N2个上述的等式,最终可以形成一个A·Z=B的矩阵,采用Jacobi叠代法求解上述的的等式,最终得到了每个点的高度值。
(公式9)
对Tsai and Shah算法的改进,主要实现在对输入图像的预处理和对输出离散点云高度值的滤波处理上。对采集的SMT焊点二维图像进行预处理和对获得的离散点云高度上的值进行滤波处理,可以使获得的离散点云更加的合理,减少了噪点,具体内容请参考作者前期研究的论文。可以看到改进的Tsai and Shah算法可以得到更好的SMT焊点二维图像和离散点云[1]。
1.2 Tsai and Shah算法实现
根据上文的理论推导,运用C#语言[3]实现Tsai and Shah算法,关键程序如下: for(I=1;I<=iter;I++) { for(i=0;i { for(j=0;j { /* calculate -f(Zij) & df(Zij) */ if(j-1 < 0 || i-1 < 0) /* take care boundary */ { p = q = 0.0f; } else { p =Zn1[i,j] - Zn1[i,(j-1)]; q =Zn1[i,j] - Zn1[(i-1),j]; } pq = 1.0 + p*p + q*q; PQs = 1.0 + Ps*Ps + Qs*Qs; Eij = pic1[i*pictureBox1.Image.Width+j]/255.0; fZ = -1.0*(Eij - MAX(0.0f,Convert.ToSingle((1+p*Ps+q*Qs)/(Math.Sqrt(pq)*Math.Sqrt(PQs)))); dfZ = -1.0*((Ps+Qs)/(Math.Sqrt(pq)*Math.Sqrt(PQs))-(p+q)*(1.0+p*Ps+q*Qs)/(Math.Sqrt(pq*pq*pq)*Math.Sqrt(PQs))) ; Y = (fZ + dfZ*Zn1[i,j]); K = (Si1[i,j]*dfZ/(Wn+dfZ*Si1[i,j]*dfZ)); Si[i,j] = (1.0 - K*dfZ)*Si1[i,j]; Zn[i,j] = Zn1[i,j] + K*(Y-dfZ*Zn1[i,j]); } } for(i=0;i { for(j=0;j { Zn1[i,j] = Zn[i,j]; Si1[i,j] = Si[i,j]; } } } 2 OpenGL与C#.NET在SMT焊点三维重建的应用
本文中编制的软件显示部分主要是利用OpenGL与Visual C#.NET完成。此软件可在窗口中对三维重构算法生成的点云进行旋转、平移、放缩、切线、排序、曲面重构等操作。本文利用此软件以重构SMT焊点模型为例,在三角网格化后对OpenGL 的命令功能进行有效组合利用,以得到实际SMT焊点的三维重建对象[2][3]。
2.1 Visual C#.Net中使用OpenGL 的方法
微软对于和他们竞争的东西,比如CORBA(COM的竞争对手)和OpenGL(DirectX的竞争对手)提供较少的标准支持。不过在C#中实现OpenGl也并非没有可能,有很多很好的第3方库可以使用。下载库CSOpenGL.2.1-1.2并且安装。在工程中添加命名空间CsGL.OpenGL,并且在工程中引用CSGL.DLL,这样就可以在C#.NET工程下使用OPENGL。
2.2 离散点的三角网格化
根据SMT焊点的二维图像利用三维重构算法计算出来的SMT焊点的高度是离散点云数据。而运用OPENGL来进行SMT焊点表面的三维重建需要将这些点有序的三角网格化[5]。利用传统三维测量仪测出的大量离散点,由于这些点往往是杂乱点,没法从数据存储结构上得到一个点的邻近点信息[4],因此,从这些杂乱离散点得到三角网格是个难题。而采用本文方法得到的离散点云是有一定规律性的,可以有效的利用这些规律将点云三角网格化。
本文中用一个二维数组Zn[,]来存储表面数据点云数据。二维数组Zn[i,j]中的(i,j)和SMT焊点二维图像的象素(x,y)的相对应位置是一一对应的,所以可以根据右手定则使用如下图1代码循环构筑三角网格化。如图1所示首先利用右手定则用(i,j), ( i+1,j+1), ( i+1,j)三个点构筑一个三角形,然后再根据右手定则用(i,j), ( i,j+1), ( i+1,j+1)构筑一个另三角形,这样的话每一个离散点就可以构筑两个三角形。本文采集的SMT焊点的二维图像的大小是128×128个象素。所以可以构筑出(128-1)×(128-1)×2=32258个三角形。利用如上规则,可以方便的完成三角网格化。在C#中的OpenGl程序如下: GLUT.glBegin(GL.GL_TRIANGLES); for(i=0;i<127;i++) { for(j=0;j<127;j++) { GLUT.glVertex3f(i, j, tsai[i,j]); GLUT.glVertex3f(i, j, tsai[i,j+1]); GLUT.glVertex3f(i+1, j, tsai[i+1,j]);
GLUT.glVertex3f(i+1, j, tsai[i+1,j]); GLUT.glVertex3f(i, j+1, tsai[i,j+1]); GLUT.glVertex3f(i+1, j+1, tsai[i+1,j+1]); } } GLUT.glEnd(); // 正方形绘制结束 2.3 法向量[7] 在三维物体显示技术中,法向量不但是得到理想的光照效果重要条件, 也是产生逼真图形的关键因素。它通过确定物体相对于光源的方位,可以计算出此点的受光情况。而三角形内部点的受光情况由三个顶点按一定的算法得到,因此,首先需要定义点云上每个点的法向量。对于一个平面,其上各点的法向量都一样,所以称为平面法向。而对于一个曲面,虽然在计算机图形学中常常用许多小曲面片去逼近,但事实上每个顶点的法向都不一样。对于曲面上的每个点的法向量计算就有不同方法,可以根据不同的应用对象选用合适的方法进行计算。OpenGL 本身并未提供计算法向量的函数,但它提供了指定法向量的函数。计算法向量的工作由程序员自己去完成。
在软件中,通过定义A1,A2,A3,B1,B2,B3六个变量作为一个三角网格三点(x1,y1,z1),(x2,y2,z2) ,(x3,y3,z3)之中的任两个点间的向量(A1,A2,A3),( B1,B2,B3)。从而计算出三角平面的法向量(x,y,z)。 A1 = x1-x2; A2 = y1-y2; A3 = z1-z2; B1 = x1-x3; B2 = y1-y3; B3 = z1-z3; x = A2*B3-A3*B2; y = A3*B1-A1*B3; z = A1*B2-A2*B1; 为了得到更平滑的光照效果,本文中将一个顶点周围的几个三角形的法向量求平均作为此点的法向量, 并采用平滑的明暗处理GLUT.glShadeModel(GLUT. GLSMOOTH)。此时 ,在边界的过渡就比较平稳,消除了边界处的不光顺。在编程中,可以在每次绘制三角形的前面对要绘制三角形的三个点求法向量,这样可以在绘制三角形表面的同时也可以将法向量信息也计算完毕,再通过GLUT.glNormal3f(x,y,z)指令完成法向量的显示。
2.4 光照、材质和贴图[7]
通过计算SMT焊点表面法向量,可以得到光源的反射角度,接下来的工作,就是要设置光照、材质和贴图。OpenGL 可以使用至少八个互相独立的光源。每增加一个光源就将显著地增加计算量。为了有效与合理的节约系统资源,软件中只使用了一个光源。光照对于三维真实感图形是非常重要的。事实上,如果没有光照,所重建的SMT焊点三维模型就没有立体感,和二维图形基本没有区别[7]。OpenGl把光分为四个独立的部分,即辐射光、环境光、散射光、反射光。在程序中分别设置他们,最后通过OpenGl的内部计算并显示出来。
OpenGl中的材质定义了物体表面对各种光的反射比率。纹理映射是真实感图形制作的一个重要部分,运用纹理映射可以方便的制作真实感图形,而不用花更多的时间去考虑物体的表面纹理。OpenGl提供了一系列完成的纹理操作函数,用户可以用它们构造理想的物体表面,可以对光照物体进行处理,使其映射出所处环境的景象。具体的关键实现程序,如下所示[7]。 public string add="焊点.bmp"; float[] Light_Model_Ambient={ 0.0f , 1.0f , -1.0f , 1.0f }; float[] Specular = { 0.2f , 0.1f , 0.1f , 0.1f }; // 定义茶壶的镜面反射颜色 float Shininess = 20.0f; // 定义镜面反射指数即材质亮度 float [] light_position = { 1.0f, 1.0f, 1.0f, 0.0f }; GL.glLightModelfv( GL.GL_LIGHT_MODEL_AMBIENT , Light_Model_Ambient ); // 设置全局环境光 GL.glLightfv( GL.GL_LIGHT0 , GL.GL_DIFFUSE , Light0_Diffuse ); GL.glMaterialfv( GL.GL_FRONT_AND_BACK , GL.GL_SPECULAR , Specular ); // 设置 镜面反射颜色 GL.glMaterialf( GL.GL_FRONT , GL.GL_SHININESS , Shininess ); // 设置 镜面反射指数 GL.glEnable( GL.GL_LIGHTING ); // 启用光照 GL.glEnable( GL.GL_LIGHT0); // 启用0号光源 GL.glClearDepth(1.0); // 设置深度缓存 GL.glEnable( GL.GL_DEPTH_TEST ); // 启用深度检测 GL.glDepthFunc(GL.GL_LESS); // 所作深度测试的类型 GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT,GL.GL_NICEST); //高度优化的透视投影计算 GL.glClearColor(0.0f, 0.0f, 0.0f, 100.0f); // 黑色背景 /**********************************************启用纹理映射****************/ GL.glEnable( GL.GL_TEXTURE_2D ); // 启用纹理映射 _Image = new Bitmap( add ); // 可以改变路径 换上你喜欢的图片 //图像的宽和高必须是2的N次方 且宽度和高度最小是64象素 当然 肯定有办法可以绕过这个限制 _Image.RotateFlip( RotateFlipType.RotateNoneFlipY ); Rectangle __Rect = new Rectangle( 0 , 0 , _Image.Width , _Image.Height ); // 图片矩形 _BitmapData = _Image.LockBits( __Rect , ImageLockMode.ReadOnly , PixelFormat.Format24bppRgb ); GL.glGenTextures( 1 , Texture ); // 生成一个纹理名字 GL.glBindTexture( GL.GL_TEXTURE_2D ,Texture[0] );//2D纹理将纹理名字Texture[0]绑定到纹理目标上 GL.glTexImage2D( GL.GL_TEXTURE_2D , 0 , (int)GL.GL_RGB, _Image.Width , _Image.Height , 0 , GL.GL_BGR_EXT , GL.GL_UNSIGNED_BYTE , _BitmapData.Scan0 ); // 生成纹理 GL.glTexParameteri( GL.GL_TEXTURE_2D , GL.GL_TEXTURE_MIN_FILTER , GL.GL_LINEAR ); GL.glTexParameteri( GL.GL_TEXTURE_2D , GL.GL_TEXTURE_MAG_FILTER , GL.GL_LINEAR); // GL_LINEAR 线形滤波 使得纹理从远到近都平滑显示 但需要更多的CPU和显卡运算 _Image.UnlockBits(_BitmapData); // 内存解锁 _Image.Dispose(); //释放__Image使用的所有资源 经过以上工作可以得到SMT焊点真实图像三维重建图形如下所示。
3 结论 本文在运用三维重构算法计算出SMT焊点的表面高度离散点云基础上,运用OpenGl完成了SMT焊点三维形态显示,使得SMT焊点三维质量信息的提取更加直观。通过本文的研究,发现在SMT焊点三维重建以及显示研究中运用OpenGl可以加快开发速度,增加了代码的可读性,通用性,提高代码执行的效率并且使得三维重建的SMT焊点表面形态更加真实。并且在OpenGl基础上开发的焊点显示窗口,拥有更专业、更逼真、更流畅的显示效果。此外,本文也探索了Visual C#.Net下OpenGl开发的方法。
参考资料: [1 ] 孙家广. 计算机图形学(第三版) [M] . 北京:清华大学出版社,1998.1 [2] 李兰友,王学彬,等. C#图像处理程序设计实例[M] . 北京:国防工业出版社,2003.4 [3] 郑小平.Visual C#.NET开发与实践[M].北京:人民邮电出版社.2001 [4] 王清,等. 散乱数据点的增量快速曲面重建算法[J ] . 软件学报, 2001,11(9) :122121227. [5] Hoope H , DeRose T,Duchamp T,et al. Surface Reconstructionfrom Unorganized Points. In :Cunningham Sed [ C] . Proceedings of the SIGGRAPH’92. Danvers : Addison2Wesley Publishing Company ,1992. 71278. [6] Ruo Zhang, Ping-Sing Tsai, James Edwin Cryer, and Mubarak Shah. Shape from Shading: A Survey[J]. IEEE TRANSACTIONS ON PATTERN ANALYSIS AND MACHINE INTELLIGENCE, VOL. 21, NO. 8, AUGUST 1999 [7] 乔林,费广正,等. OpenGL 程序设计[M] . 北京:清华大学出版社,2000.
|