指纹的特征提取和匹配研究- 附部分代码

这是我在研二的模式识别课程中做的,2010年,当时觉得没什么用,现在回头看一下觉得还是有很多东西值得一看,整理一下。

摘要:指纹识别技术具有不会丢失、不会遗忘、唯一性、不变性、防伪性能好和使用方便等优点,已经逐步在门禁、考勤、金融、公共安全和电子商务等领域得到应用。指纹识别技术是利用人类指纹的唯一性.通过对指纹图案的采样、特征信息提取并与库存样本耗比较的过程来实现身份识另q的技术. 指纹是目前最为常见的生物特征,虽然研究者对此己持续关注多年,取得了许多研究成果,但随着社会的迫切需要,以及现有技术在实际应用和测试中表现出的许多不足,*年来,对这种识别技术的研究仍然十分活跃。其中,特征提取和特征匹配作为尤为关键的研究内容,在很大程度上决定了系统的总体性能。

身份认证是人们在日常生活和工作中经常遇到的一个问题,,网络与信息化技术正处于普及应用阶段,随之而来的是身份的数字化和隐性化,这给身份认证提出了更新、更高的要求。传统的身份识别技术已经越来越不能适应社会发展的需求,人类亟需更加方便、可靠、安全的身份验证技术。

关键词:指纹,图像处理,模式识别

指纹的细节特征可以有150种之多但这些特征出现的概率并不相等,很多特征是极其罕见的.一般在自动指纹识别技术中只使用两种细节特征:纹线端点和分叉点的位置,而纹线分叉点则是纹线突然…分为二的位置大量统计结果和实际应用证明,这两类特征点在指纹中出现的机会最多、最稳定,而且比较容易获取.更重要的是,使用这两类特征点足以描述指纹的唯一性通过算法检测指纹中这两类特征点的数量以及每个特征点的类型、位置和所在夏域的纹线方向是特征提取算法的任务.

指纹比对指纹比对指的是通过对两枚指纹的比较来确定它们是否同源的过程,即两枚指纹是否来源于同一个指头.指纹比对主要是依靠比较两枚指纹的局部纹线特征和相互关系来决定指纹的唯一性的指纹的局部纹线特征和相互关系通过细节特征点的数量、位置和所在区域的纹线方向等参数来度量,细节特征的集合形成一个拓卜结构指纹比对的过程实际就是两个拓f、结构的匹配问题.由于采集过程中的变形、特征点定位的偏差、真正特征电的缺失和伪特征点的存在等问题,即使是两枚同源的指纹,所获得的特征信息也不可能完全一样,指纹比对的过程必然是一个模糊匹配问题。

1特征提取方面

指纹识别技术主要由图像采集、预处理、特征提取、匹配等几部分构成。

指纹图像是人体手指表面凸凹不*的纹线在二维*面的映像,它的感兴趣区域(ROD由一系列浓淡相间的脊线和谷线紧密排列,形成了一种*乎*行的纹理结构。要在充分分析指纹纹理特点以及ROI和背景关系的基础上,通过图像分割、滤波处理等技术尽可能消除不利因素的影响,突出手指本身固有的结构及细节特点,便于提取指纹特征。

根据上面分析,可将整幅指纹图像分为许多小块,将每一分块的纹线简化为正弦波,然后设计滤波器来滤取正弦波的频谱,就有可能得到*似于理想情况下的指纹纹线,从而达到增强目的。

当指纹图像质量较差时,许多方法有效的前提条件不复存在,也自然难以具有较好的鲁棒性。因此,进行劣质指纹增强时必须考虑两个问题:

1)如何从指纹图像中分割出无需增强和无法增强的区域?

2)如何自适应地增强指纹图像中需要增强的区域?

其中第一个问题涉及到指纹图像分割,即从整幅图像中分割出含有指纹的ROI,以

及进一步分割出无法增强的纹线区域。第二个问题是在解决第一个问题基础上,考虑如何提高增强效果。要解决这两个问题,必须深入分析指纹图像中的下列因素:纹线的方向,纹线的频率,纹线区域分割及纹线质量状况,纹线增强策略。

1.1指纹图像的方向场

指纹方向图抽象了指纹脊线与谷线交错*行分布的特征,反映了指纹图像纹理结构的本质,方向图是原始指纹图像的一种变换,即用纹线上某点的方向来表示该纹线的方向。一般有两种方向图,一种是点方向图,表示原始指纹图像中每一像素点纹线的方向;另一种是块方向图,表示原始指纹图像中某点区域所有像素点的*均方向,即表示原始指纹图像中每条纹线的大致走向。

方向场的计算方法大致可分为试探法、频域估计法和时域拟合法三类。

试探法根据指纹纹线走向性的有界性和可量化性,假定在某一方向上,纹线的评价指标将出现极值.然后通过计算极值来反求方向。

频域估计法的基本出发点是对指纹图像进行变换域分析,这种方法同样存在量化误差的问题,另外由于频域中点的方向与时域中的方向并不能严格地线性对应起来,所以该方法求取的方向仍然存在较大的量化误差和较弱的抗干扰能力。

时域拟合法主要根据区域内各点本身的方向,通过对灰度梯度等信息进行统计拟合,然后利用最小二乘原理计算得到一个主导方向。

1.2 指纹频率场

    指纹纹线在局部可视为*行条纹,其频率为纹线之间*均距离的倒数。同指纹方向信息一样,指纹纹线频率也体现了指纹的基本特征。将所有局部区域的纹线频率组合起来即构成了指纹的频率场。

目前对纹线频率的估计方法主要包括时域统计法和频域分析法两大类。时域统计法从纹线的空间位置关系出发,在已经获取指纹方向的前提下,将指纹灰度值沿纹线方向投影到其垂直轴上,统计峰谷极值之间的距离来获得纹线的*均宽度,从而确定区域的纹线频率。

 频域分析法利用了离散傅立叶变换的特点,即纹线之间的距离关系在傅立叶频谱呈现对应分布,能量会集中在较小范围内。通过时域规格化的方法,将灰度均值置零,就可以除掉频谱中的直流分量,然后通过搜索频谱中峰值来确定其频率。

1.3指纹区域分割及纹线质量评价

指纹区域分割是指去掉指纹图像的背景区域,以及纹线区域中非常模糊的部分。指纹分割不但可以提高特征提取的准确性,而且能够加快特征提取的速度,其关键在于度量指纹图像的区域特性,这种特性同时也表达了区域内的质量信息,是纹线质量评价的指标。

指纹图像的分割方法大体可分为基于灰度特性和基于方向特性两类。基于灰度特性方法的判别依据是指纹局部的灰度方差特性,该方法用每个像素点的灰度特征进行分割,速度较快,但分割边界容易出现毛刺。灰度特性方法在背景简单的情况下能够将指纹纹线很好地分割开,但是这些单一的分割策略易受采集指纹时光照、反射等因素的影响,对于灰度差不大、噪声较强的图像效果并不理想。

基于方向特性方法的判别依据则是纹线和谷线方向的一致性。该方法的分割效果依赖于所求点方向及块方向的可靠性。而对图像对比度的高低并不敏感,不受光照、光源分布及反射等的影响,自适应性能较好,能够较好地将指纹脊线和谷线分割开。但是对于模式区及纹线不连续、单一灰度等方向难以正确估计的区域,方向图分割难以取得令人满意的效果。

1.4指纹纹线增强

相对于自然界的许多纹理图像,指纹图像的纹理结构要相对单纯,在方向性和频率性方面呈规律分布。但是这种结构容易到采集噪声和手指裂纹、干湿状况等因素的影响,呈现出局部的不稳定性,表现为劣质指纹图像。劣质指纹的增强一直是指纹识别系统的重点和难点。

这些算法主要可分为基于频域、基于时域、基于尺度空间、基于知识、基于小波分析、基于神经网络等几大类。

基于频域的方法主要是对图像中每个局部分块区域进行傅立叶变换,将图像信息的空间位置表达转变为频域表达,然后选择一定方向和频率的滤波器在频域滤波,然后反变换得到增强图像。

基于时域的增强方法主要是设计一定特性的滤波器来与指纹图像进行卷积。常用的滤波器包括方向滤波器,Gabor滤波器,非线性扩散滤波器,各向异性滤波器等。

基于尺度空间的方法实际上是采用不同尺度的滤波算子对图像进行卷积,并考察由此得到的边缘点随尺度变化而具有的性质来决定边缘点。常用的多尺度算子是高斯函数的二阶导数(LOG算子)。

 基于知识的增强方法的核心思想是利用计算机来模拟人工思路进行图像增强,把人对指纹结构的认识引入到指纹处理。这类方法首先将这种先验认识以规则的形式表达,然后将指纹图像在这种引导下进行二值化,细化,并再次增强获得二值图像,接着来检测指纹特征。

  基于小波分析的方法主要是利用小波去噪的原理对指纹图像进行增强,但除了Gabor小波、Morlet小波之外,其它小波基的方向性和频率性并不显著,因此在指纹中的运用并不多见。基于神经网络的方法从原理来看,并没有充分利用指纹的关键信息,增强的效果难以达到实际要求。

   纹线增强的核心在于滤波器设计。由于指纹图象中不同区域的结构和质量差异很大,设计鲁棒的增强滤波器必须需要考虑这些因素,具有较大的挑战性。目前来看,时域滤波器和频域滤波器最为有效。

 特征提取和特征匹配是指纹识别中联系密切的两个步骤。特征提取是指经过指纹图像预处理之后,在纯化的纹线上寻找代表指纹唯一性的指标的过程,特征匹配则是在已有特征的基础上设计算法,度量来自两个特征集合的相似程度。特征提取是特征匹配的先决条件,一种具有鉴别力、利于比较的特征无疑会降低匹配时的难度。同时,由于特征的不完整性和不稳定性,利用人工专家思路,设计对特征具有鲁棒性的指纹匹配算法会使自动指纹识别具有更好的性能。此外,特征在不同情况下具有不同的鉴别能力,指纹匹配时不一定用到所有特征。

2指纹特征匹配方面   

指纹特征匹配除了与特征提取密切相关之外,一般要针对具体应用场合来设计算法。经过研究者多年的努力,指纹匹配已经取得了许多进展,目前主流的匹配方法主要分为模板匹配、图像相关、细节匹配、纹线匹配等四类。

1)模板匹配:这类方法多利用指纹的纹理信息,如比较两枚指纹的指纹及其插值改进模板等,通过计算模板之间的相似程度来得到两枚指纹的匹配结果,从而达到鉴别个人身份的目的。模板匹配方法的匹配速度较快,但建立模板常需要进行多次滤波,滤波的耗时会极大地影响登录的速度。对于许多类型相似的指纹,从宏观角度描述的模板缺乏足够的鉴别能力。

2)图像匹配:这类方法借鉴一般图像匹配的思路,找到指纹图像的参考点之后,对整幅指纹图像进行相关处理,计算其相似程度来鉴别身份。这种方法在上这种方法非常适合在线识别,但受指纹质量影响较大,需要采集者密切配合。这种方法对于形变和劣质指纹具有较明显的优势,但是匹配速度较慢。

3)纹线匹配:这类方法将纹线作为指纹匹配的直接对象,首先比较两条纹线之间的相似程度,然后计算判断其附*的纹线是否匹配,接着选取匹配程度最大的纹线对作为参考纹线,计算其它纹线的相似程度。相对于点模式匹配,这类方法判断纹线是否匹配时有很多的判断,速度较慢。在非线性形变的影响下,纹线的严格匹配关系难以准确建立。

4)细节匹配:这类方法主要利用了指纹细节点之间对应关系的不变性。点模式匹配是其中的典型代表,它首先提取指纹的细节点特征,形成特征点集,然后对输入指纹和模板指纹的细节点集进行比对,对输入指纹的细节点进行几何变换之后,寻找模板指纹中对应的细节点,在重合面积内找到的细节点数目超过一定阈值,则两者可视为来自同一手指。

 指纹的匹配过程本质上是建立输入指纹特征和模板指纹特征之间对应关系的过程。它首先依赖于上文已经提取或建立的指纹结构或纹理特征,其次取决于如何度量这些确定特征的相似程度,此外还包括针对不同情况,从模板指纹和输入指纹中建立这些特征之间的总体匹配分值。   

指纹的匹配策略可从全局和局部两方面来考虑,全局方法寻找指纹整体上的相似度,但对于劣质指纹难以给出很准的匹配分值;局部方法从指纹的局部细节出发,通过构建两幅指纹特征之间的局部相似量来判断两者的相似程度。由于非线性形变的连续性,局部结构的稳定性更高,但是对于对于不同的指纹可能存在相似的局部结构。另外,由于局部结构计算相似程度时,更易受无效区域的影响,难以给出准确的相似度分值,因此应该对这两者取长补短,建立合理的匹配策略。这种策略应该在度量来自同一特征的相似程度的同时,突出不同特征的差异。

 在这种思想的指导下,本文提出了一种基于分层鉴别的指纹混合匹配方法。这种方法和人工专家的指纹匹配思路非常类似,就是首先借助显著的全局信息来对齐两枚指纹,然后在此基础上寻找细节之间的相似性,若相似性达到一定程度,则可给出匹配结果;若全局信息缺失或可信度不高,无法对齐指纹,则改从局部结构着手,寻找局部结构的相似性,同时将这种局部结构进行蔓延,查看在已匹配的局部结构的前提下,是否有其它局部结构的支持。

2.1从全局搜索指纹的匹配特征

指纹的稳定点在很大程度上决定了指纹的拓扑结构和唯一性。因此本文以稳定点匹配来从全局搜索指纹的匹配特征。由于稳定点也是类似于细节点的点模式特征,据此,我们首先可以采用和点模式匹配类似的方法来匹配模板特征中和输入特征中的稳定点集。除了一般的处理之外,还有两点值得注意:阈值设置和匹配策略。

例如,一幅指纹图像采集到了两个吸引点,两个排斥点;另一幅指纹图像采集到一个排斥点:第三幅指纹图像采集到一个吸引点;当对前两幅指纹进行匹配时,就要记录两对可能匹配的稳定点对。对第一枚指纹和第三枚指纹进行匹配时,也要记录两对可能匹配的稳定点对。然后我们计算每一匹配的稳定点对的OrientationCodes特征的相似分值,来明确稳定点对的匹配情况。若相似分值小于一个较小阈值,则认为这一稳定点对不匹配。这一阈值可在0.25—0.65之间变化,为了减少拒识现象,本文实验中,这一阈值设为0.3。这一步的判断可剔除掉那些类型相同(比如同是左旋),稳定点之间距离接*相同,但方向模式显著不同的两幅指纹。

   接着我们着眼于模板特征和输入特征中每一匹配的稳定点,分别构建对应的星形结构.并计算星形结构的相似度分值。

最后,我们利用曲率场来作最终确认,若两枚指纹的稳定点对被准确找到,并且局部的方向模式和细节模式均己匹配,那我们要查看是否存在这种情形,即非线性形变引起了上述特征的偏移,从而导致上述的误匹配。如果曲率场的分值很低,则这是属于误匹配,否则,这种准确匹配得到进一步确认。前面各级得到的匹配分值都是两枚指纹匹配与否的证据。

 从上述过程来看,经过逐级确认,两枚指纹在全局拓扑结构和稳定点分布上的相似性在逐步明确,并且其周围方向分布模式和周围细节点分布模式的相似性也在逐步明确,那么最终的匹配分值可以由前面各阶段的匹配分值加权组合而成。

  上述全局匹配策略的优点在于:1)较好地模拟了人工专家作指纹匹配时先全局后局部的工作思路,能够统一指纹全局特征和局部特征。2)计算速度很快,这种方法在进行大规模指纹检索时优势非常突出。3)对于明显匹配和明显不匹配的指纹,给出的结果非常准确。比如两枚指纹同为环型,均有两个吸引点和两个排斥点,但两个吸引点对之间的OrientafionCodes值非常小,那么无需构建星形结构就能够判断两者的差异所在。事实上在实际系统中,对于反复使用的用户,采集的图像其实是非常相似的,这种方法具有较好的适应性。

2.2从局部搜索指纹的匹配特征

当全局方面不足以给出指纹是否匹配的明确判断时,需要从局部方面寻找指纹的相似度。这时的匹配特征主要从细节点特征展开搜索。其主要思路仍然是首先考虑全部的细节点,然后考虑到局部的细节点。

我们首先用Dalaunay三角剖分分别建立模板指纹和输入指纹的全部细节点之间的关系,然后比较对应的特征向量,计算三角剖分的相似度分值,若匹配的细节点数目很多,且匹配分值明显大于较大阈值,这时可判断两枚指纹成功匹配。或者,匹配的细节点数目不是非常之多,但在前面全局匹配中得到的匹配分值并不很小,同时Dalaunay三角剖分的相似度分值也较大(本文设为0.55),这时也可判断两枚指纹成功匹配。

然后,考虑那些Dalaunay三角剖分获得的匹配数目不多的情况,采取点模式匹配方法来获得匹配的细节点数目。为避免算法复杂度,减少误匹配现象发生,这里要估计点模式匹配的核心参数。经过对Dalaunay三角剖分建立的模板特征矢量和输入特征矢量进行比对,我们假定获得了r对成功匹配的矢量。相应地,我们能够建立模板细节点集与输入细节点集的对应关系。

 接着,我们通过分别计算每一点对的OrientationCodes特征之间和PolyLines特征之间的相似度分值,来判断这些点对是否真正匹配。然后将两者以权重组成得到匹配分值,若这个分值很小,则认为两枚指纹不匹配。若这个分值很大且得到的细节点对数目c大于一定阈值,则认为两枚指纹匹配。若C=0,则认为两枚指纹不匹配。对于其它情况,则进一步估计几何变换参数。

最后,我们估计重新组织的点对集之间的几何变换参数来得到最终的匹配结果。尽管在实际匹配过程中,模板图像和输入图像的采集传感器的分辨率大多相同。使用最小二乘法(LMS)来估计误差的极小值。这样,我们可以通过上述的估计参数来获得模板指纹和输入指纹的细节点集之间的匹配分值和匹配数目,进而做出明确判断。这样将最难确定的部分留在最后,即使发生错误也是一小部分劣质和严重形变的指纹。这样不仅可提高匹配效率,而且可提高匹配的准确程度。

3.自动指纹识别技术的发展方向

    非接触式真皮层指纹采集生理学的研究结果表明,指纹的结构在真皮层有着完整和稳定的表现.如果能实现在真皮层采集指纹结构,就可以在指纹采集技术方面实现突破,在指头干、湿、脏和指纹磨损严重的情况下都能准确、清晰、完整地进行指纹采集.通过非接触方式采集指纹,则可以有效解决指纹录入时的变形问题.

兼容主流采集设备的识别芯片的开发现在已有一些企业将自动指纹识别的核心算法进行了封装,以芯片的形式出售,这可以利用硬件提高程序的执行速度,提高系统稳定性.是值得肯定的.但几乎所有的识别芯片都存在同样一个问题:识别性能严重依赖采集设备,即一种芯片只能支持一种特定类别和型号的指纹采集设备这是非常严重的问题因为从本质上讲,指纹采集和识别技术的研究是相互独立的今天最好的采集技术未必能在明天继续领先,将现在性能摄好的指纹采集设备和水*最高的识别芯片结合起来的系统,在今天应该是最先进的系统但当更先进的指纹采集技术和设备出现时,鉴于现有芯片对采集设备的依赖性,系统很难迅速将其利用起来.所以,自动指纹识别芯片的开发应该向独立化、通用化的方向发展,具备良好的采集设备兼容性、支持主流的采集设备.这样,识别算法的芯片化才具有更大的意义,系统才具有强大的生命力.

多种生物识别技术的融合生物识别技术是一个综合的体系,指纹识别仅仅是其中的一种各种生物识别技术都具有自身的特点和优势充分利用其他生物识别技术的优势,将其他生物识别技术与指纹结合使用,实现优势互补,是自动指纹识别技术的发展方向之一比如,可以将脸形和指纹识别技术相结合,使用脸形识别结果作为一种索引,实现辨识模式下的指纹识别,识别的速度可得到明显的提高。

指纹识别技术是一项综合性的高新技术,它涉及图像处理、模式识别、计算机、光学、电子和生理等领域,是一个学科交叉性很强的研究领域.迄今为止,该技术的研究已经取得了巨大的成就,也面临着一些困难,需要光学、电子、计算机、数学乃至生理等学科的共同参与和努力,才有可能尽快将这一技术完善并实现产业化.

#include "iostream.h"
#include "math.h"
#include "stdlib.h"
#include "time.h"

#define X_h 50 
#define X_l -50 
#define Y_h 50 
#define Y_l -50 
#define NUM 100 

class Point
{
public:Point();
void Show();
double X; 
double Y; 
int Part; 

};

Point::Point()
{
X=((double)(rand()%1000)/1000.0)*(X_h-X_l)+X_l;
Y=((double)(rand()%1000)/1000.0)*(Y_h-Y_l)+Y_l;
Part=0;
if((X>=0)&&(X<X_h)&&(Y>0)&&(Y<Y_h))
Part=1;
if((X>X_l)&&(X<0)&&(Y>0)&&(Y<Y_h))
Part=2;
if((X>X_l)&&(X<X_h)&&(Y<=0)&&(Y>Y_l))
Part=3;

void Point::Show()
{ cout<<"("<<X<<","<<Y<<")"<<endl;
cout<<" Àà±ðΪ£º"<<Part<<"Àà"<<endl;
}


void Real(Point p[],Point rand_point)
{ int i;
rand_point.X=((double)(rand()%1000)/1000.0)*(X_h-X_l)+X_l;
rand_point.Y=((double)(rand()%1000)/1000.0)*(Y_h-Y_l)+Y_l;

double d1,temp_xl1,temp_xh1,temp_yl1,temp_yh1;
double d2,temp_xl2,temp_xh2,temp_yl2,temp_yh2;
double temp_x[NUM],temp_y[NUM],temp,dis[NUM] ; 


cin>>d1;

temp_xl1=rand_point.X-d1;
temp_xh1=rand_point.X+d1;
temp_yl1=rand_point.Y-d1;
temp_yh1=rand_point.Y+d1;

int k;
for(i=0;i<NUM;i++)
if((p[i].X>=temp_xl1)&&(p[i].X<=temp_xh1)&&(p[i].Y>=temp_yl1)&&(p[i].Y<=temp_yh1))
{
temp_x[i]=p[i].X-rand_point.X;
temp_y[i]=p[i].Y-rand_point.Y;
dis[i]=sqrt((pow(temp_x[i],2))+(pow(temp_y[i],2)));
k=i;
}
temp=dis[k];

for(i=0;i<NUM;i++)
{
if((p[i].X>=temp_xl1)&&(p[i].X<=temp_xh1)&&(p[i].Y>=temp_yl1)&&(p[i].Y<=temp_yh1))
{
temp_x[i]=p[i].X-rand_point.X;
temp_y[i]=p[i].Y-rand_point.Y;
dis[i]=sqrt((pow(temp_x[i],2))+(pow(temp_y[i],2)));
if(dis[i]<temp)
{
dis[i]=dis[i]+temp;
temp=dis[i]-temp;
dis[i]=dis[i]-temp;
k=i;
}

}
}

p[k].Show();


d2=(sqrt(2))*d1;
temp_xl2=rand_point.X-d2;
temp_xh2=rand_point.X+d2;
temp_yl2=rand_point.Y-d2;
temp_yh2=rand_point.Y+d2;

int m;
for(i=0;i<NUM;i++)
if((p[i].X>=temp_xl2)&&(p[i].X<=temp_xh2)&&(p[i].Y>=temp_yl2)&&(p[i].Y<=temp_yh2))
{
temp_x[i]=p[i].X-rand_point.X;
temp_y[i]=p[i].Y-rand_point.Y;
dis[i]=sqrt((pow(temp_x[i],2))+(pow(temp_y[i],2)));
m=i;
}
temp=dis[m];

for(i=0;i<NUM;i++)
{
if((p[i].X>=temp_xl2)&&(p[i].X<=temp_xh2)&&(p[i].Y>=temp_yl2)&&(p[i].Y<=temp_yh2))
{
temp_x[i]=p[i].X-rand_point.X;
temp_y[i]=p[i].Y-rand_point.Y;
dis[i]=sqrt((pow(temp_x[i],2))+(pow(temp_y[i],2)));
if(dis[i]<temp)
{
dis[i]=dis[i]+temp;
temp=dis[i]-temp;
dis[i]=dis[i]-temp;
m=i;
}
}
}

p[m].Show();

double X1,X2,Y1,Y2,L1,L2;
X1=p[k].X-rand_point.X;
Y1=p[k].Y-rand_point.Y;
L1=sqrt((pow(X1,2))+(pow(Y1,2)));

X2=p[m].X-rand_point.X;
Y2=p[m].Y-rand_point.Y;
L2=sqrt((pow(X2,2))+(pow(Y2,2)));

if(L1<L2)
rand_point.Part=p[k].Part;
else
rand_point.Part=p[m].Part;


rand_point.Show();


}
void main()
{
srand(time(0));
Point Point[NUM], rand_point;
Real(Point,rand_point);
}

原文地址:https://www.cnblogs.com/zhaoyueplc/p/3334545.html