CN1150282A - 对标准肖像图像进行压缩和解压缩的方法 - Google Patents
对标准肖像图像进行压缩和解压缩的方法 Download PDFInfo
- Publication number
- CN1150282A CN1150282A CN95121165A CN95121165A CN1150282A CN 1150282 A CN1150282 A CN 1150282A CN 95121165 A CN95121165 A CN 95121165A CN 95121165 A CN95121165 A CN 95121165A CN 1150282 A CN1150282 A CN 1150282A
- Authority
- CN
- China
- Prior art keywords
- image
- int
- block
- ptr
- feature
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Pending
Links
Images
Classifications
-
- H—ELECTRICITY
- H04—ELECTRIC COMMUNICATION TECHNIQUE
- H04N—PICTORIAL COMMUNICATION, e.g. TELEVISION
- H04N19/00—Methods or arrangements for coding, decoding, compressing or decompressing digital video signals
- H04N19/90—Methods or arrangements for coding, decoding, compressing or decompressing digital video signals using coding techniques not provided for in groups H04N19/10-H04N19/85, e.g. fractals
- H04N19/94—Vector quantisation
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06T—IMAGE DATA PROCESSING OR GENERATION, IN GENERAL
- G06T9/00—Image coding
- G06T9/008—Vector quantisation
-
- G—PHYSICS
- G07—CHECKING-DEVICES
- G07C—TIME OR ATTENDANCE REGISTERS; REGISTERING OR INDICATING THE WORKING OF MACHINES; GENERATING RANDOM NUMBERS; VOTING OR LOTTERY APPARATUS; ARRANGEMENTS, SYSTEMS OR APPARATUS FOR CHECKING NOT PROVIDED FOR ELSEWHERE
- G07C9/00—Individual registration on entry or exit
- G07C9/20—Individual registration on entry or exit involving the use of a pass
- G07C9/22—Individual registration on entry or exit involving the use of a pass in combination with an identity check of the pass holder
- G07C9/25—Individual registration on entry or exit involving the use of a pass in combination with an identity check of the pass holder using biometric data, e.g. fingerprints, iris scans or voice recognition
- G07C9/257—Individual registration on entry or exit involving the use of a pass in combination with an identity check of the pass holder using biometric data, e.g. fingerprints, iris scans or voice recognition electronically
Abstract
本发明的方法和设备可形成一组可寻址的标准化图象特征,它们代表一类选定肖像图像的特征。将所要压缩的肖像图像规范成与构成上述一组标准特征的特征有同样的大小与位置,标准化的过程还具有能使亮度平衡的特征。逐特征地比较所要压缩的图像与上述可寻址特征组中的特征并通过表示各特征地址的位而将最佳匹配的特征与所要压缩的图像联系起来。通过利用向量技术以及对多种特征均具有对称性的认识来减少实现上述表示法所需的位数。
Description
请参照构成本说明书一部分的缩微平片附件,此附件包括两张含有128帧面的缩微平片。
本申请涉及到:
Ray,Ellson和Gandhi 1993年10月29日提交的美国专利申请08/145,051,该申请题为“对磁性交易卡作图像压缩、存储和检索的方法与设备”并具有柯达摘要(Kodak Docket)第68290号。
Ray和Ellson1993年10月29日提交的美国专利申请08/145,284,该申请题为“对标准图像库进行压缩的方法”并具有柯达摘要第68291号。
Ray和Ellson 1993年10月29日提交的美国专利申请08/144,753,该申请题为“按保留值进行数据编码的方法与设备”并具有柯达摘要第68362号。
Ray.Ellson和Elbaz与本申请同日提交的柯达摘要第71412号,题为“形成标准图像模板的方法与设备”。
在允许的情况下本文以全文的方式引用了上述参考申请的内容。
本发明涉及到数字化图像压缩及解压缩这一领域。具体地说,本技术能以低于500个二进制位的方式压缩存储灰度肖像图像。
本专利文献缩微平片附件的公开内容包括了具有版权保护要求的材料。在本专利文献或专利公开刊载于美国专利和商标局的专利文件或记录中时,上述材料的版权拥有者并不反对本专利文献或专利公开的任何一部分进行复制,但在任何情况下都保留所有的其它权利。
一般地说,图像压缩力图降低图像的存储量要求。解压缩是对图像进行恢复。并非所有的压缩/解压缩过程都能将图像恢复成原本的形式。能做到完全恢复的称为“无损耗的”方法。一般地说,无损耗的方法不会象会改变图像且使图像质量降低的有损耗方法那样高度地压缩图像。在希望有高压缩率的应用中,最经常使用的是有损耗的方法。
在图像包括有空间上的相关性时,可以对这些图像进行压缩。上述相关性是指在大多数情况下相邻像素值之间的差异比图像的动态范围要小。基本的经验法则是:相关性越大意味着在不损失视频逼真性的情况下更有可能有较高的压缩率。大部分图像压缩法均有广泛的统计测度基础。某些方法更复杂并且使得压缩算法因局部统计法而异(见M.Rabbani和P.Jones的“数字图像压缩技术”VolT77,SPIE Press.Bellingham,Washington,1997)。但是,由于不存在有关图像特征和图像位置的预备知识,所以,上述所有技术均应用于整个的图像。上述统计工作计算出相邻像素之间的相关性,但这些统计并不计算不同图像相应位置处的像素组之间的相关性。
业已研制了多个算法以处理诸如电影顺序帧之类的图像运动序列(见Bernd Tahne的“数字图像处理:概念、算法及科学应用”,Springer-Verlag,Berlin,1991)。按很接近的时间所抓取的图像之间具有较高的相关程度,并且,随着图像片段的运动去测度图像之间的差异可以导致较大的压缩率。对具有递增失真的图像来说,上述类型的图像对图像的相关关系具有很好的效果。
其它类型的图像具有图像对图像的相关关系,但未达到运动序列所具有的程度而无法用运动算法很好地的压缩。以失踪儿童的照片库为例。对这类图像来说,由于脸部具有某些共同的特征,所以存在有基于像素位置的图像对图像的高度相关性。可以象利用给定图像中空间相关性那样利用不同图像间的这种相关性以改进压缩。
对某些图像库的分析可以认识到以图像位置为基础的图像逼真度的相对重要性。的确,保持儿童脸部的高度逼真要比保持儿童头发或肩膀的逼真性更重要,而头发或肩膀的逼真性又要比背景的逼真性重要得多。在视频图像逼真性不太重要的区域处可进行更大程度的图像压缩。
在许多应用中,保持原始图像的方向和量化不如保持该图像内所包含的视觉信息那么重要。具体地说,对失踪儿童库内的图像来说,如果能与原始图像或经过处理以利压缩的图像同样容易地确认肖像中儿童的身份,那么,在将处理过的图像放入照片库中时就不存在损失。可以利用这一原理通过将原始图像转成标准格式来建立经过处理的图像库。对失踪儿童的肖像来说,包括让每个儿童的头部定向以使眼睛处于水平方向并使头部相对图像的边界居中。这些标准图像一旦建立起来就能被充分地压缩,这是因为,对它们标准化的认识会增加图像对图像的相关性。
来自称为向量量化(VQ)的压缩方法中的技术在查找图像部分之间相关性方面是有用的。通过向量量化VQ来进行压缩特别适用于固定比例、有损耗的高压缩率的压缩应用(见R.M.Gray的“向量量化”,IEEE ASSP Magazine,Vol.1,1984年4月,PP.4-29)。这种方法将图像分成小块的“图像块”。然后将这些图像块与通常称为码本的预定图像块集合中的其它图像块相匹配。匹配算法通常是最小平方误差法(MSE)。由于所说的图像块集合是预定的,所以,用简单索引就可引用该集合中的一个项目。因此,用一个号码就可引用一个多像素的图像块。利用这种方法可以预算出用于一个图像的位数。当每个图像块分配了较多的位数时,可以增加码本的大小或者使图像块的大小变小。
在先有技术中,码本是由称为训练集合的一组多个典型图像所构成的。将图像分成图像块,然后将图像块看作是多维向量空间内的向量,例如,对一8×8的图像块来说,向量空间为64维。从图像训练集合的每个图像中选定图像块。一旦从训练集合中确定了所有的向量,就可找到族,并且,将典型元素赋给各个族。选择所说的族以使多个训练集合与用于将号码所赋给的族的典型元素之间的整个复合距离最小化。选择技术为Linde-Buzo-Gray(LBG)算法(见Y.Linde等人的“一种用于向量量化器设计的算法”,IEEETransaction On Communications.Vol.COM-28.No.1,1981年1月PP84-95)。可用为说明图像块所预算出的位数来确定族的数量。假定为n位,则编码表包括多达2n个族代表或码向量。
以上所引用的专利申请即Ray,Ellson和Gandhi等人的美国专利申请第08/145,051号以及Ray和Ellson的美国专利申请第08/145,284号均说明了这样一种系统,它利用图像库中的标准化特征以最小的图像质量损失实现非常高的压缩率。
上述专利申请说明了用来抽取图像库中图像共同特征的过程并且将这一过程用作图像标准化的基础。一旦图像被标准化成一标准的库图像,就可对该图像进行压缩,以后可将该图像解压缩成有损耗的原始库图像的再现图像。
以上所引用的专利申请中的大致内容包括:
标准化:
选择最重要的图像特征。
处理一组来自图像库的典型图像以增强所选定的特征。
测出所选定特征在典型图像内的位置。
确定对图像特征位置的约束条件。
处理所说的图像以满足图像特征位置的约束条件。
根据出现的特征或所要求的图像质量水平确定图像的各个区域。
确定各个子区域的图像对图像的图像相关性。
根据将子区域分成图像块的分块情况和码本大小来分配用于存储每个子区域的图像信息的空间。
构造码本以便利用所说的相关性。
处理所说的图像以增强特征。
在图像中定位选中的特征。
通过处理所说的图像以满足图像特征位置的约束条件,从而使得该图像标准化。
根据所说的子区域及其图像块来划分图像。
对每一个区域来说,确定码本内最接近图像的项。
将一组用于各个图像块的码本值存储起来,这是因为,它们就是压缩后的图像。
解压缩:
从上述一组码本值中抽取码本的值。
根据上述一组码本值中相应子区域的位置来确定码本。
根据码本值从以上所确定的码本中抽取图像块。
将上述图像块拷贝至所说子区域内的适当图像块位置。
继续插入图像块直至整个图像内的所有图像块位置均被填满。
为了能够以与单磁道磁性交易卡的国际标准相一致的方式存储压缩后的脸部图像,压缩后的脸部图像数据必须低于500位(见ISO7811)这一容量还兼顾了为进一步减少磁道的位容量而存在的若干保留字符。在Ray和Ellson于1993年10月29日提交的题为“用于带有保留值的数据编码的方法与设备”的美国专利申请第08/144,753号中,对每一个451位的磁道来说,数据范围具有信息论上的最大存储容量。上述申请还说明了用于存储442位无约束数据的编码方法。
当目标位数非常少时,如在按442位进行脸部图像存储的情况下,上述压缩/解压缩过程就无法提供一致质量的脸部图像。在试图由图像来确认一个人时,最好有一致的图像质量。对要求更高的检验系统来说,还需要在压缩后图像的质量方面作其它的改进。具体地说,在码本形成、图像标准化以及图像块对称性方面存在着改进的可能性。
以往的压缩方法通过所谓的LBG算法而利用了基于训练的码本形成过程。上述算法是称为聚类算法这类算法中的一种。该算法的特点是找出一数据集内预定数量的类并以最佳的方式选出该类的一个代表。就LBG算法而言,所说的数据集包括来自多个图像的像素块,并且,该算法的操作可找出预定数量的最能代表所述数据集的像素块。在有多种尺度去衡量什么是好的情况下,最通常的一个尺度就是欧几里德意义上的最小距离即像素之间平方差之和。一个类的代表通常是该类的形心即该类中像素块的均值。LBG算法首先分类,然后选出每个类的形心,再通过选出最近的形心将数据集的元素重新赋给形心。重新分类会形成新的类,并且,该算法以迭代的方式继续直至出现收敛。
在多数情况下,只要类的数量始于特定的数目,重新分类的过程就会减小类的总数量。其结果是次优的,因为,增加另一个类会有更好的整体结果。所以,最好有一种用于保持有效类数量的方法。另一种可能出现的问题是一个类可能减小成具有很少量的成员。在一个类只有一个成员的情况下,所说的形心就是这个成员,因而该成员与其形心之间的距离为零,从而仍存在有所说的族。结果是,某些类较大,并且,通过分裂一较大的类而获得较好的总体结果。
最佳的方法是通过计算类的数量来保持有效的类数,并且,对每个类来说均测定其范围即该类的直径,同时,如果某些类没有成员,则将最大的类分裂成两个较小的类。通过把过小类的数据元素看作是分离元素并将这些元素从数据集中剔除,可以处理这些类的问题。必须谨慎地进行这一过程,否则的话,会丢掉过多的数据元素。
脸部图像中相关性的一种类型是脸部左右两侧之间的近似镜像的对称性。通常在近似正面的透视肖像中,靠近中心线的脸部之间有较大程度的相关性。具体地说,用于表现脸部位于眼睛上方和下方部分的图像块具有较高程度的对称相关性。但是,在从略有不同的角度来观察时,由于鼻子的外观的变化,对称程度会沿面部的中线降低。需要的是这样一种方法,它能够在不对鼻子进行不利于对称性的约束的情况下通过利用人脸在脸部中线周围区域的自然对称性而进一步减少存储压缩肖像图像所需的位数。
尽管人脸的几何形状具有固有的对称性,但肖像的光照条件可能是很不对称的。这就会导致人脸肖像左右两侧亮度失衡。所需要的是这样一种方法,它用于平衡人脸肖像的亮度以便使得脸部图像肖像高度标准化并提高人脸图像的自然对称性。
通过对亮度及图像特征位置的标准化,可以得到专门的码本以便在图像的特定位置处表现预期的图像内容。Sexton在题为“视频图像处理”的美国专利第5086480号中说明了一种使码本专门化的方法,在该专利中,说明了对两种码本的使用。上述方法通过彻底搜索码本而从两个码本中找出最佳的码向量,然后标记在其中找到最佳匹配的那个码本。最终的结果是一“超级码本”,该码本中包含两个由可能为不同的码向量数目构成的码本,在所说的超级码本中,前述标志指示出所选定的码本。码本的选定并不源于一部分图像特征的先有知识,Sexton计算出将哪个码本用于各个图像内的每个码向量。较大规模的压缩可能性是要消除存储码本标志的需要。
肖像图像的某些部分对确认一个人来说并没有显著的价值。例如,肩膀部分对确认过程来说具有最低的价值,而且,这一部分通常被衣服所覆盖,而衣服即便是对同一个人来说也是经常变化的。由于这类区域具有较低的价值,所以,也可以减少用以对图像进行编码的位分配。在本发明中,即使需要也给某些这类区域分配少量的位,并且,用相邻图像块的图像数据来合成这种图像数据。这样就能用较多的位分配去对更重要的部分进行编码。
本发明的最佳方法之一是这样一种方法,它用于形成一组可寻址的图像特征,这些特征体现了一类选定数字图像类中的特征,所说的方法包括下列步骤:
a.使来自选定类的数字图像标准化,以便将至少一个预期的特征置于标准的方向和位置上;
b.确定上述选定类中标准图像所代表的特征的预期位置;
c.从上述选定类中标准图像内抽取出图像内容,该内容出现在用于每一特征的预期位置处;以及
d.根据步骤c所抽取出的图像内容为每一特征形成一组可寻址的相同特征。
本发明用代表一类选定图像的码向量来形成一组可寻址的图像特征的设备实施例包括:
用于为选定类的图像建立标准的装置,所说的标准包括选定图像特征的最佳部位。
用于测出各选定类图像内至少一个选定图像特征位置的装置;
用于处理每个特定类的图像以形成标准几何图像的装置,其中,根据所建立的标准使至少一个特定的图像特征定位;
用于从上述标准几何图像中抽取特征块的装置,所说的每个特征块均表示一有意义的图像特征;
分组装置,它用于将所有相同的特征块聚集成一组;以及
利用表示上述各组的码向量来为每一组均形成一组可寻址的图像特征的装置。
本发明总的目的是提供一种用来形成脸部图像的技术,所说的图像具有足够的质量并可用于确认交易卡的持卡人。本发明可以压缩、存储和检索肖像图像,其中,正如国际标准所规定的那样,压缩后的肖像图像数据可存储在交易卡的单一磁道内。本发明通过下列方式对先有技术中压缩方法进行了改进,即增加了用于生成码本的改进训练方法、用于使脸部图像的光照条件标准化的亮度平衡法、以及用于脸部对称区域的链式图像块。
从以上内容可以看出,本发明的主要目的是用最少量的位对肖像图像进行编码。
本发明的另一目的是提供一种解码技术以便对编码后的图像进行快速解码。
本发明的再一目的是提供一种经过改进的编码肖像图像。
本发明的又一目的是能够在编码过程中剔除图像无意义的部分。
本发明的还一目的是提供这样一种技术,它能够在缺乏实际图象数据的情况下插入可能的图像内容。
参照下列说明及附图,可以更清楚地看出本发明上述及其它特征,在附图中,相同的字符代表相同的部分,并且,附图构成了本发明公开的一部分。
图1以框图的形式概述了本发明的处理流程。
图2A、2B和2C说明了分别为倾斜的、旋转至标准位置的以及调整至标准尺寸的正面脸部肖像。
图3以流程图的方式说明本发明的标准化的方法。
图4A显示了模板内模板元素的位置及大小。
图4B用阴影区来说明了上述模板内具有自左向右翻转属性的模板元素的位置与尺寸。
图4C用阴影区来说明了上述模板内具有自顶向下翻转属性的模板元素的位置与尺寸。
图4D用阴影区来说明了上述模板内相链接的模板元素的位置与尺寸。
图5以表格的形式说明了本发明特定实施例中模板内肖像特征及其特点。
图6A和6B说明了本发明特定实施例中模板内用于每一元素的模板元素数据记录。
图7以流程图的方式说明了构造本发明之码本的训练方法。
图8说明了一组码向量,这组码向量与本发明上述特定实施例中所使用的各个特征类型有关。
图9A以流程图的方式说明了进行压缩的模型。
图9B以流程图的方式说明了构造压缩位流的方法。
图10说明了对压缩后图像进行码向量编号和标记。
图11说明了图像的压缩位表示法。
图12说明了带有数据有储装置的交易卡。
图13A和13B以流程图的方式说明了本发明的解压缩方法。
图14说明了从特征类型码向量集合中抽取出的码向量以及具有至少一种翻转属性的轻阴影的码向量。
图15说明了实现所有翻转属性之后的码向量。
图16说明了最终的图像。
图17说明了实施本发明方法的最佳系统结构。部件清单
10训练图像
12标准化装置
14特征模板
16训练器
18码本
20标准化图像
22压缩器
24压缩后的图像
26解压缩器
28解压缩后的图像
30-54(只有偶数)操作块
80照片
82负片
100设备
102装置
104扫描仪
106转换器
120交易卡
122存储区(多磁道)
200工作站
202显示器
204键盘
206鼠标
208CD阅读机
210CD记录机
212打印机
214调制解调器
216交易卡记录机
330-336(只有偶数)操作框
700-730(只有偶数)操作框
900-922(只有偶数)操作框
950-970(只有偶数)操作框
A-M模板元素
图1中的框图给出了本发明的功能概况。在图1中,将一组训练图像10装入一规范器12内,规范器12将训练图像10加工成具有一致格式的标准训练图像。利用特征模板14进一步处理标准训练图像以生成训练图像块,这一功能由训练器16来表示。训练器16可形成码本18,该码本包括了基于训练图像块的码向量。上述码本与特征模板14相配合构成了压缩和解压缩处理的基础。利用规范器12的功能由诸如肖像之类的原始图像形成诸如标号为20的标准图像。在把要进行编码的标准图像20传送给数据压缩器22时,该压缩器会产生压缩的图像24。然后存储或传送压缩后的图像以供将来使用。由解压缩器26象在压缩器22中使用的那样利用同一特征模板和编码表数据所进行的解压缩过程能提供解压缩的图像28。
图2A显示了正面脸部肖像的图像。在这一图像实例中,脸部是倾斜的并偏离图像的中心(不对称)。根据图像来源的不同,脸部在图像内会有位置及尺寸方面的其它变化。为了能用本发明取得最大的效果,就要对脸部的尺寸、位置和方向进行标准化。为了能够处理图像,应将该图像转化成作为一个像素值矩阵的数字格式。可通过扫描和/或其它周知的数字化处理技术来获得图像的数字格式(像素值)(不是本发明的内容)。然后在诸如图17所示的显示器202之类的显示设备上将数字化图像显示出来,并且,利用标准化过程形成标准化的几何图像。对图像进行标准化以便在与特征模板14(本说明书的后面将予以详细说明)相关的模板元素之间进行质量匹配。这一过程通过确定图像对象左右眼中心的位置而从图2A的图像开始进行。在图2B中,通过在必要时旋转和平移图2A的原始图像来形成一新的数字化图像即部分标准化了的几何图象。利用周知的图像处理操作在软件内实现上述旋转与平移以使得左右眼的中心沿预定的水平轴定位并围绕一中心垂直轴等距地间隔定位。图2C说明了图2B经缩小过程进行尺寸调节从而形成了标准化几何图像的图像。
参照图3,在流程图的左面一列中说明了用于形成标准化几何图像的处理流程,流程图的左面一列始于操作框30,它标记为“选定图像”以说明自身的功能。根据功能对图中所有的流程框加以标记。上述选定过程是一种以存在有人的正面脸部图像为基础的选择过程,也就是说要用模板14进行处理的图像。选定过程还包括创建图像的数字化矩阵表示。然后在操作32处将数字化矩阵装入用于显示给操作人员的系统(见图16中的系统)。如前所示,操作人员在操作34处确定左右眼的中心并通过操作36对该图像的脸部作任何必要的旋转、平移和改变尺寸操作以便形成标准化的几何图像。然后,通过操作38将标准化的几何图像存储起来。
具体地说,在本发明的上述实施例中,将图像的标准几何图形设置成宽为56个像素、高为64个像素、眼睛中心距图像顶部28个像素且位于假想垂直中线两侧8个像素位置处的图像。通过将初始图像显示给操作人员而确认左右眼睛的中心,操作人员用光标指出左右眼睛的中心,而光标则是由诸如鼠标、数字化书写输入板、光笔或触摸屏之类的设备来驱动的。另一种方法是用特征搜索程序自动地进行这种处理。在一个实施例中,操作人员确定眼睛的位置,并且,一处理器利用查找眼睛的搜索法对限定在操作人员所指定的部位周围很小区域内的眼睛位置进行微调。
在调整了图像大小及眼睛位置之后,就进行亮度标准化。在框图的右侧标号为40-54这一列中,处理标准几何图像的亮度以便减小图像对象在可察觉到的光线方面的变化、减小反射强光、将皮肤色调调节成预定的值并且减少阴影,同时将最终的标准几何图象存储起来以供将来使用。有三种空间尺度可用于规范训练图像亮度方面的变化:大的用于光的强度/方向,中的用于修正来自侧光的非对称阴影、小的用于减小来自眼镜、珠宝和皮肤的反射强光。上述过程会改变图像的平均亮度。还可以调整称为对比度的亮度变化以增强某些在确认容貌过程中有用的特征,但在将彩色图像转换成灰度图像时会减弱上述特征。
图像标准化过程在存储之前的最后一步是将脸部的平均亮度即鼻子附近的平均亮度转换为预定的值。在本发明的最佳实施例中,就浅皮肤色调的人而言,预定值为165,就中间皮肤色调的人而言,预定值为155,就深皮肤色调的人而言,预定值为135。这样,所形成的标准化数字图像可由一个可存储的像素值矩阵来表示。
图4A说明了要供标准图像使用的模板14的结构。模板14分成标记为A至M的64个模板元素。这些元素按人脸的13个相应特征排列,例如,标记为A的模板元素对应于头顶处的头发的特征,标记为G的模板元素对应于眼睛。图5、图6A和图6B中的表对其余的模板元素进行了说明。尽管本发明的最佳实施例是按64个模板元素和13个特征来实现的,但是,应该认识到,这些数字是可以改变的以便适应情况,并且,这些数字并不对本发明的方法构成限制。还应注意,模板的某些区域没有分配给任何的元素。这些未作分配的区域不具有以从码本中进行信息检索为基础的图象内容。用于将图像内容分配给这些区域的方法以分配以下将予以说明的相邻区域为基础。模板的大小与宽为56个像素高为64个像素的标准图像的几何形状相匹配。模板元素的尺寸以模板元素所要表现的脸部特征的尺寸为基础。例如,元素G大小与标准图像中的眼睛成比例,并且,元素G的两个实例位于标准图像中眼睛的位置处。
参照图4B,暗阴影的模板元素具有自左向右的翻转属性,以后将对该属性作详细说明。
参照图4C,暗阴影的模板元素具有自顶向下的翻转属性,以后将对该属性作详细说明。应该注意,可以使模板元素有一个以上的属性。
模板的另一个属性是链接。图4D用暗阴影区域显示了作为链路一部分的模板元素的位置。在这一特定实施例中,有7个链接元素对。每对阴影模板元素之间的链接均为水平的,例如中心左侧的元素G与中心右侧的元素G相链接。尽管作为最佳实施例示出了7个链接元素对,但也可在多于两个元素的组合中形成链接,也可在任何一组具有相同标记的元素之间形成链接。
正如所看到的那样,模板14包括一系列模板元素,它们表示一系列数据记录,其中,在所说的最佳实施例中,每个记录均用来说明位置、大小、标记、自左向右的属性、自顶向下的属性以及链接。在需要时也可创建带有其它和/或附加因素的记录。
模板14记录了模板元素的分布和大小。每个模板元素均具有一码本18(见图1)以及与图像相对应的空间关系。如前所述,模板14包括64个由矩形像素区构成的模板元素。这些模板元素分配给13个不同码本中的一个,每一个码本都对应于一个不同类型的脸部特征。码本18是大小均匀的码向量集合,而码向量则为4×16、8×8、8×5、4×10、4×6或8×4个像素。填充码本18的码向量是训练器16(图1)根据抽取自训练图像的图像块生成的。
在图5中,表格说明了图4A至4D所示的模板元素A-M的属性。码本中列出的第一个属性是该码本所包含的码向量数,该数值为128或256。这两个数值均为2的幂,具体地说,它们是27和28。这在用于指定码向量的码本索引使用所有7位或8位索引时是有优点的。在图5的表中,码本的索引长度为8或7。用于码向量的图像块的大小是列出的第二个和第三个属性并给定为按像素的块宽和按像素的块高。每个图像块的像素数是上述块宽与块高的积。列出的第四个属性是上述特定实施例的特征模板内分配给码本的模板元素出现的次数。唯一属性是列出的第五个特征属性,它表示可以唯一地选择多少个模板元素(即删除每对链接的模板元素中的一个成员)。列出的第六个特征属性是为存储从码本中选出的码向量而分配的位数。该位数是唯一的模板元素数与索引长度的位数的乘积。特征位那一行中各项目的和为442,该数字是将压缩图像存储为一无限制的二进制记录所需的总位数。因此,特征模板承载有建立图4A至4D的图及图5中表格所需的全部信息。图6A和6B中的表格以数据的形式表示了图4A至4D的图。
参照图7所示的训练器16的操作流程,第一个操作框即操作框700表示装载标准的训练图像。训练图像是一组认为能反映出肖像图像特征的图像,而肖像图像则传送给压缩器22以便用上述训练过程所形成的码本18来加以压缩。如操作框702所示,首先为选定的码本类型从图像中抽取图像块。然后,根据抽出的图像块诸如上述自顶向下和自左向右的翻转属性之类的对称类型使这些图像块定向。这一过程如框704所示。下一个操作框即判别框706检查是否在标准图像训练集内有其它图像存在。一般地说,对这一训练过程来说,推荐用2000个图像。如果在上述训练集内有其它的图像,则该过程如图所示循环返回至框702。否则,该过程继续至框708,在框708处,将形心初始化为随机的图象块。在所说的最佳实施例中,将形心初始化为第一序列的图像块。参照框710,将每个图像块均分配给在框708中所确定的最近的形心。在框712中,合并比一定阈值更加彼此接近的形心。例如,如果确定出两个形心有小于预定的距离,则将它们标记为太靠近,在这种情况下,合并这两个形心,并且,将所有的图像块都分配给一个形心,对另一个形心不作分配。参照框714,用未分配的形心分裂大范围的形心。这意味着,如果一个形心在分配给该形心的不同码向量之间有很大的距离,则将该形心分成两个形心,其中,新形心中分配给上述码向量的那个形心来自前一步骤中未作分配的形心。在框716中,对占用最少的形心不作分配,然后利用该形心分裂业已认定属范围较大的其余形心。在框718中,将最靠近的形心合并到一起。在框720中,再次利用合并过程所形成的新的未作分配的形心去分裂更多的大范围形心。参照框722,为每个形心寻找新的位置。之所以需要这一过程是因为,在改变将图像块分配给不同形心的情况下,分配给形心的码向量的中心位置已在实际上发生了变化。计算出分配给每个形心组的成组码向量中心的新位置以确定如何通过图像块重新分配过程来移动形心。参照框724,将每个图像块分配给最近的形心,由于形心已移动了约一位,所以,某些业已分配给一个形心的图像块在实际上更靠近另一个形心。
参照框726,按最多到最少的占用情况重排所说的形心。这种重新排序会在以后的选代操作中提高重新分配过程的速度。在框728中,进行收敛测试,如果尚未收敛,则该过程会返回至框712,在框712处合并太接近的形心。如果业已完成了收敛,则该过程前进至框730,在框730处将形心存储为新形成的码本的码向量。
在图8中,详细地示出了用于码本的部分码向量,这些码向量对应于特征类型A、G和M。请注意,图8中的特征元素G123对应于图3、图4A至4D、图5和图10中模板的左右眼睛元素。同样,图8的模板元素A46对应于图3、图4、图5和图10所示的模板左上角内的头发。
图9A以流程图的方式说明了为图像的各种模板元素查找最佳匹配码向量的过程。如框900和框902所示,上述过程始于装载标准化图像或装置要予以标准化的图像。标准化的图像对应于图1的框20并且是框902所表示的过程的结果。
在框904中,从标准图像中抽取出对应于第一模板元素的下一个图像块。然后,如框906所示,根据水平翻转和/或垂直翻转属性的对称类型来使抽出的图像块定向。在框908中,通过比较图像块与码本内对应于模板元素特征类型的所有码向量,从而从码本中查出最佳匹配码向量的索引。比较框910根据存储在模板内的信息确定图像块是否是链接的。如果是链接的图像块,则流程前进至框914,在框914处,将表示匹配优良度的值存储起来。在本发明的特定实施例中,尽管能很容易地想到其它优良度测度,但将两个图像块与码向量之间的均方差比较用作匹配优良度的测度。在框916中,正如在上述最佳实施例中那样,将来自匹配的值与类中的其它链接块相比较。在框918中,选择带最佳值的码向量,在本例中,最佳值是均方差检验的最低值。然后,在框912中将上述向量用作来自码本的最佳匹配码向量的索引。如果图像块不是链接的,则流程直接前进至框912。流程从框912前进至框920,框920是一比较框,它用于确认元素是否是模板中的最后一个元素。如果不是,则流程返回至框904并抽取对应于下一个模板元素的下一个图像块。如果是最后一个图像块,则流程继续以便在框922内创建压缩图像的位流。图9B说明了该创建过程。
参照图9B,在框950中将位流指针BSP设置为零,将模板元素指针TP也设置为零。在框952中,检索模板元素号TP。框954是判别框,其中判断模板元素是否链接的。如果未链接模板元素,则流程继续至以下将予以说明的框958。如果是链接的模板元素,则流程继续至第一判别框956以确定该模板元素是否是链接组中的第一次出现,如果该模板元素是链接组中的第一次出现,则流程继续至以下将予以说明的框958,如果模板元素不是链接组中的第一次出现,则流程继续至以下将予以说明的框966。
参照框958,从模板元素中检索出若干位,这些位标记为“BN”。所说的位用来对模板元素的码向量索引进行编码。在前述最佳实施例中,每个模板元素有7或8位。流程继续至框960,用BN位对码向量进行编码。
在框962处,插入起始于位地址BSP处的多个位BN。在框964处,使位流指针BSP加BN,在框966处,模板元素指针加1。判别点968查询是否已用尽模板元素,如果“是”,则位流在框970处结束,如果“否”并且还存在有模板元素,则流程循环返回至框952并且继续进行。
图10说明了图9A和9B中所述的最佳匹配码向量比较过程中的特定标准图像的结果。在图10中,每个模板元素均赋有字母和数字。字母表示与该模板元素相对应的特征类型,数字表示最佳匹配码向量按具体的优良度测度的索引。
图11的表格显示了对应于图6A和6B表格中所示的模板元素序列的最佳码向量号,表中的号码自左列到右列从上向下地顺序排列。重要的是保持模板元素的顺序与图6A和图6B相一致,以便图9B所示的过程能具有可正确说明压缩图像位流的位流指针。图11中所示的各最佳码向量号的索引长度对应于图5所示表格中作为索引长度的特征类型的索引长度。在位表示栏中将最佳码向量号的表示显示为二进制数,这种位表示的长度等于索引长度。在上述二进制数没有足够的位数的情况下,则填充先行零以便二进制数的长度等于该二进制位表示的前一栏中的索引长度。如果位表示栏中的二进制数字是按序的,即始于左侧的栏目并向下继续然后进入右侧的栏目,则最终的442位二进制数会对应于最后输出的压缩图象。该数对应于图1中的压缩图像24。
图12说明了一带有数字化存储装置的交易卡120。这种存储装置是由诸如磁性编码装置或条码装置之类的多种装置形成的。就磁性存储器而言,通常的方法是使磁性存储区122有如图12由磁道1、磁道2和磁道3所示的多个磁道。
参照图13A。在图13A中,对压缩的位流进行解压缩以形成解压缩的图像。在框302中,将位流指针BSP初始化为零并且将模板元素指针TP置为零。流程继续至框304,在框304中检索模板元素指针TP。在框306中,判别是否模板元素是链接的。如果未链接,则流程继续至框310。如果是链接的,则流程继续至判别框308。判别框308判断是否是链接组中的第一次出现。如果是,则流程继续至框310。如果否,则流程继续至框312。
参照框310,从模板元素中抽取出用于码向量索引和编码表类型的位数BN。在框314中,从压缩位流中抽出从BSP到BSP+BN-1的位。在框316中使位流指针增加BN。然后,流程进入框318。参照框312,在存在有不是该组的第一次出现的链接组时,就复制来自该组的上一次出现的码向量索引。将先前的出现移至框318。在框318中根据指示出的码本类型检索索引码向量。这一码向量代表来自特定图像的特征类型。所说的模板元素指示如何使图像块定向。在框320中,使图像块如模板元素所示的那样定向。如有指示,进行水平自左向右的翻转或垂直自顶向下的翻转。在框322中,将模板元素所示部位处的图像块插入图像。在框324中,使模板指针TP加1。判别框326测定是否已使用了所有的模板元素。如果没有,则流程返回至框304并且继续进行。如果已使用了所有的模板元素,则流程进入图13B中的点A。
在图13B中,显示了用于建立索引的流程。该流程构造未分配有模板元素的区域。在框328中,将可能的像素用于上述区域。框330中的图像块之间具有接合痕迹,必须要修匀这些痕迹,框330表示了这一过程。利用整个接合痕迹的平均值来水平和垂直地修匀这种痕迹。在框332中,增加重建图像的对比度。这一点是通过证实在重建图像中使用了图像的所有动态范围0-255而实现的。在所述的最佳实施例中,这一点是通过简单的线性重新定标而实现的。在框334中,增加与空间位置有关的随机噪声。这项工作是在图像的中心不是很重要并且边缘处的噪声非常显著的情况下以图像的中心为基准进行的。在框336处输出重构的图像。输出的图像对应于图1中框28的解压缩图像。
图4B和4C分别显示出了哪些模板元素具有自左向右和自顶向下的翻转属性。在图6A和图6B的表格中还用TRUE/FALSE(真/假)标志来指示具有上述翻转属性的模板元素。在图14中,用代表像素的方块内的斜线来表示要进行翻转的码向量。图15显示对图14中的码向量作用了翻转属性,其中图14中对应于图4B中画黑点的模板元素的所有码向量均自左向右翻转,图14中对应于图4C中画黑点的模板元素的所有码向量均自顶向下翻转。应该注意,某些模板元素在使来自图14的码向量变换至图15的码向量方位时会进行上述两种翻转,并且,会在相关的元素内产生翻转。
下一步是通过图像处理操作根据图15的定向码向量的镶嵌结构来形成图16所示的最终图像。图15中的镶嵌结构由于是由码向量构成的,所以可能具有某些在视觉上令人不舒服的人为现象。利用图像处理算法的某种组合,可以消除这些人为现象。
在上述最佳实施例中,所采用的周知图像处理操作的组合包括修匀码向量的边界、提高对比度、进行线性插入以填充遗漏的图像区以及增加与空间有关的随机噪声。以三个连续的像素P1、P2和P3为例来说明修匀操作,其中,P1和P2处于一个码向量内,P3处于相邻的码向量内。用下式的结果来替代像素P2:
(P1+2*P2+P3)/4
通过确定镶嵌结构的最小像素值min和最大像素值max可以提高对比度。可用下式中的Pnew来替代镶嵌结构的每个像素值Pcur:
Pnew=255*(Pcur-min)/(max-min)
用线性插入法填充特征模板不与任何模板元素相对应的区域。对每个区域来说,用边界像素的已知值来计算出平均像素值。将已知边界的未知对角置成上述平均值。用线性插入法来计算未作分配的内部像素的其余部分。在本发明的特定实施例中,有四个这样未作分配的区域,每个区域均位于特征模板的角上。
所增加的在空间随机噪声取决于下式:
V=噪声的大小
其中,i=受影响的像素的列
j=受影响的像素的行
rand是一伪随机的浮点数,范围是(-1,1)。将值n(i,j)加给位置(i,j)处的像素。如果最终的像素大于255,则将该像素减小至255,如果该像素小于0,则将该像素置为0。图16显示了经上述操作处理之后的图像。应该认识到,在其它情况下也可以使用其它图像处理操作,不应将所说的最佳实施例视为限制性的。
图17说明了实现本发明方法的设备100。设备100包括装置102,它用于将诸如照片80或负像82之类的非数字化图象转换成图像的数字化表示。通常,用扫描仪104实现上述转换,扫描仪104能输出以模拟形式表示像素值的信号。然后,用模拟-数字转换器106将上述模拟像素值转换成表示扫描图像的数字值。可将其它数字图像源直接输入工作站200。在本发明的最佳设备实施例中,工作站200是SUN SPARC10,它以UNIX为操作系统用标准C语言编程。附件A-E全面说明了本发明的程序部分。借助于软件,键盘204和鼠标206的控制通过显示器202显示出数字图像。也可利用CD阅读机208或其它类似的设备使数字图像进入系统。用本发明的方法和设备所创建的模板可下装至CD记录机210以便存储到CD盘上、下装至打印机212所打印的硬拷贝上、下装到交易卡记录器216以便在交易卡的数据存储区内进行编码、或者用调制解调器214和传输线加以传输以便在远距离处进行处理和存储。优点
本发明的优点是:
可显著地减少表示压缩图像所需的位数。
通过减小皮肤平均亮度因图像而异的变化能使得码本在脸部区域内提供最佳匹配图像块。
利用链接的模板元素可在不增加存储压缩图像所需的位数的情况下改进图像质量。
能根据相邻模板元素重构与任何模板元素不关联的图像区。
通过改进后的训练过程提供高质量的码本。
尽管示出了本发明的最佳实施例,但是,很明显,在不脱离本发明实质精神的情况下可以形成多种改型和改进。所以,后附权利要求书涵盖了所有属于本发明真正范围的改型和改进。
p.1 Standardized Geometric Image Generator Appendix A-Docket#71,250&#71,412 1993,1994 Eastman Kodak Company,Rochester,New York 14650-2201 /******************************************************************** *Standardized Geometric Image Generator * *Copyright Eastman Kodak Company,1993-1994 * ********************************************************************/ #include<stdio.h> /*For printf and so on.*/ #include<stdlib.h> #include<math.h> #include<string.h> #include<ctype.h> #include<errno.h> #include<Xm/Text.h> #include<Mrm/Mrm.Appl.h> /*Motif Toolkit and MRM*/ #include<X11/X.h> #include<Xm/MessageB.h> #include<Xm/Xm.h> /* */ /*Include file from VUIT */ /*1.VUIT global routine declarations */ /*2.Global variables */ /*3.Literals from UIL code */ /*VUIT routines for the user to call*/ void s_error(); int HashFunction(); int HashLookup(); int HashRegister(); void VUIT_Manage(); void VUIT_Unmanage(); /* Motif Global variables*/ Display *display;/*Display vriable*/ XtAppContext app_context;/*application context*/ Widget toplevel_widget; /*Root widget ID of application*/ MrmHierarchy s_MrmHierarchy;/*MRM database hierarchy ID */ <dp n="d27"/> p.2 /* Literals from the UIL code*/ #define K_updateimage 32 #define K_writefiles 31 #define K_fairhair 30 #define K_nobeard 29 #define K_beard 28 #define K_nomustache 27 #define K_mustache 26 #define K_noglasses 25 #define K_glasses 24 #define K_medium 23 #define K_dark 22 #define K_light 21 #define K_female 20 #define K_male 19 #define K_filename 18 #define K_file_select 17 #define K_display_2 16 #define K_display_1 15 #define K_status 14 #define K_type 13 #define K_mouth_y 12 #define K_eye_ly 11 #define K_eye_ry 10 #define K_mouth_x 9 #define K_eye_lx 8 #define K_eye_rx 7 #define K_general_message 6 #define K_general_input 5 #define K_error_message 4 #define K_cancel 3 #define K_help 2 #define K_ok 1 /* *Glboal data */ static MrmType class_id; /*Place to keep class ID*/ static MrmType *dummy_class; /*and class variable.*/ static char*db_filename_vec[]= /*Mrm.hierachy file list.*/ { "credcard.uid" }; static int db_filename_num= <dp n="d28"/> p.3 (sizeof db_filename_vec/sizeof db_filename_vec[0]); char*vuit_dummy_ident_value="VUIT dummy identifier value"; #define hash_table_limit 500 struct HASH_TABLE_STRUCT { char*widget_name; Widget id; }hash_table[hash_table_limit+1]; /* *Forward declarations */ void Error_message_proc(); void General_message_proc(); void General_input_proc(); void Widget_create(); void Exit_proc(); void File_select(); void CC_convert_all(); void CC_next_file(); void CC_prev_file(); void CC_new_file(); void File_select_cancel(); void File_select_help(); void CC_display_expose(); void CC_set_header(); void CC_writefiles(); void CC_updateimage(); /* *Names and addresses of callback routines to register with Mrm */ static MrmRegisterArg reglist[]={ {"Error_message_proc",(caddr_t)Error_message_proc}, {"General_message_proc",(caddr_t)General_message_proc}, {"General_input_proc",(caddr_t)General_input_proc}, {"Widget_create",(caddr_t)Widget_create}, {"Exit_proc",(caddr_t)Exit_proc}, {"File_select",(caddr_t)File_select}, {"CC_convert_all",(caddr_t)CC_convert_all}, {"CC_next_file",(caddr_t)CC_next_file}, {"CC_prev_file",(caddr_t)CC_prev_file}, {"CC_new_file",(caddr_t)CC_new_file}, {"File_select_cancel",(caddr_t)File_select_cancel}, {"File_select_help",(caddr_t)File_select_help}, <dp n="d29"/> p.4 {"CC_display_expose",(caddr_t)CC_display_expose}, {"CC_set_header",(caddr_t)CC_set_header}, {"CC_updateimage",(caddr_t)CC_updateimage}, {"CC_writefiles",(caddr_t)CC_writefiles}}; static int reglist_num=(sizeof reglist/sizeof reglist[0]); -/* *Names and addresses of uil identifiers(if any)to register with Mrm. *These identifiers are registered with a dummy value to allow the generated *code to run without error. *You can avoid the registration of these identifiers by simplying editing *this template file(vuit_main_template_c)and removing the following *special format comments: * ***VUIT ident registration*** * ***VUIT identlist size*** * ***VUIT register identifiers*** *You can provide your own registration of identifiers by calling your own *routine in response to a callback(such as the MrmNcreateCallback for your *application’s main window),or by modifying this template to call your *own registration routine. */ typedef struct { char Size; char Fill[1]; unsigned char OLeftX; unsigned char OLeftY; unsigned char ORightX; unsigned char ORightY; unsigned char OMouthX; unsigned char OMouthY; unsigned char LeftX; unsigned char LeftY; unsigned char RightX; unsigned char RightY; unsigned char MouthX; unsigned char MouthY; char Filler[40-(8+12)]; }Header_data; typedef struct { int i_pixel; int j_pixel; <dp n="d30"/> p.5 int block_height; int block_width; int bit_depth; int codebook_type; int symmetric_block; int h_flip; int v_flip; int codevalue; int error; int RowDiff; int ColDiff; }BlockInfo; static void set_something(); static void get_something(); void ResetIDFields(void); void FlipImage(unsigned char*); int ReadImage(unsigned char*); void DisplayImage(int,unsigned char*); void SamplePoint(int,int,float*,float*); void Inverse Point(int,int,float*,float*); unsigned char Bilinear(unsigned char*,int,int,float,float); void smoothpli(float*,float*,int,float,float*,float*,int); float pli(float*,float*,int,float); zoomer(float,unsigned char*,unsigned char*); void image_architecture(void); void extract_block(unsigned char*,unsigned char*,BlockInfo*); horizontal_block_flip(unsigned char*,BlockInfo*); vertical_block_flip(unsigned char*,BlockInfo*); int vq_encode(unsigned char*,BlockInfo*); int mean_square_error(unsigned char*,unsigned char*,int); int mean_square_check(unsigned char*,unsigned char*,int,int); void ButtonDisplay1(Widget,XtPointer,XEvent*,Boolean*); void ButtonDisplay2(Widget,XtPointer,XEvent*,Boolean*); #define charset XmSTRING_DEFAULT_CHARSET #define ABS(a)((a)<(0)?-(a):(a)) #define NINT(x)((x<0)?(short int)(x-0.5):(short int)(x+0.5)) #define MAX(a,b)((a)>(b)?(a):(b)) #define MIN(a,b)((a)<(b)?(a):(b)) #define Swap_w(a,b)(b=(a & 0xffff)<<16|(a>>16&0xffff)); #define Swap_b(a,b)(b=(short int)(a & 0xff)<<8|(a>>8&0xff)) short int*Reve_c; <dp n="d31"/> p.6 #define Reve_b(a,b)(Reve_c=(short int*)&b;Swap_w(a,b); swap_b(Reve_c[0],Reve_c[0]);swap_b(Reve_c[1],Reve_c[1])) #define true 1 #define false 0 #define Message_button_ok 0 #define Message_button_apply 1 #define Message_button_cancel2 #define Message_button_help 3 #define Message_message_label4 #define CMPBLKSIZE 16 #define NUMBER_COLORS 256 #define IMG_WID 180 #define IMG_LEN 180 #define DISPLAY_WID IMG_WID*2 #define DISPLAY_LEN IMG_LEN*2 #define CenteredImage_wid 112 #define CenteredImage_len 128 #define DwsmpImage_wid CenteredImage_wid/2 #define DwsmpImage_len CenteredImage_len/2 #define CenterOffsetX(IMG_WID-CenteredImage_wid)/2 #define CenterOffsetY(IMG_LEN-CenteredImage_len)/2 #define PIXELS_BETWEEN_EYES 30 #define RED_SCALE 3 #define GREEN_SCALE 6 #define BLUE_SCALE 1 #define FACTOR_I 8 #define FACTOR_2 10 #define TOTAL_BLOCKS 64 #define FINAL_PIXELS IMG_WID #define FINAL_LINES IMG_LEN #define RIGHT_EYE_COL (FINAL_PIXELS/2)+ (PIXELS_BETWEEN_EYES/2) #define RIGHT_EYE_ROW (FINAL_LINES/2)-8 #define IMG_CENTER IMG_WID/2 #define MOUTH_ROW RIGHT_EYE_ROW+40 #define ORIGINAL_PIXELS IMG_WID <dp n="d32"/> p.7 #define ORIGINAL_LINES IMG_LEN #define EYE_CODE_BOOK_SIZE 2*8*2*5*256 #define MAX_BLOCK_PIXELS 256 Arg arglist[20]; Widget Widget_id[100],Message_widget[10]; char Unix_filename[256]; FILE*fp; static float DwsmpMat[3][3]=(1.,1.,1., 1.,8.,1., 1.,1.,1.}; float LeftEyeX,LeftEyeY,RightEyeX,RightEyeY,MouthX,MouthY; float theta,T[4],alpha,beta_gamma[2],BackGround; float mean_tar; int high,low,phigh,plow; int Img_wid=IMG_WID,Img_len=IMG_LEN,ImgBufSiz_short,ImgBufSiz_char; int DisplayImgBufSiz,DisplayWid=DISPLAY_WID,DisplayLen=DISPLAY_LEN; int Default_depth,Window_id,Gc_mask,Screen_num,FileNumber; int Image_displayed[100],Grid_displayed[100],Histo[256]; int MF_flag,LMD_flag,GNG_flag,MNM_flag,Local_MNM_flag; int BNB_flag,Local_BNB_flag,FH_flag; char In_filename[256]; int mse_table[512]; Header_data Header; BlockInfo block_stats[TOTAL_BLOCKS]; BlockInfo block_stuffTmp[2]; unsigned char*BlankImageData,*DisplayIImageData,*Display2ImageData; unsigned char*LuminanceImage,*CenteredImage,*CCenteredImage; unsigned char*FinalImage,*HistogramedImage,*targa_image; unsigned char*Red,*Green,*Blue,*EyeCodeBook[NO_EYE_CODE_BOOKS]; unsigned char(*TmpPtr1)[IMG_LEN],(*TmpPtr2)[DISPLAY_LEN]; unsigned char Lookup_table[NUMBER_COLORS]; <dp n="d33"/> p.8 unsigned char Image1[CenteredImage_len][CenteredImage_wid]; unsigned char Image2[DwsmpImage_len][DwsmpImage_wid]; unsigned char Image3[CenteredImage_len+1][CenteredImage_wid+1]; Display *Display_id; Screen *Screen_id; yisual *Default_visual; Colormap Default_cmap,Cmap; XColor Color_map[NUMBER_COLORS]; XGCValues Gc_def; GC Gc; XImage *Blank_display; <dp n="d34"/> p.9 /* *OS transfer point.The main routine does all the one-time setup and *then calls XtAppMainLoop. */ unsigned int main(argc,argv) unsigned int argc; /*Command line argument count.*/ char *argv[]; /* Pointers to command line args.*/ { Arg arglist[2]; float sum=0; int i,j,n,Contig,N_colors_alloc,Start_colors,End_colors; int Plmask[NUMBER_COLORS],Pixs_colrs[NUMBER_COLORS]; short int R[2],G[2],B[2]; unsigned char *Ptr,CodeBook_Filename[256]; for(n=0;n<100;n++) { Image_displayed[n]=0; Grid_displayed[n]=0; } MrmInitialize(); /*Initialize MRM before initializing*/ /*the X Toolkit.*/ /* If we had user-defined widgets,we would register them with Mrm.here. */ /* Initialize the X Toolkit.We get back a top level shell widget.*/ XtToolkitInitialize(); app_context=XtCreateApplicationContext(); display=XtOpenDisplay(app_context,NULL,argv[0], "Credit Card Image",NULL,O,&argc,argv); if(display==NULL) { fprintf(stderr,"%s:Can’t open display\n",argv[0]); exit(l); } n=0; XtSetArg(arglist[n],XmNallowShellResize,True);n++; <dp n="d35"/> p.10 toplevel_widget=XtVaAppCreateShell(argv[0],NULL, applicationShellWidgetClass, display,XmNallowShellResize,True, NULL); /* Open the UID files(the output of the UTL compiler)in the hierarchy*/ if(MrmOpenHierarchy(db_filename_num,/*Number of files.*/ db_filename_vec, /*Array of file names.*/ NULL, /*Default OS extenstion.*/ &s_MrmHierarchy) /*Pointer to returned MRM ID*/ !=MrmSUCCESS)s_error("can’t open hierarchy"); MrmRegisterNames(reglist,reglist_num); /* Manage initial windows */ VUIT_Manage("Error_message"); VUIT_Unmanage("Error_message"); VUIT_Manage("CC_main_win"); /* Realize the top level widget.All managed children now become visible */ XtRealizeWidget(toplevel_widget); image_architecture(); ImgBufSiz_char =sizeof(char)*Img_wid*Img_len; ImgBufSiz_short =sizeof(short)*Img_wid*Img_len; DisplayImgBufSiz =sizeof(char)*DisplayWid*DisplayLen; targa_image =(short*)malloc(ImgBufSiz_short); BlankImageData =(unsigned char*)malloc(DisplayImgBufSiz); DisplaylImageData=(unsigned char*)malloc(DisplayImgBufSiz); Display2ImageData=(unsigned char*)malloc(DisplayImgBufSiz); LuminanceImage =(unsigned char*)malloc(ImgBufSiz_char); CenteredImage =(unsigned char*)malloc(ImgBufSiz_char); CCenteredImage =(unsigned char*)malloc(ImgBufSiz_char*3); FinalImage =(unsigned char*)malloc(ImgBufSiz_char); HistogramedImage =(unsigned char*)malloc(ImgBufSiz_char); Red =(unsigned char*)malloc(ImgBufSiz_char); Green =(unsigned char*)malloc(ImgBufSiz_char); Blue =(unsigned char*)malloc(ImgBufSiz_char); <dp n="d36"/> p.11 EyeCodeBook[i]=(unsigned char*) malloc(EYE_CODE_BOOK_SIZE); sprintf(CodeBook_Filename,"book_%s_5",classes[i]); fp=fopen(CodeBook_Filename,"rb"); fread(EyeCodeBook[i],EYE_CODE_BOOK_SIZE,1,fp); close(fp); for(i=0,i<64;i++) { mse_table[256-i]=i*i; mse_table[256+i]=mse_table[256-i]; } for(i=64;i<256;i++) { mse_table[256-i]=64*64; mse_table[256+i]=mse_table[256-i]; } Ptr=BlankImageData; for(i=0;i<DisplayLen;i++) for(j=0;j<DisplayWid;j++)*Ptr++=0; /* Define variables for image display*/ Start_colors=32; N_colors_alloc=NUMBER_COLORS-Start_colors; End_colors=NUMBER_COLORS; Gc_mask =255; Display_id =display; Screen_id =XtScreen(toplevel_widget); Screen_num =0; Default_depth =DefaultDepth(Display_id,Screen_num); Default_visual =DefaultVisualOfScreen(Screen_id); Default_cmap =DefaultColormap(Display_id,Screen_num); Window_id =XtWindow(toplevel_widget); for(i=0;i<NUMBER_COLORS;i++) { Color_map[i].pixel=i; Lookup_table[i]=i; } if(Default_depth==8) { Default_visual->class=DirectColor; Default_visual->bits_per_rgb=8; <dp n="d37"/> p.12 Default_visual->map_entries=NUMBER_COLORS; Default_visual->red_mask=255; Default_visual->green_mask=255; Default_visual->blue_mask=255; Cmap= XCreateColormap(Display_id,Window_id,Default_visual,AllocAll); /* Contig=1;*/ Contig=0; XQueryColors(Display_id,Default_cmap,Color_map,NUMBER_COLORS); /* DefineColors(True);/*redifine standard colors for new map*/ for(i=Start_colors;i<End_colors;i++) { Color_map[i].pixel=i; Color_map[i].red=i*257; Color_map[i].green=i*257; Color_map[i].blue=i*257; Color_map[i].flags=DoRed|DoGreen|DoBlue; } #if 0 Color_map[i].pixel=i; Rgbmap(i,R,G,B); Color_map[i].pixel=i; Color_map[i].red=R[1]; Color_map[i].green=G[1]; Color_map[i].blue=B[1]; Color_map[i].flags=DoRed|DoGreen|DoBlue; #endif XStoreColors(Display_id,Cmap,Color_map,NUMBER_COLORS); for(i=0;i<Start_colors;i++) { Lookup_table[i]=Start_colors; } } else Cmap=XDefaultColormapOfScreen(Screen_id); if(Default_depth==8)Gc_def.plane_mask=255; else Gc_def.plane_mask=0xFFFFFF; <dp n="d38"/> p.13 Gc_def.foreground=XWhitePixelOfScreen(Screen_id); Gc_def.background=XBlackPixelOfScreen(Screen_id); Gc_def.function=GXcopy; Gc_mask=GCBackground|GCForeground| GCPlaneMask|GCFunction; Gc=XCreateGC(Display_id,Window_id,Gc_mask,&Gc_def); XSetWindowColormap(Display_id,Window_id,Cmap); for(i=0;i<256;i++)Histo[i]=0; for(i=0;i<3;i++) for(j=0;j<3;j++)sum+=DwsmpMat[j][i]; for(i=0;i<3;i++) for(j=0;j<3;j++)DwsmpMat[j][i]=DwsmpMat[j][i]/sum; /* Reset ID fields to known state*/ ResetIDFields(); /* Sit around forever waiting to process X-events.We never leave Xt AppMainLoop. From here on,we only execute our callback routines. */ XtAppMainLoop(app_context); } #if 0 void function Rgbmap(int i,int *R,int *G,int *B) { int j,k,l; j=(i&"007) k=(i&"070)/(pow(2,3)); l=(i&"300)/(pow(2,6)); R=(int)(j*9362.142857+.5); G=(int)(k*9362.142857+.5); B=(int)(1*21845+.5); } #endif <dp n="d39"/> p.14 /* *All errors are fatal. */ void s_error(problem_string) char*problem_string; { printf(%s\n",problem_string); exit(0); } <dp n="d40"/> p.15 void VUIT_Manage(widget_name) char *widget_name; { Widget id=NULL; Window pop_window; XWindowChanges values; if(HashLookup(widget_name,&id)) if(XtIsManaged(id)) { pop_window=XtWindow(XtParent(id)); values.x=values.y=values.width=values.height= values.bord er_width=values.sibling=NULL; values.stack_mode=Above; XConfigureWindow(display,pop_window,CWStackMode,&values); } else XtManageChild(id); else { MrmFetchWidget(s_MrmHierarchy,widget_name,toplevel_widget, &id, &class_id); XtManageChild(id); HashRegister(widget_name,id); } } <dp n="d41"/> p.16 void VUIT_Unmanage(widget_name) char *widget_name; { Widget id; if(HashLookup(widget_name,&id)) XtUnmanageChild(id); } <dp n="d42"/> p.17 int HashRegister(widget_name,id) char *widget_name; Widget id; { int ndx; for(ndx=HashFunction(widget_name,hash_table_limit); ((hash_table[ndx].widget_name!=NULL)&& (ndx<hash_table_limit)); ndx++); if(hash_table[ndx].widget_name!=NULL) for(ndx=0; hash_table[ndx].widget_name!=NULL; ndx++); if(ndx>hash_table_limit) return(FALSE); else { hash_table[ndx].widget_name=XtCalloc(1,strlen(widget_name)+1); strcpy(hash_table[ndx].widget_name,widget_name); hash_table[ndx].id=id; return(TRUE); } } <dp n="d43"/> p.18 int HashLookup(name,id) char *name; Widget *id; { int ndx; for(ndx=HashFunction(name,hash_table_limit); ((hash_table[ndx].widget_name!=NULL)&& (ndx<=hash_table_limit)); ndx++) if(strcmp(name,hash_table[ndx].widget_name)==0) { *id=hash_table[ndx].id; return(TRUE); } if(ndx>hash_table_limit) for(ndx=0; ((hash_table[ndx].widget_name!=NULL)&& (ndx<=hash_table_limit)); ndx++) { if(strcmp(name,hash_table[ndx].widget_name)==0) { *id=hash_table[ndx].id; retun(TRUE); } } return(FALSE); } <dp n="d44"/> p.19 int HashFunction(name,maxval) char *name; int maxval; { #define HashVecSize 20 /*plenty for 31 character names*/ typedef union { short int intname[HashVecSize]; /*name as vector of ints*/ char charname[2*HashVecSize];/*name as vector of chars*/ }HashName; HashName locname; /*aligned name*/ int namelen; /*length of name*/ int namelim; /*length limit(fullword size)*/ int namextra; /*limit factor remainder*/ int code=0; /*hash code value*/ int ndx; /*loop index*/ /* *Copy the name into the local aligned union. *Process the name as a vector of integers,with some remaining characters. *The string is copied into a local union in order to force correct *alignment for alignment-sensitive processors. */ strcpy(locname.charname,name); namelen=strlen(locname.charname); namelim=namelen>>1; /*divide by 2*/ namextra=namelen & 1; /*remainder*/ /* *XOR each integer part of the name together,followed by the trailing *0/1 character */ for(ndx=0;ndx<namelim;ndx++) code=code∧((locname.intname[ndx])<<ndx); if(namextra>0) code=code∧((locname.intname[ndx])&0x00FF); return(code&0x7FFF)%maxval; } <dp n="d45"/> p.20 void Error_message_proc(w,tag,reason) Widget w; int *tag; unsigned long *reason; { VUIT_Unmanage("Error_message"); } <dp n="d46"/> p.21 void General_message_proc(w,tag,reason) Widget w; int *tag; unsigned long *reason; { VUIT_Unmanage("General_message"); } <dp n="d47"/> p.22 void General_input_proc(w,tag,reason) Widget w; int *tag; unsigned long *reason; { VUIT_Unmanage("General_input"); } <dp n="d48"/> p.23 void Widget_create(w,tag,reason) Widget w; int *tag; unsigned long *reason; { - Widget_id[*tag]=w; /* Add event handlers for mouse buttons*/ if(*tag==K_display_1) XtAddEventHandler(w,ButtonReleaseMask,0,ButtonDisplay1,0); if(*tag==K_display_2) XtAddEventHandler(w,ButtonReleaseMask,0,ButtonDisplay2,0); if(*tag==K_error_message) { Message_widget[Message_button_ok]= XmMessageBoxGetChild(Widget_id[K_error_message], XmDIALOG_OK_BUTTON); Message_widget[Message_button_cancel]= XmMessageBoxGetChild(Widget_id[K_error_message], XmDIALOG_CANCEL_BUTTON); Message_widget[Message_button_help]= XmMessageBoxGetChild(Widget_id[K_error_message], XmDIALOG_HELP_BUTTON); Message_widget[Message_message_label]= XmMessageBoxGetChild(Widget_id[K_error_message], XmDIALOG_MESSAGE_LABEL); XtUnmanageChild(Message_widget[Message_button_cancel]); XtUnmanageChild(Message_widget[Message_button_help]); } } <dp n="d49"/> p.24 void Exit_proc(w,tag,reason) Widget w; int *tag; unsigned long *reason; { exit(0); } <dp n="d50"/> p.25 void File_select(w,tag,reason) Widget w; int *tag; unsigned long *reason; VUIT_Manage("File_select_win"); } void File_select_cancel(w,tag,reason) Widget w; int *tag; unsigned long *reason; { VUIT_Unmanage("File_select_win"); } <dp n="d51"/> p.26 void File_select_help(w,tag,reason) Widget w; int *tag; unsigned long *reason; { VUIT_Unmanage("File_select_win"); } <dp n="d52"/> p.27 void CC_convert_all(w,tag,Fs_struct) Widget w; int *tag; XmFileSelectionBoxCallbackStruct *Fs_struct; { XmString Simple_sting; int i,j,k,l; int Filename_len; char *Local_filename,*Tmp,Text[255],*luminance; if(!XmStringGetLtoR(Fs_struct->value,charset,&Local_filename))return; Filename_len=strlen(Local_filename); if(!*Local_filename) sprintf(Text,"%s\0","No Files Selected"); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_error_message],XmNmessageString, Simple_string); VUIT_Manage("Error_message"); XmStringFree(Simple_string); XtFree(Local_filename); return; } VUIT_Unmanage("File_select_win"); sprintf(In_filename,"% s\0",Local_filename); for(i=0;i<Filename_len;i++) Local_filename[i]=(char)tolower(In_filename[i]); Local_filename[Filename_len]=0; Tmp=strstr(Local_filename,".tga"); *Tmp=0; Tmp-=5; sscanf(Tmp,"%d",&FileNumber); XtFree(Local_filename); TmpPtrl=(unsigned char(*)[])LuminanceImage; <dp n="d53"/> p.28 if(ReadImage(LuminanceImage)!=NULL) { TmpPtr2=(unsigned char(*)[])DisplaylImageData; for(i=0,j=0;i<Img_len;i++,j+=2) { for(k=0,1=0;k<Img_wid;k++,l+=2) { TmpPtr2[l][j]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l+1][j]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[1][j+1]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[1+1][j+1]=Lookup_table[TmpPtr1[k][i]]; } } DisplayI mage(K_display_1,DisplaylImageData); } Grid_displayed[K_display_2]=0; DisplayImage(K_display_2,BlankImageData); Image_displayed[K_display_2]=0; } <dp n="d54"/> p.29 void CC_new_file(w,tag,Fs_struct) Widget w; int *tag; XmFileSelectionBoxCallbackStruct *Fs_struct; { XmString Simple_string; int i,j,k,l; int Filename_len; char *Local_filename,*Tmp,Text[255],*luminance; if(!XmStringGetLtoR(Fs_struct->value,charset,&Local_filename))return; Filename_len=strlen(Local_filename); if(!*Local_filename) { sprintf(Text,"%s\0","No Files Selected"); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_error_message],XmNmessageString, Simple_string); VUIT_Manage("Error_message"); XmStringFree(Simple_string); XtFree(Local_filename); return; } VUIT_Unmanage("File_select_win"); sprintf(In_filename,"%s\0",Local_filename); for(i=0;i<Filename_len;i++) Local_filename[i]=(char)tolower(In_filename[i]); Local_filename[Filename_len]=0; Tmp=strstr(Local_filename,".tga"); *Tmp=0; Tmp-=5; sscanf(Tmp,"%d",&FileNumber); XtFree(Local_filename); <dp n="d55"/> p.30 TmpPtrl=(unsigned char(*)[])LuminanceImage; if(ReadImage(LuminanceImage)!=0) { TmpPtr2=(unsigned char(*)[]) DisplaylImageData; for(i=0,j=0;i<Img_len;i++,j+=2) { for(k=0,1=0;k<Img_wid;k++,1+=2) { TmpPtr2[l][j]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l+1][j]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l][j+1]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l+1][j+1]=Lookup_table[TmpPtr1[k][i]]; } } DisplayImage(K_display_1,DisplaylImageData); } Grid_displayed[K_display_2]=0; DisplayImage(K_display_2,BlankImageData); Image_displayed[K_display_2]=0; ResetIDFields(); } <dp n="d56"/> p.31 void CC_next_file(w,tag,reason) Widget w; int *tag; unsigned long *reason; { int i,j,k,l,Filename_len; char *Tmp,FileNumChar[6],Local_filename[255],*luminance; char Text[255]; XmString Simple_string; if(strlen(In_filename)==0) { sprintf(Text,"%s\0","Unable to open file"); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_error_message],XmNmessageString, Simple_string); VUIT_Manage("Error_message"); XmStringFree(Simple_string); return; } sprintf(FileNumChar,"%05d",FileNumber); Filename_len=strlen(In_filename); for(i=0;i<Filename_len;i++) Local_filename[i]=(char)tolower(In_filename[i]); Local_filename[Filename_len]=0; Tmp=strstr(Local_filename,"f"); Tmp=strstr(Tmp,FileNumChar); FileNumber++; if(FileNumber>99999)FileNumber=1; sprintf(FileNumChar,"%05d",FileNumber); sprintf(Tmp,"%s",FileNumChar); Tmp[5]=∵; for(i=0;i<Filename_len;i++) In_filename[i]=(char)tolower(Local_filename[i]); In_filename[Filename_len]=0; TmpPtr1=(unsigned char(*)[])LuminanceImage; if(ReadImage(LuminanceImage)!=0) <dp n="d57"/> p.32 { TmpPtr2=(unsigned char(*)[])DisplaylImageData; for(i=0,j=0;i<Img_len;i++,j+=2) { for(k=0,1=0;k<Img_wid;k++,l+=2) { Tmpptr2[l][j]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l+1][j]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l][j+1]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l+1][j+1]=Lookup_table[TmpPtr1[k][i]]; } } DisplayImage(K_display_1,DisplaylImageData); } else DisplayImage(K_display_1,BlankImageData); Grid_displayed[K_display_2]=0; DisplayImage(K_display_2,BlankImageData); Image_displayed[K_display_2]=0; ResetIDFields(); } void CC_prev_file(w,tag,reason) Widget w; int *tag; unsigned long *reason; { int i,j,k,l,Filename_len; char *Tmp,File NumChar[6],Local_filename[255],*luminance; char Text[255]; XmString Simple_string; if(strlen(In_filename)==0) { sprintf(Text,"%s\0","Unable to oPen file"); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_error_message],XmNmessageString, Simple_string); VUIT_Manage("Error_message"); XmStringFree(Simple_string); return; } sprintf(FileNumChar,"%05d",FileNumber); <dp n="d58"/> p.33 Filename_len=strlen(In_filename); for(i=0;i<Filename_len;i++) Local_filename[i]=(char)tolower(In_filename[i]); Local_filename[Filename_len]=0; Tmp=strstr(Local_filename,FileNumChar); FileNumber-; if(File Number<=0)FileNumber=1; sprintf(FileNumChar,"%05d",FileNumber); sprintf(Tmp,"%s",FileNumChar); Tmp[5]=∵; for(i=0;i<Filename_len;i++) In_filename[i]=(char)tolower(Local_filename[i]); In_filename[Filename_len]=0; TmpPtr1=(unsigned char(*)[])LuminanceImage; if(ReadImage(LuminanceImage)!=0) { TmpPtr2=(unsigned char(*)[])DisplaylImageData; for(i=0,j=0;i<Img_len;i++,j+=2) { for(k=0,1=0;k<Img_wid;k++,l+=2) { TmpPtr2[l][j]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l+1][j]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l][j+1]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l+1][j+1]=Lookup_table[TmpPtr1[k][i]]; } } DisplayImage(K_display_I,DisplaylImageData); } else DisplayImage(K_display_1,BlankImageData); Grid_displayed[K_display_2]=0; DisplayImage(K_display_2,BlankImageData); Image_displayed[K_display_2]=0; ResetIDFields(); } void CC_display_expose(w,tag,reason) Widget w; int *tag; unsigned long *reason; <dp n="d59"/> p.34 int Window; if(*tag==K_clisplay_1 && Image_displayed[*tag]==1) DisplayImage(K_display_1,DisplaylImageData); if(*tag==K_display_2&&Image_displayed[*tag]==1) DisplayImage(K_display_2,Display2ImageData); } <dp n="d60"/> p.35 void CC_set_header(w,tag,reason) Widget w; int *tag; unsigned long *reason; { int Widget_offset; char Text[255]; XmString Simple_string; Widget_offset=*tag; } <dp n="d61"/> p.36 void CC_updateimage(w,tag,reason) Widget w; int *tag; unsigned long *reason; { float s1,s2,TmpVal1,TmpVal2; float sample_x,sample_y,weight_x,weight_y,ZoomFactor; int base_x,base_y; int i,j,k,l,Eye_locate; char *Tmp,Text[255]; unsigned char *original_image; unsigned char *ptr; XmString Simple_string; if(LeftEyeX==011 LeftEyeY==011 RightEyeX==011 RightEyeY==011 MouthX==011 MouthY==0) { sprintf(Text,"%s\0","Eye and Mouth Co-ordinates not selected"); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_error_message],XmNmessageString, Simple_string); VUIT_Manage("Error_message"); XmStringFree(Simple_string); return; } /*location of left and right eyes in current image*/ alpha=PIXELS_BETWEEN_EYES/ sqrt((RightEyeY-LeftEyeY)*(RightEyeY-LeftEyeY)+ (RightEyeX-LeftEyeX)*(RightEyeX-LeftEyeX)); theta=atan2((double)(RightEyeY-LeftEyeY), (double)(RightEyeX-LeftEyeX)); *T=(float)cos(theta); *(T+2)=(float)sin(theta); *(T+1)=-*(T+2); *(T+3)=*T; beta_gamma[0]=RIGHT_EYE_ROW-alpha*(*T* (RightEyeY-LeftEyeY)+ *(T+1)*(RightEyeX-LeftEyeX)); <dp n="d62"/> p.37 beta_gamma[1]=RIGHT_EYE_COL-alpha*(*(T+2)*(RightEyeY- LeftEyeY)+*(T+3)*(RightEyeX-LeftEyeX)); original_image=LuminanceImage; BackGround=*original_image; ptr=CenteredImage; for(i=0;i<FINAL_LINES;i++) for(j=0;j<FINAL_PIXELS;j++) { SamplePoint(j,i,&sample_x,&sample_y); weight_x=1.0-fmod(sample_x,1.0); weight_y=1.0-fmod(sample_y,1.0); base_x=(int)sample_x; base_y=(int)sample_y; *ptr=Bilinear(original_image,base_x,base_y,weight_x,weight_y); ptr++; } #if 0 InversePoint(MouthX,MouthY,&sample_x,&sample_y); printf("RIGHT_EYE_ROW%d\n",RIGHT_EYE_ROW); printf("RIGHT_EYE_COL%d\n",RIGHT_EYE_COL); printf("sample x %f\n",sample_x); printf("sample y %f\n",sample_y); ZoomFactor=(RIGHT_EYE_ROW-MOUTH_ROW)/ (RIGHT_EYE_ROW-sample_y)-1.0; printf("Zoom factor %f\n",ZoomFactor); ZoomFactor=MIN(ZoomFactor,.05); ZoomFactor=MAX(ZoomFactor,-.05); printf("Zoom factor %f\n",ZoomFactor); zoomer(ZoomFactor,CenteredImage,FinalImage); #endif if((Eye_locate=EyeLocate(CenteredImage))==-1); else if(Eye_locate==True) { InversePoint(LeftEyeX,LeftEyeY,&sample_x,&sample_y); block_stuffTmp[0].j_pixel=NINT(sample_y)+ block_stuffTmp[0].ColDiff; <dp n="d63"/> p.38 block_stuffTmp[0].i_pixel=NINT(sample_x)+ block_stuffTmp[0].RowDiff; SamplePoint(block_stuffTmp[0].j_pixel,block_stuffTmp[0].i_pixel, &TmpVal1,&TmpVal2); LeftEyeX=NINT(TmpVal1); LeftEyeY=NINT(TmpVal2); InversePoint(RightEyeX,RightEyeY,&sample_x,&sample_y); block_stuffTmp[1].i_pixel=NINT(sample_y)+ block_stuffTmp[1].RowDiff; block_stuffImp[1].j_pixel=NINT(sample_x)+ block_stuffTmp[1].ColDiff; SamplePoint(block_stuffTmp[1].j_pixel,block_stuffTmp[1].i_pixel, &TmpVal1,&TmpVal2); RightEyeX=NINT(TmpVal1); RightEyeY=NINT(TmpVal2); alpha=PIXELS_BETWEEN_EYES/ sqrt((RightEyeY-LeftEyeY)*(RightEyeY-LeftEyeY)+ (RightEyeX-LeftEyeX)*(RightEyeX-LeftEyeX)); theta=atan2((double)(RightEyeY-LeftEyeY), (double)(RightEyeX-LeftEyeX)); *T=(float)cos(theta); *(T+2)=(float)sin(theta); *(T+1)=-*(T+2); *(T+3)=*T; beta_gamma[0]=RIGHT_EYE_ROW-alpha*(*T* (RightEyeY-LeftEyeY)+ *(T+1)*(RightEyeX-LeftEyeX)); beta_gamma[1]=RIGHT_EYE_COL-alpha*(*(T+2)*(RightEyeY- LeftEyeY)+*(T+3)*(RightEyeX-LeftEyeX)); original_image=LuminanceImage; BackGround=*original_image; ptr=CenteredImage; for(i=0;i<FINAL_LINES;i++) for(j=0;j<FINAL_PIXELS;j++) { SamplePoint(j,i,&sample_x,&sample_y); weight_x=1.0-fmod(sample_x,1.0); <dp n="d64"/> p.39 weight_y=1.0-fmod(sample_y,1.0); base_x=(int)sample_x; base_y=(int)sample_y; *ptr=Bilinear(original_image,base_x,base_y,weight_x,weight_y); ptr++; } } ptr=CCenteredImage; original_image=Red; BackGround=*original_image; for(i=0;i<FINAL_LINES;i++) for(j=0;j<FINAL_PIXELS;j++) { SamplePoint(j,i,&sample_x,&sample_y); weight_x=1.0-fmod(sample_x,1.0); weight_y=1.0-fmod(sample_y,1.0); base_x=(int)sample_x; base_y=(int)sample_y; *ptr=Bilinear(original_image,base_x,base_y,weight_x,weight_y); ptr++; } original_image=Green; BackGround=*original_image; for(i=0;i<FINAL_LINES;i++) for(j=0;j<FINAL_PIXELS;j++) { SamplePoint(j,i,&sample_x,&sample_y); weight_x=1.0-fmod(sample_x,1.0); weight_y=1.0-fmod(sample_y,1.0); base_x=(int)sample_x; base_y=(int)sample_y; *ptr=Bilinear(original_image,base_x,base_y,weight_x,weight_y); ptr++; } original_image=Blue; BackGround=*original_image; for(i=0;i<FINAL_LINES;i++) for(j=0;j<FINAL_PIXELS;j++) { <dp n="d65"/> p.40 SamplePoint(j,i,&sample_x,&sample_y); weight_x=1.0-fmod(sample_x,1.0); weight_y=1.0-fmod(sample_y,1.0); base_x=(int)sample_x; base_y=(int)sample_y; *ptr=Bilinear(original_image,base_x,base_y,weight_x,weight_y); ptr++; } /* Following code used to bypass code to stretch image*/ { unsigned char *ptr1,*ptr2; ptr1=CenteredImage; ptr2=FinalImage; for(i=0;i<Img_len;i++) for(j=0;j<Img_wid;j++) { *ptr2=(unsigned char)*ptr1++; if(*ptr2>255)*ptr2=255; if(*ptr2<0)*ptr2=0; ptr2++; } } TmpPtr1=(unsigned char(*)[])FinalImage; TmpPtr2=(unsigned char(*)[])Display2ImageData; Header.OLeftX=(unsigned char)LeftEyeX; Header.OLeftY=(unsigned char)LeftEyeY; Header.ORightX=(unsigned char)RightEyeX; Header.ORightY=(unsigned char)RightEyeY; Header.OMouthX=(unsigned char)MouthX; Header.OMouthY=(unsigned char)MouthY; for(i=0,j=0;i<Img_len;i++,j+=2) { for(k=0,1=0;k<Img_wid;k++,l+=2) { TmpPtr2[l][j]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l+1][j]=Lookup_table[TmpPtrl[k][i]]; TmpPtr2[l][j+1]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l+1][j+1]=Lookup_table[TmpPtr1[k][i]]; } } /*Displaylmage(K_display_1,Display2ImageData);*/ <dp n="d66"/> p.41 Grid_displayed[K_cisplay_21=1; DisplayImage(K_display_2,Display2ImageData); Image_displayed[K_ciisplay_2]=1; /* Following code used to bypass Shijie’s code to histogram image*/ -{ unsigned char *ptr1,*ptr2; ptr1=FinalImage; ptr2=HistogramedImage; for(i=0;i<Img_len;i++) for(j=0;j<I_mg_wid;j++) { *ptr2=(unsigned char)*ptr1++; if(*ptr2>255)*ptr2=255; if(*ptr2<0)*ptr2=0; ptr2++; } } #if0 /* Image Display for testing*/ TmpPtr1=(unsigned char(*)[])HistogramedImage; TmpPtr2=(unsigned char(*)[])Display2ImageData; for(i=0,j=0;i<Img_len;i++,j+=2) { for(k=0,1=0;k<Img_wid;k++,l+=2) { TmpPtr2[l][j]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l+1][j]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l][j+1]=Lookup_table[TmpPtr1[k][i]]; TmpPtr2[l+1][j+1]=Lookup_table[TmpPtr1[k][i]]; } } Grid_displayed[K_display_2]=1; DisplayImage(K_display_2,Display2ImageData); #endif } <dp n="d67"/> p.42 void CC_writefiles(w,tag,reason) Widget w; int *tag; unsigned long *reason; { XmString Simple_string; float TmpVal1,TmpVa12; int Window; XImage *Display_image; int i,j,k,l,m,n,Full_filename_len,File_len,Dire_len; #if defined VMS short int *Word_ptr; #endif char *Tmp,*Dire_ptr,*File_ptr,Dire[256],File[256],Text[255]; char Rgb_filename[256],Lum_filename[256],Tga_filename[256]; char Norm_filename[256],Dsmp_filename[256],Csmp_filename[256]; unsigned char CharTmp; Full_filename_len=strlen(Unix_filename); if(MF_flag==011LMD_flag==011 GNG_flag==011MNM_fag==011BNB_flag==0) { sprintf(Text,"%s\0","Identification fields not selected"); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_error_message],XmNmessageString, Simple_string); VUIT_Manage("Error_message"); XmStringFree(Simple_string); return; } #if defined VMS for(i=0;i<Full_filename_len;i++) Unix_filename[i]=(char)tolower(Unix_filename[i]); Tmp=strstr(Unix_filename,"tga"); Tmp+=3; *Tmp=0; #endif Full_filename_len=strlen(Unix_filename); <dp n="d68"/> p.43 /*Parse filename */ for(i=Full_filename_len;i>0;-i) if(Unix_filename[i]==∵)break; Unix_filename[i]=0; Full_filename_len=strlen(Unix_filename); for(i=Full_filename_len;i>0;--i) if(Unix_filename[i]==′/′)break; File_ptr=&Unix_filename[i+1]; File_len=Unix_filename-File_ptr; File_len+=Full_filename_len; Dire_ptr=&Unix_filename[0]; Dire_len=Full_filename_len-File_len-1; strncpy(File,File_ptr,File_len); strncpy(Dire,Dire_ptr,Dire_len); Dire[Dire_len]=0; File[File_len]=0; sprintf(Tga_filename,"%s/%s.tga",Dire,File); sprintf(Rgb_filename,"%s/img/%s.img",Dire,File); sprintf(Lum_filename,"%s/lum/%s.lum",Dire,File); sprintf(Norm_filename,"%s/nrm/%s.nrm",Dire,File); sprintf(Dsmp_filename,"%s/dsi/%s.dsi",Dire,File); sprintf(Csmp_filename,"%s/cds/%s.cds",Dire,File); /* Output color full size image file*/ Header.LeftX=Header.OLeftX; Header.LeftY=Header.OLeftY; Header.RightX=Header.ORightX; Header.RightY=Header.ORightY; Header.MouthX=Header.OMouthX; Header.MouthY=Header.OMouthY; if((fp=fopen(Tga_fiIename,"rb"))==NULL) { sprintf(Text,"%s\0","Unable to open targa file"); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_error_message],XmNmessageString, Simple_string); VUIT_Manage("Error_message"); XmStringFree(Simple_string); <dp n="d69"/> p.44 return; } i=fread(targa_image,1,sizeof(short)*9,fp); i=fread(traga_image,1,ImgBufSiz_short,fp); fclose(fp); if((fp=fopen(Rgb_filename,"wb"))==NULL) { sprintf(Text,"%s\0","Unable to open color image file"); Simple_string=XmStringCreateSimple(Text); set_ximething(Widget_id[K_error_message],XmNmessageString, Simple_string); VUTT_Manage("Error_message"); XmingFree(Simple_string); sprintf(Text,"%s"," "); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_filename],XmNlabelString,Simple_string); XmStringFree(Simple_string); return; } fwrite(&Geader,sizeof(Header_data),1,fp); fwrite(targa_image,ImgBufSiz_short,1,fp); fclse(fp); /* Output luminance full size image file*/ Header.LeftX=Header.OLeftX; Header.LeftY=Header.OLeftY; Header.RightX=Header.ORightX; Header.RightY=Header.ORightY; Header.MouthX=Header.OMouthX; Header.MouthY=Header.OMouthY; if((fp=fopen(Lum_filename,"wb"))==NULL) { sprintf(Text,"%s\0","Unable to open luminance file"); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_error_message],XmNmessageString, Simple_string); VUIT_Manage("Error_message"); XmStringFree(Simple_string); sprintf(Text,"%s", "); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_filename],XmlabelString,Simple_string); <dp n="d70"/> p.45 XmStringFree(Simple_string); return; } fwrite(&Header,sizeof(Header_data),1,fp); fwrite(LuminanceImage,ImgBufSiz_char,1,fp); fdose(fp); TmpPtr1=(unsigned char(*)[])HistogramedImage; for(i=CenterOffset Y,j=0;i<(CenterOffset Y+CenteredImage_len);i++,j++) for(k=CenterOffsetX,l=0;k<(CenterOffsetX+CenteredImage_wid); k++,l++) { Image1[j][l]=TmpPtr1[i][k]; Image3[j+1][l+1]=TmpPtr1[i][k]; } for(j=0;j<CenteredImage_len+1;j++)Image3[j][0]=0; for(l=0;l<CenteredImage_wid+1;l++)Image3[0][1]=0; /* Output luminance centered image file */ InversePoint((Header.OLeftX-CenterOffsetX+block_stuffTmp[0].ColDiff), (Header. OLeftY-CenterOffsetY+block_stuffTmp[0].RowDiff), &TmpVal1,&TmpVal2); Header.LeftX=NINT(TmpValI); Header.LeftY=NINT(TmpVal2); InversePoint((Header.ORightX- CenterOffsetX+block_stuffTmp[1].ColDiff), (Header.ORightY-CenterOffsetY+block_stuffTmp[1].RowDiff), &TmpVal1,&TmpVal2); Header.RightX=NINT(TmpVal1); Header.RightY=NINT(TmpVal2); InversePoint((Header.OMouthX- CenterOffsetX+block_stuffTmp[1].ColDiff), (Header.OMouthY-CenterOffsetY+block_stuffTmp[1].RowDiff), &TmpVal1,&TmpVal2); Header.MouthX=NINT(TmpVal1); Header.MouSY=NINT(TmpVal2); if((fp=fopen(Norm_filename,"wb"))==NULL) { sprintf(Text,"%s\0","Unable to open normalized file"); <dp n="d71"/> p.46 Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_error_message],XmNmessageString, Simple_string); VUIT_Manage("Error_message"); XmStringFree(Simple_string); sprintf(Text,"%s"," "); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_filename],XmNlabelString,Simple_string); XmS tringFree(Simple_string); return; } fwrite(&Header,sizeof(Header_data),1,fp); fwrite(Imagel,sizeof(Imagel),1,fp); fclose(fp); /* Convolve and down sample image*/ for(i=1,j=0;i<(CenteredImage_len);i+=2,j++) { for(k=1,l=0;k<(CenteredImage_wid);k+=2,1++) { TmpVal2=0; for(m=0;m<3;m++) for(n=0;n<3;n++) { TmpVal1=(float)Image3[i+m][k+n]; TmpVal2+=(TmpVal1*DwsmpMat[m][n]); } if(TmpVal2>255.)TmpVal2=255.; if(TmpVal2<0.)TmpVal2=0.; Image2[j][1]=(unsigned char) TmpVal2; } } /* Output luminance centered and downsampled image file */ InversePoint((Header.OLeftX-CenterOffsetX+block_stuffTmp[0].ColDiff), (Header.OLeftY-CenterOffsetY+block_stuffTmp[0].RowDiff), &TmpVal1,&TmpVal2); Header.LeftX=NINT(TmpVal1)/2; Header.LeftY=NINT(TmpVal2)/2; InversePoint((Header.ORightX- CenterOffsetX+block_stuffTmp[1].ColDiff), <dp n="d72"/> p.47 (Header.ORightY-CenterOffsetY+block_stuffTmp[1].RowDiff), &TmpVal1,&TmpVal2); Header.RightX=NINT(TmpVal1)/2; Header.RightY=NINT(TmpVal2)/2; InversePoint((Header.OMouthX- CenterOffsetX+block_stuffTmp[1].ColDiff), (Header.OMouthY-CenterOffsetY+block_stuffTmp[1].RowDiff), &TmpVal1,&TmpVal2); Header.MouthX=NINT(TmpVal1)/2; Header.MouthY=NINT(TmpVal2)/2; if((fp=fopen(Dsmp_filename,"wb"))==NULL) { sprintf(Text,"%s\0","Unable to open luminance downsampled file"); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_error_message],XmNmessageString, Simple_string); VUIT_Manage("Error_message"); XmStringFree(Simple_string); sprintf(Text,"%s", "); Simple_string=XnStringCreateSimple(Text); set_something(Widget_id[K_filename],XmNlabelString,Simple_string); XmStringFree(Simple_string); return; } fwrite(&Header,sizeof(Header_data),1,fp); fwrite(Image2,sizeof(Image2),1,fp); fclose(fp); /* Output color centered and downsampled image file*/ /* Convolve and down sample red color image*/ FlipImage(Red); Tmp=Red; for(i=0;i<Img_len;i++) for(j=0;j<Img_wid;j++)*Tmp++=*Tmp<<3; TmpPtr1=(unsigned char(*)[])Red; for(i=CenterOffsetY,j=0;i<(CenterOffsetY+CenteredImage_len);i++,j++) for(k=CenterOffsetX,l=0;k<(CenterOffsetX+CenteredImage_wid); k++,l++) Image3[j+1][l+1]=TmpPtr1[i][k]; <dp n="d73"/> p.48 for(j=0;j<CenteredImage_len+1;j++)Image3[j][0]=0; for(l=0;l<CenteredImage_wid+1;l++)Image3[0][1]=0; for(i=1,j=0;i<(CenteredImage_len);i+=2,j++) for(k=1,1=0;k<(CenteredImage_wid);k+=2,1++) { TmpVal2=0; for(m=0;m<3;m++) for(n=0;n<3;n++) { TmpVal1=(float)Image3[i+m][k+n]; TmpVal2+=(TmpVal1*DwsmpMat[m][n]); } if(TmpVal2>255.)TmpVal2=255.; if(TmpVal2<0.)TmpVal2=0.; Image2[j][1]=(unsigned char)TmpVal2; } } if((fp=fopen(Csmp_filename,"wb"))==NULL) { sprintf(Text"%s\0","Unable to open color downsampled file"); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_error_message],XmNmessageString, Simple_string); VUIT_Manage("Error_message"); XmStringFree(Simple_string); sprintf(Text,"%s", "); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_filename],XmNlabelString,Simple_string); XmStringFree(Simple_string); return; } fwrite(&Header,sizeof(Header_data),1,fp); fwrite(Image2,sizeof(Image2),1,fp); /* Convolve and down sample green color image*/ Fliplmage(Green); Tmp=Green; for(i=0;i<Img_len;i++) for(j=0;j<Img_wid;j++)*Tmp++=*Tmp<<3; <dp n="d74"/> p.49 TmpPtr1=(unsigned char (*) []) Green; for(i=CenterOffsetY,j=0;i<(CenterOffsetY+CenteredImage_len);i++,j++) for(k=CenterOffsetX,l=0;k<(CenterOffsetX+CenteredImage_wid); k++,l++) Image3[j+1][l+1]=TmpPtr1[i][k]; for(j=0;j<CenteredImage_len+1;j++)Image3[j][0]=0; for(l=0;l<CenteredImage_wid+1;l++)Image3[0][1]=0; for(i=1,j=0;i<(CenteredImage_len);i+=2,j++) for(k=1,l=0;k<(CenteredImage_wid);k+=2,l++) { TmpVal2=0; for(m=0;m<3;m++) for(n=0;n<3;n++) { TmpVal1=(float)Image3[i+m][k+n]; TmpVal2+=(TmpVal1*DwsmpMat[m][n]); } if(TmpVal2>255.)TmpVal2=255.; if(TmpVal2<0.)TmpVal2=0.; Image2[j][l]=(unsigned char)TmpVal2; } } fwrite(Image2,sizeof(Image2),1,fp); /* Convolve and down sample blue color image*/ FlipImage(Blue); Tmp=Blue; for(i=0;i<Img_len;i++) for(j=0;j<Img_wid;j++)*Tmp++=*Tmp<<3; TmpPtr1=(unsigned char(*)[])Blue; for(i=CenterOffsetY,j=0;i<(CenterOffsetY+CenteredImage_len);i++,j++) for(k=CenterOffsetX,l=0;k<(CenterOffsetX+CenteredImage_wid); k++,l++) Image3[j+1][l+1]=TmpPtr1[i][k]; for(j=0;j<CenteredImage_len+1;j++)Image3[j][0]=0; for(l=0;l<CenteredImage_wid+1;l++)Image3[0][l]=0; for(i=1,j=0;i<(CenteredImage_len);i+=2,j++) <dp n="d75"/> p.50 { for(k=1,l=0;k<(CenteredImage_wid);k+=2,1++) { TmpVal2=0; for(m=0;m<3;m++) for(n=0;n<3;n++) { TmpVal1=(float)Image3[i+m][k+n]; TmpVal2+=(TmpVal1* DwsmpMat[m][n]); } if(TmpVal2>255.)TmpVal2=255.; if(TmpVal2<0.)TmpVal2=0.; Image2[j][1]=(unsigned char)TmpVal2; } } fwrite(Image2,sizeof(Image2),1,fp); fdose(fp); Grid_displayed[K_display_2]=0; DisplayImage(K_display_2,BlankImage Data); Image_displayed[K_display_2]=0; } <dp n="d76"/> p.51 void ButtonDisplayI(Widget w,XtPointer x,XEvent *Event,Boolean *Cont) { XmString Simple_string; XButtonEvent *ButtonEvent; XButtonEvent *ButtonEvent2; int i,j,k,l; char Text[255]; ButtonEvent=(XButtonEvent*)Event; /* Check which button was released*/ if(MF_flag==011 LMD_flag==011 GNG_flag==011 MNM_flag==011 BNB_flag==0) { sprintf(Text,"%s\0","Identification fields not selected"); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_error_message],XmNmessageString, Simple_string); VUIT_Manage("Error_message"); XmStringFree(Simple_string); return; } if(Image_displayed[K_display_1]==1) { if(ButtonEvent->button==1) { LeftEyeX=ButtonEvent->x/2; LeftEyeY=ButtonEvent->y/2; sprinff(Text,"% d",(int)LeftEyeX); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_eye_lx],XmNlabelString,Simple_string); XmStringFree(Simple_string); sprintf(Text,"%d",(int)LeftEyeY); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_eye_ly],XmNlabelString,Simple_string); XmStringFree(Simple_string); <dp n="d77"/> p.52 } else if(ButtonEvent->button==3) { RightEyeX=ButtonEvent->x/2; RightEyeY=ButtonEvent->y/2; sprintf(Text,"%d",(int)RightEyeX); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_eye_rx],XmNlabelString,Simple_string); XmStringFree(Simple_string); sprintf(Text,"%d",(int)RightEyeY); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_eye_ry],XmNlabelString,Simple_string); XmStringFree(Simple_string); } else if(ButtonEvent->button==2) { MouthX=ButtonEvent->x/2; MouthY=ButtonEvent->y/2; sprintf(Text,"% d",(int)MouthX); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_mouth_x],XmNlabelString,Simple_string); XmStringFree(Simple_string); sprintf(Text,"% d",(int)MouthY); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_mouth_y],XmNlabelString,Simple_string); XmStringFree(Simple_string); } } } <dp n="d78"/> p.53 void ButtonDisplay2(Widget w,XtPointer x,XEvent *Event,Boolean *Cont) { #define N 33 XmString Simple_string; XButtonEvent *ButtonEvent; float intv,x1,x2,ratio,mean,cvmean,gammal; floatpct[101],a1[4],a2[4],b1[N],b2[N]; floatlut[256]; int i,j,k,l; int cvpct[101],sum,psum,size; int LocalX,LocalY,BlockX,BlockY; char Text[255]; ldiv_t div; unsigned char *ptr1,*ptr2; ButtonEvent=(XButtonEvent*)Event; if(MF_flag==011 LMD_flag==011 GNG_flag==011MNM_flag==011BNB_flag==0) { sprintf(Text,"%s\0","Identification fields not selected"); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_error_message],XmNmessageString, Simple_string); VUIT_Manage("Error_message"); XmStringFree(Simple_string); return; } /* Check which button was released*/ if(Image_displayed[K_display_2]==1) { if(ButtonEvent->button==1) { LocalX=ButtonEvent->x/2-CenterOffsetX; LocalY=ButtonEvent->y/2-CenterOffsetY; <dp n="d79"/> p.54 BlockX=(LocalX/16)*16+CenterOffsetX; BlockY=(LocalY/16)*16+CenterOffsetY; TmpPtr1=(unsigned char(*)[])CenteredImage; for(i=BIckX;i<BlockX+CMPBLKSIZE;i++) { for(j=BlockY;j<BlockY+CMPBLKSIZE;j++) { Histo[TmpPtr1[j][i]]++; } } /* Histogram block of image image*/ } else if(ButtonEvent->button==2) { /* Shijie*/ #if 0 #define high 230 #define low 25 #define phigh 97 #define plow 5 #define mean_tar 128.0 #endif <dp n="d80"/> p.55 void ResetIDFields() { set_something(Widget_id[K_male],XmNset,False); set_something(Widget_id[K_female],XmNset,False); MF_flag=0; set_something(Widget_id[K_light],XmNset,False); set_something(Widget_id[K_dark],XmNset,False); set_something(Widget_id[K_medium],XmNset,False); LMD_flag=0; set_something(Widget_id[K_glasses],XmNset,False); set_somethirg(Widget_id[K_noglasses],XmNset,False); GNG_flag=0; set_something(Widget_id[K_mustache],XmNset,False); set_something(Widget_id[K_nomustache],XmNset,False); MNM_flag=0; Local_MNM_flag=0; set_something(Widget_id[K_bear d],XmNset,False); set_something(Widget_id[K_nobeard],XmNset,False); BNB_flag=0; Local_BNB_flag=0; set_something(Widget_id[K_fairhair],XmNset,False); FH_flag=0; Header. FairHair=′N′; } int ReadImage(unsigned char *luminance) { XmString Simple_string; int i,j,Filename_len,Full_filename_len,File_len,Dire_len; short int *t_ptr,*T_buf; char*File_ptr,*Tmp,Text[255]; unsigned char*r_ptr,*g_ptr,*b_ptr; /* Open selected file*/ MF_flag=0; LMD_flag=0; GNG_flag=0; MNM_flag=0; BNB_flag=0; FH_flag=0; <dp n="d81"/> p.56 if((fp=fopen(In_filename,"rb"))==NULL) { sprintf(Text,"%s\0","Unable to,open file"); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_error_message],XmNmessageString, Simple_string); VUIT_Manage("Error_message"); XmStringFree(Simple_string); return 0; } strcpy(Unix_filename,In_filename); #if defined VMS i=fgetname(fp,Unix_filename,0); #endif Full_filename_len=strlen(Unix_filename); for(i=Full_filename_len;i>0;-i) if(Unix_filename[i]==′/′)break; File_ptr=&Unix_filename[i+1]; File_len=Unix_filename-File_ptr; File_len+=Full_filename_len; sprintf(Text,"%s",File_ptr); Simple_string=XmStringCreateSimple(Text); set_something(Widget_id[K_filename],XmNlabelString,Simple_string); XmStringFree(Simple_string); void DisplayImage(int Widget_index,unsigned char *Image_data) { int i,Window; XImage *Display_image; Display_id=XtDisplay(Widget_id[Widget_index]); Screen_id=XtScreen(Widget_id[Widget_index]); Screen_num=0; Window=XtWindow(Widget_id[Widget_index]); Default_visual=DefaultVisualOfScreen(Screen_id); Default_depth=DefaultDepth(Display_id,Screen_num); Display_image= XCreateImage(Display_id,Default_visual,Default_depth, ZPixmap,0,(char *)Image_data, <dp n="d82"/> p.57 DisplayWid,DisplayLen,8,0); XPutImage(Display_id,Window,Gc,Display_image,0,0,0,0, DisplayWid,DisplayLen); Image_displayed[Widget_index]=1; if(Widget_index==K_display_2) if(Grid_displayed[K_display_2]==1) { for(i=0;i<CenteredImage_wid*2;i+=CMPBLKSLZE*2) { XDrawRectangle(Display_id,Window,Gc,CenterOffsetX*2, CenterOffsetY*2+i,CMPBLKSIZE*2,CMPBLKSIZE*2); XDrawRectangle(Display_id,Window,Gc,(CenterOffsetX+CMPBLKSIZE )*2, CenterOffsetY*2+i,CMPBLKSIZE*2,CMPBLKSIZE*2); XDrawRectangle(Display_id,Window,Gc,(CenterOffsetX+CMPBLKSIZE*2)*2, CenterOffsetY*2+i,CMPBLKSIZE*2,CMPBLKSIZE*2); XDrawRectangle(Display_id,Window,Gc,(CenterOffsetX+CMPBLKSIZE*3)*2, CenterOffsetY*2+i,CMPBLKSIZE*2,CMPBLKSIZE*2); XDrawRectangle(Display_id,Window,Gc,(CenterOffsetX+CMPBLKSIZE*4)*2, CenterOffsetY*2+i,CMPBLKSIZ*2,CMPBLKSIZE*2); XDrawRectangle(Display_id,Window,Gc,(CenterOffsetX+CMPBLKSIZE*5)*2, CenterOffsetY*2+i,CMPBLKSIZE *2,CMPBLKSIZE*2); XDrawRectangle(Display_id,Window,Gc,(CenterOffsetX+CMPBLKSIZE*6)*2, CenterOffsetY*2+i,CMPBLKSIZE*2,CMPBLKSIZE*2); } XDrawRectangle(Display_id,Window,Gc,(CenterOffsetX+CMPBLKSIZE*2+9)* 2, (CenterOffsetY+CMPBLKSIZE*3+8)*2,2,2); XDrawRectangle(Display_id,Window,Gc,(CenterOffsetX+CMPBLKSIZE*4+7)* 2, (CenterOffsetY+CMPBLKSIZE*3+8)*2,2,2); } Display_image->data=NULL; XDestroyImage(Display_image); } <dp n="d83"/> p.58 void FlipImage(unsigned char *image) { int i,j; unsigned char*backward_ptr,*image_ptr,temp; image_ptr=image; for(i=0;i<Img_len/2;i++) { backward_ptr=image+Img_wid*(Img_len-1-i); for(j=0;j<Img_wid;j++) { temp=*image_ptr; *image_ptr++=*backward_ptr; *backward_ptr++=temp; } } } void SamplePoint(int c,intr,float *x,float *y) { float fl_r,fl_c,temp; fl_r=(float)r; fl_c=(float)c; fl_r-=*beta_gamma; fl_c-=*(beta_gamma+1); fl_r/=alpha; fl_c/=alpha; *y=*T*fl_r+*(T+2)*fl_c+LeftEyeY; *x=*(T+1)*fl_r+*(T+3)*fl_c+LeftEyeX; /* *x=T[0][0]*fl_r+T[1][0]*fl_c+LeftEyeY; *y=T[0][1]*fl_r+T[1][1]*fl_c+LeftEyeX;*/ } void InversePoint(int c,intr,float *x,float *y) { float fl_c,fl_r,temp; float temp_a,temp_b; fl_c=(float)c; fl_r=(float)r; <dp n="d84"/> p.59 temp_a=((fl_r-LeftEyeY)-(*(T+1)*fl_c))/*I; *y=temp_a*alpha+*beta_gamma; temp_b=((fl_c-LeftEyeX)-(*(T+2)*fl_r))/*(T+3); *x=temp_b*alpha+*(beta_gamma+1); } unsigned char Bilinear(unsigned char *original_image, int base_x,int base_y, float weight_x,float weight_y) { float result; unsigned char *ptr; if(base_x<011 base_x>=ORIGINAL_PIXELS-1) result=BackGround; else if(base_y<011 base_y>=ORIGINAL_LINES-1) result=BackGround; else{ ptr=original_image+base_y*ORIGINAL_PIXELS+base_x; result=weight_y*weight_x*(float)*(ptr)+ weight_y*(1.0-weight_x)*(float)*(ptr+1)+ (1.0-weight_y)*weight_x*(float)*(ptr+ORIGINAL_PIXELS)+ (1.0-weight_y)*(1.0-weight_x)*(float)*(ptr+ORIGINAL_PIXELS +1); } return(unsigned char)result; } /* Sub:piecewise smoothing */ void smoothpli(float*Xin,float*Yin,int nl,float intv, float*Xout,float*Yout,int n2) { int i,j,k,m; float de,*u1,*v1,*u,*v; /* interpolate to(n1-2)*2 points*/ m=(n1-1)*2;k=1; u=(float*)malloc(m*sizeof(float)); v=(float*)malloc(m*sizeof(float)); <dp n="d85"/> p.60 for(i=1;i<nl-1;i++) { u[k]=Xin[i]-intv;v[k]=pli(Xin,Yin,n1,u[k]);k++; u[k]=Xin[i]+intv;v[k]=pli(Xin,Yin,n1,u[k]);k++; } u[0]=Xin[0];u[m-1]=Xin[n1-1]; v[0]=Yin[0];v[m-1]=Yin[n1-1]; /* sample n2 points*/ de=1.0*(Xin[n1-1]-Xin[0])/(n2-1); u1=(float*)malloc(n2*sizeof(float)); v1=(float*)malloc(n2*sizeof(float)); for(i=0;i<n2;i++) { u1[i]=u[0]+i*de; v1[i]=pli(u,v,m,u1[i]); /* smooth n2 points*/ for(k=1;k<n2-1;k++) { Xout[k]=u1[k]; Yout[k]=0.5*(v1[k]+0.5*(v1[k-1]+v1[k+1])); } Xout[0]=u1[0];Xout[n2-1]=ul[n2-1]; Yout[0]=v1[0];Yout[n2-1]=vl[n2-1]; free(u);free(v);free(u1);free(v1); return; zoomer(fioat zoom_factor,unsigned char *image,unsigned char *bigger_image) { float weight; int i,j,top; unsigned char*orig_ptr,*big_ptr; <dp n="d86"/> p.61 big_ptr=bigger_image; for(i=0;i<FINAL_LINES;i++) { weight=RIGHT_EYE_ROW+((float)(i-RIGHT_EYE_ROW))/(1.0+ zoom_factor); top=(int)weight; weight-=(float)top; orig_ptr=image+FINAL_PIXELS*top; if(top<011 top>=FINAL_LINES) for(j=0;j<FINAL_PIXELS;j++) { *big_ptr++=(unsigned char)BackGround; orig_ptr++; } else for(j=0;j<FINAL_PIXELS;j++) { *big_ptr++= (unsigned char)(weight*(float)*(orig_ptr+FINAL_PIXELS)+ (1.0-weight)*(float)*orig_ptr); orig_ptr++; } } } /* Sub:piecewise linear interpolation */ float pli(float *Xin,float *Yin,int n1,float x) { float y; int i; if(x<Xin[0])return(Yin[0]); else if(x<Xin[n1-1]) { i=0; while(Xin[i]<=x)i++; y=Yin[i-1]+(Yin[i]-Yin[i-1])*(x-Xin[i-1])/(Xin[i]-Xin[i-1]); return(y); } else return(Yin[n1-1]); } <dp n="d87"/> p.62 /**************************************************************** **/ vertical_block_flip(unsigned char*block,BlockInfo *block_stuff) { int i,j,temp; unsigned char *block_ptr; int offset; int width,height; width=block_stuff->block_width; height=block_stuff->block_height; block_ptr=block; for(j=0;j<height/2;j++){ offset=width*(height-(2*j+1)); for(i=0;i<width;i++){ temp=*block_ptr; *block_ptr=*(block_ptr+offset); *(block_ptr+offset)=temp; block_ptr++; } } } /**************************************************************** / horizontal_block_flip(unsigned char *block,BlockInfo *block_stuff) { int i,j,temp; int width,height; width=block_stuff->block_width; height=block_stuff->block_height; for(i=0;i<width/2;i++) for(j=0;j<height;j++){ temp=*(block+j*width+i); *(block+j*width+i)=*(block+(j+1)*width-(i+1)); *(block+(j+1)*width-(i+1))=temp; } } <dp n="d88"/> p.63 void image_architecture(void) { int i; FILE*fp; fp=fopen("block_structure_information","r"); for(i=0;i<TOTAL_BLOCKS;i++){ fscanf(fp,"%d",&block_stats[i].i_pixel); fscanf(fp,"%d",&block_stats[i].j_pixel); fscanf(fp,"%d",&block_stats[i].block_height); fscanf(fp,"%d",&block_stats[i].block_width); fscanf(fp,"%d",&block_stats[i].bit_depth); fscanf(fp,"%d",&block_stats[i].codebook_type); fscanf(fp,"%d",&block_stats[i].symmetric_block); fscanf(fp,"%d",&block_stats[i].h_flip); fscanf(fp,"%d",&block_stats[i].v_flip); } fclose(fp); } /********************************************************************* ************ * * Name: extract_block * ********************************************************************** *********/ void extract_block(unsigned char *image,unsigned char *block, BlockInfo *block_stuff) { int i,j; int width,height,row,col; unsigned char *block_ptr,*image_ptr; width=block_stuff->block_width; height=block_stuff->block_height; row=block_stuff->i_pixel; col=block_stuff->j_pixel; block_ptr=block; image_ptr=image+row* IMG_WID+col; for(i=0;i<height;i++){ for(j=0;j<width;j++)*block_ptr++=*image_ptr++; imageptr+=(IMG_WID-width); } <dp n="d89"/> p.64 int EyeLocate(unsigned char *image) { #define EYE 5 #define BLOCKENDS 5 register int i,j,k; register int mate; register int best_mse,best_i,best_j; int best_left_i,best_right_i,Eye_side; int best_left_j,best_right_j,Bad,Found; unsigned char block_data[MAX_BLOCK_PIXELS]; for(i=0;i<TOTAL_BLOCKS;i++)block_stats[i].error=0; Eye_side=0; for(k=0;k<TOTAL_BLOCKS;k++) { if(block_stats[k].codebook_type==EYE) { block_stuffTmp[Eye_side]=block_stats[k]; extract_block(image,block_data,&block_stuffTmp[Eye_side]); Found=vq_encode(block_data,&block_stuffTmp[Eye_side]); best_i=0; best_j=0; best_mse=block_stuffTmp[Eye_side].error; if(Found==False)return-1; /* if(Eye_side==0)printf("LEFT EYE"); else printf("RIGHT EYE"); printf("MSE:%6d\n",block_stuffTmp[Eye_side].error); */ block_stuffTmp[Eye_side].i_pixel-=BLOCKENDS; block_stuffTmp[Eye_side].j_pixel-=BLOCKENDS; /*fincthe eye*/ <dp n="d90"/> p.65 for(i=-(BLOCKENDS);i<=BLOCKENDS;i++) { for(j=-(BLOCKENDS);j<=BLOCKENDS;j++) { extract_block(image,block_data,&block_stuffTmp[Eye_side]); Found=vq_encode(block_data,&block_stuffTmp[Eye_side]); if(block_stuffTmp[Eye_side].error<best_mse) { best_i=i; best_j=j; best_mse=block_stuffTmp[Eye_side].error; } /* printf("i:%2d j:%2d MSE:%6d\n",i,j,block_stuffTmp[Eye_side].error); */ block_stuffTmp[Eye_side].j_pixel++; } block_stuffTmp[Eye_side].i_pixel++; block_smffTmp[Eye_side].j_pixel-=(BLOCKENDS*2+1); } block_stuffTmp[Eye_side].i_pixel-=(BLOCKENDS*2); block_stuffTmp[Eye_side].j_pixel++; /* printf("i:%2d j:%2d MSE:%6d\n", best_i,best_j,best_mse); */ block_stuffTmp[Eye_side].RowDiff=best_i; block_stuffTmp[Eye_side].ColDiff=best_j; Eye_side++; } } Bad=False; if(best_left_i==best_right_i)Bad=True; if(best_left_j==best_right_j)Bad=True; return Bad; } /************************************************************** ******** <dp n="d91"/> p.66 * Name: vq_encode ************************************************************************************************ *******/ int vq_encode(unsigned char *block,BlockInfo *block_stuff) { int i,j,k; int pix_per_block; int num_vectors; int mse,Found; unsigned char *codebook,Flags[5]; /* * Initialize the codebook that is going to be used. */ pix_per_block=block_stuff->block_height*block_stuff->block_width; num_vectors=block_stuff->bit_depth; /* Generate codebook offset*/ sprintf(Flags,"%c%c%c%c",Header.Sex,Header.Color, Header.Glasses,′N′); Flags[4]=0; for(i=0,Found=False;i<CLASSES_TOTAL;i++) { if((strstr(dasses[i],Flags))!=NULL) { Found=True; break; } } if(Found==True) { codebook=EyeCodeBook[i]; if(block_stuff->h_flip==1) horizontal_block_flip(block,block_stuff); if(block_stuff->v_flip==1) vertical_block_flip(block,block_stuff); /* * Determine the best codevector for the image block */ <dp n="d92"/> p.67 block_stuff->error=mean_square_error(block,codebook,pix_per_block); block_stuff->codevalue=0; for(k=1;k<num_vectors;k++){ codebook+=pix_per_block; mse=mean_square_check(block,codebook,pix_per_block, block_stuff->error); if(mse<block_stuff->error){ block_stuff->error=mse; block_stuff->codevalue=k; } } } } int mean_square_error(unsigned char *x,unsigned char *y,int length) { register i; int result; unsigned char *x_ptr,*y_ptr; int *mse_table_ptr; result=0; x_ptr=x; y_ptr=y; mse_table_ptr=&mse_table[256]; for(i=0;i<length;i++) result+=*(mse_table_ptr+((int)*x_ptr++-(int)*y_ptr++)); return result; } int mean_square_check(unsigned char *x,unsigned char *y,int length, int lowest_so_far) { register i; int result; unsigned char *x_ptr,*y_ptr; int*mse_table_ptr; result=0; x_ptr=x; y_ptr=y; mse_table_ptr=&mse_table[256]; <dp n="d93"/> p.68 for(i=0;i<length/2;i++){ result+=*(mse_table_ptr+((int)*x_ptr++-(int)*y_ptr++)); result+=*(mse_table_ptr+((int)*x_ptr++-(int)*y_ptr++)); if(lowest_so_far<result)break; } return result; } /* Simplified SET VALUE routine to use only when changing a single attribute. *If we need to change more than one,all new values should be put *into one arglist and we should make one XtSetValues call(which is MUCH *more efficient). */ static void set_something(w,resource,value) Widget w; char *resource,*value; { Arg al[1]; if(w==NULL)return; XtSetArg(al[0],resource,value); XtSetValues(w,al,1); } /* *Simplified GET VALUE routine to use only when retrieving a single attribute. *If we need to retrieve more than one,all values should be put *into one arglist and we should make one XtGetValues call(which is MUCH *more efficient). */ static void get_something(w,resource,value) Widget w; char *resource,*value; { Arg al[1]; if(w==NULL)return; XtSetArg(al[0],resource,value); <dp n="d94"/> p.69 XtGetValues(w,al,1); } <dp n="d95"/> Standardizer p.1 Appendix B-Docket # 71,250 &71,412 1993,1994 Eastman Kodak Company,Rochester,N.Y.14650-2201 /* *standardizer.c * *Description:Form standardized image by adjusting luminence level of standardized geometric image * *Copyright Eastman Kodak Company,1993,1994 */ #include<stdio.h> #include<string.h> #include<malloc.h> #include<math.h> #define FALSE 0 #define TRUE 1 #define PIXELS_PER_LINE 56 #define LINES_PER_IMAGE 64 #define IMAGE_PIXELS (PIXELS_PER_LINE * LINES_PER_IMAGE) #define LEFT_X 16 #define RIGHT_X 40 #define MID_X ((LEFI_X+RIGHT_X)/2) #define HALF_GAP_X ((RIGHT_X-LEFT_X)/2) #define TOP_Y 24 #define BOTTOM_Y 52 #define MID_Y ((TOP_Y+BOTTOM_Y)/2) #define HALF_GAP_Y ((BOTTOM_Y-TOP_Y)/2) #define SKIN_PIXELS ((LEFT_X-RIGHT_X)*(TOP_Y-BOTTOM_Y)) #define RAMP 0.45 #define SCALE 1024 #define SKIN 135 #define SPEC 175 #define TRAIN_IMAGES_MIN 1 #define TRAIN_IMAGES_MAX 2000 #define HEADER_BYTES 40 #define FEATURES 12 #define FEATURE_TYPES (2*CB+1) <dp n="d96"/> Standardizer p.2 int mean_outer_mask[VERTICAL_BLOCKS][HORIZONTAL_BLOCKS]={0,1,1,0,- 1,-1,0,3,1,1,0,-1,-1,-3,3,4,4,4,4,4,-3,3,4,4,4,4,4,-3,3,4,4,4,4,4,-3,3,4,4,4,4,4,-3, 0,4,4,4,4,4,0,0,0,0,0,0,0,0}; int mean_inner_mask[VERTICAL_BRICKS][HORIZONTAL_BRICKS]={0,0,0,0, 0,0,6,10,-6,0,4,5,10,-5,-4,8,6,10,-6,-8,8,8,10,-8,-8,9,12,7,-12,-9,9,12,7,- 12,-9,0,2,11,-2,0}; int contrast_outer_mask[VERTICAL_BLOCKS][HORIZONTAL_BLOCKS]={3,1,1, 1,-1,-1,-3,3,1,1,1,-1,-1,-3,3,4,4,4,4,4,-3,3,4,4,4,4,4,-3,3,4,4,4,4,4,-3,3,4,4,4,4, 4,-3,3,4,4,4,4,4,-3,3,3,2,11,-2,-3,-3}; int contrast_inner_mask[VERTICAL_BRICKS][HORIZONTAL_BRICKS]={4,10, 10,10,-4,4,6,10,-6,-4,4,5,10,-5,-4,8,6,10,-6,-8,8,8,10,-8,-8,9,12,7,-12,-9,9, 12,7,-12,-9,9,2,11,-2,-9}; int mean_pixels[FEATURE_TYPES]; int contrast_pixels[FEATURE_TYPES]; int mean_luminance[FEATURE_TYPES]; int mean_mse[FEATURE_TYPES]; int mask_enhancement[FEATURE_TYPES]; int centerline_table[PIXELS_PER_LINE]; main(argc,argv) int argc; char *argv[]; { register int i,j,k,m; register int x; register int horizontal_scaling; register int mask; register int tone_adjustment; register int left_right_adjustment; register int top_bottom_adjustment; register int centerline_adjustment; char original_filen[200]; char standardized_filen[200]; unsigned char stand_geom_image[LINES_PER_IMAGE][PIXELS_PER_LINE]; unsigned char standardized_image[LINES_PER_IMAGE][PIXELS_PER_LINE]; int int_image[LINES_PER_IMAGE][PIXELS_PER_LINE]; int mse_image[LINES_PER_IMAGE][PIXELS_PER_LINE]; int contrast_map[LINES_PER_IMAGE][PIXELS_PER_LINE]; int contrast_enhancement[LINES_PER_IMAGE][PIXELS_PER_LINE]; int mean_adjustment_map[LINES_PER_IMAGE][PIXELS_PER_LINE]; int asymmetry_map[LINES_PER_IMAGE][PIXELS_PER_LINE]; int mean_map[LINES_PER_IMAGE][PIXELS_PER_LINE]; <dp n="d97"/> Standardizer p.3 unsigned char nothing_map[LINES_PER_IMAGE][PIXELS_PER_LINE]; unsigned char *nothing_ptr; char header[HEADER_BYTES]; unsigned char *stand_geom_image_ptr; unsigned char *standardized_image_ptr; int *map_ptr,*mean_adjust_map_ptr; int *int_image_ptr; int *mse_image_ptr; int file_number; int left_skin_pixels; int center_skin_pixels; int right_skin_pixels; int skin_tone_left; int skin_tone_center; int skin_tone_right; int skin_tone_top; int skin_tone_bottom; FILE*fp mask_map_maker(mean_outer_mask,mean_inner_mask,mean_map); mask_map_maker(contrast_outer_mask,contrast_inner_mask,contrast_map); /*count pixels for averaging*/ for(i=0;i<FEATURE_TYPES;i++){ mean_pixels[i]=0; contrast_pixels[i]=0; } for(i=0;i<LINES_PER_IMAGE;i++) for(j=0;j<PIXELS_PER_LINE;j++){ k=mean_map[i][j]+CB; if(k<011k>FEATURE_TYPES+1) printf("Out of bounds problem%d%d----%d\n",i,j,mean_map[i][j]); mean_pixels[k]++; k=contrast_map[i][j]+CB; if(k<011k>FEATURE_TYPES+1) printf("Out of bounds%d%d----%d\n",i,j,contrast_map[i][j]); contrast_pixels[k]++; } #define CL_04 #define CL_114 #define CL_2(MID_X-3) <dp n="d98"/> Standardizer p.4 /*construct centerline LUT*/ for(i=0;i<CL_0;i++) centerline_table[i]=0; for(i=CL_0;i<CL_l;i++)centerline_table[i]=SCALE*(i-CL_0)/(CL_1-CL_0); for(i=CL_1;i<CL_2;i++)centerline_table[i]=SCALE- (SCALE*(CL_1-i))/(CL_1-CL_2); for(i=CL_2;i<MID_X+1;i++)centerline_table[i]=0; for(i=1;i<MID_X;i++) centerline_table[PIXELS_PER_LINE-i]= -1*(centerline_table[i-1]+centerline_table[i+1])/2; for(i=1;i<MID_X;i++) centerline_table[i]=-1*centerline_table[PIXELS_PER_LINE-i]; left_skin_pixels=mean_pixels[CB+4]+mean_pixels[CB+6]+ mean_pixels[CB+9]+mean_pixels[CB+12]; right_skin_pixels=mean_pixels[CB4]+mean_pixels[CB-6]+ mean_pixels[CB-9]+mean_pixels[CB-12]; center_skin_pixels=mean_pixels[CB+10]+mean_pixels[CB+12]+ mean_pixels[CB-12]; /*Read in input image*/ for(file_number=TRAIN_IMAGES_MIN; file_number<_TRAIN_IMAGES_MAX;file_number++){ /*read the original file*/ sprintf(original_files,"/sg_images/f%04d",file_number); if((fp=fopen(original_filen,"rb" ))==NULL){ printf("***Error-opening%s for reading\n",original_filen); fclose(fp); } else{ fread(header,sizeof(char),HEADER_BYTES,fp); fread(stand_geom_image,IMAGE_PIXELS*sizeof(unsigned char),1,fp); fclose(fp); memset(nothing_map,(unsigned char)′\0′,IMAGE_PIXELS); for(i=0;i<PIXELS_PER_LINE;i++){ stand_geom_image_ptr=&stand_geom_image[0][i]; nothing_ptr=&nothing_map[0][i]; for(j=0;j<LINES_PER_IMAGE;j++){ if(*stand_geom_image_ptr== *(stand_geom_image_ptr+PIXELS_PER_LINE)){ *nothing_ptr=(unsigned char)255; nothing_ptr+=PIXELS_PER_LINE; stand_geom_image_ptr+=PIXELS_PER_LINE; }. else break; } <dp n="d99"/> Standardizer p.5 } for(i=0;i<PIXELS_PER_LINE;i++){ stand_geom_image_ptr=&stand_geom_image[LINES_PER_IMAGE-2][i]; nothing_ptr=&nothing_map[LINES_PER_IMAGE-2][i]; for(j=0;j<LINES_PER_IMAGE;j++){ if(*stand_geom_image_ptr== *(stand_geom_imageptr-PIXELS_PER_LINE)){ *nothing_ptr=(unsigned char)255; nothing_ptr-=PIXELS_PER_LINE; stand_geom_image_ptr-=PIXELS_PER_LINE; } else break; } } /*find present mean skin tone per region,both right and left*/ for(i=0;i<FEATURE_TYPES;i++)mean_luminance[i]=0; stand_geom_image_ptr=&stand_geom_image[0][0]; map_ptr=&mean_map[0][0]; for(i=0;i<IMAGE_PIXELS;i++){ mask=CB+*map_ptr++; mean_luminance[mask]+=(int)*(stand_geom_image_ptr++); } skin_tone_left=mean_luminance[CB+4]+mean_luminance[CB+6]+ mean_luminance[CB+9]+mean_luminance[CB+12]; skin_tone_right=mean_luminance[CB-4]+mean_luminance[CB-6]+ mean_luminance[CB-9]+mean_luminance[CB-12]; skin_tone_center=mean_luminance[CB+10]+mean_luminance[CB+12]+ mean_luminance[CB-12]; for(i=0;i<FEATURE_TYPES;i++) if(mean_pixels[i]!=0)mean_luminance[i]/=mean_pixels[i]; /*calculate region averages*/ skin_tone_left/=left_skin_pixels; skin_tone_right/=right_skin_pixels; skin_tone_center/=center_skin_pixels; skin_tone_top=(mean_luminance[CB+10]+mean_luminance[CB+4]+ mean_luminance[CB-4]+mean_luminance[CB+6]+ mean_luminance[CB-6])/5; skin_tone_bottom=(mean_luminance[CB+12]+mean_luminance[CB-12]+ mean_luminance[CB+11])/3; /*adjust image to mean and equal left right luminance*/ left_right_adjustment=(int)(SCALE*RAMP* (float)(skin_tone_left-skin_tone_right)/(float)(MID_X-LEFT_X)); <dp n="d100"/> Standardizer p.6 top_bottom_adjustment=(int)((SCALE*RAMP*((float)skin_tone_top- (float)skin_tone_bottom))/(float)(MID_Y-TOP_Y)); /*compensate for symmetric flash drop off from nose*/ /*add to reduce side shadows*/ centeriine_adjustment=(int)(SCALE*0.8*(float)(skin_tone_center- (skin_tone_right+skin_tone_left)/2)/(float)(MID_X-LEFT_X)); /*adjust original image for low frequency lighting*/ stand_geom_image_ptr=&stand_geom_image[0][0]; int_image_ptr=&int_image[0][0]; standardized_image_ptr=&standardized_image[0][0]; for(j=0;j<LINES_PER_IMAGE;j++){ if(j<TOP_Y){ k=-1*top_bottom_adjustment*HALF_GAP_Y; horizontal_scaling=0; } else if(j>BOTTOM_Y){ k=top_bottom_adjustment*HALF_GAP_Y; horizontal_scaling=0; } else{ k=top_bottom_adjustment*(j-MID_Y); horizontal_scaling=HALF_GAP_Y-abs(j-MID_Y); } for(i=0;i<PIXELS_PER_LINE;i++){ if(i<LEFT_X)x=LEFT_X; else if(i>RIGHT_X)x=RIGHT_X; else x=i; m=(k+(x-MID_X)* (left_right_adjustment-horizontal_scaling*centerline_table[i] *centerline_adjustment/(SCALE*HALF_GAP_Y)))/SCALE; *(int_image_ptr++)=((int)*(stand_geom_image_ptr++))+m; } } /*Suppress speculars points in the image*/ /*base on tone adjustment*/ tone_adjustment=SKIN-skin_tone_center; specular_suppressor(int_image,SPEC-tone_adjustment); /*initialize mse and luminance masks*/ for(i=0;i<FEATURE_TYPES;i++){ mean_mse[i]=1; mean_luminance[i]=0; } /*find new mean for each region*/ int_image_ptr=&int_image[0][0]; <dp n="d101"/> Standardizer p.7 map_ptr=&mean_map[0][0]; for(i=0;i<IMAGE_PIXELS;i++) mean_luminance[CB+*map_ptr++]+=*(int_image_ptr++); skin_tone_left=mean_luminance[CB+4]+mean_luminance[CB+6]+ mean_luminance[CB+9]+mean_luminance[CB+12]; skin_tone_right=mean_luminance[CB-4]+mean_luminance[CB-6]+ mean_luminance[CB-9]+mean_luminance[CB-12]; skin_tone_center=mean_luminance[CB+10]+mean_luminance[CB+12]+ mean_luminance[CB-12]; for(i=0;i<FEATURE_TYPES;i++) if(mean_pixels[i]!=0)mean_luminance[i]/=mean_pixels[i]; /*calculate region averages*/ skin_tone_left/=left_skin_pixels; skin_tone_right/=right_skin_pixels; skin_tone_center/=center_skin_pixels; /*Suppress speculars points in the image*/ /*base on tone adjustment*/ tone_adjustment=SKIN-skin_tone_center; specular_suppressor(int_image,SPEC-tone_adjustment); memcpy(mean_adjustment_map,int_image,sizeof(int)*IMAGE_PIXELS); smooth_all(mean_adjustment_map); smooth_all(mean_adjustment_map); smooth_all(mean_adjustment_map); /*find new contrast for each region based on smoothed mean*/ int_image_ptr=&int_image[0][0]; mean_adjust_map_ptr=&mean_adjustment_map[0][0]; mse_image_ptr=&mse_image[0][0]; map_ptr=&contrast_map[0][0]; j=SPEC-tone_adjustment; for(i=0;i<IMAGE_PIXELS;i++){ mask=*(map_ptr++); *mse_image_ptr=*int_image_ptr-*(mean_adjust_map_ptr++); /* reduce the contribution to mse of specular pixels*/ if(*(int_image_ptr++)>j)*mse_image_ptr/=2; if(*mse_image_ptr>255)mean_mse[mask+CB]+=64; else if(*mse_image_ptr<-255)mean_mse[mask+CB]+=64; else mean_mse[mask+CB]+=mse_table[256+*mse_image_ptr]; mse_image_ptr++; } /*calculate contrast enhancement value for each block*/ for(i=0;i<FEATURE_TYPES;i++) mask_enhancement[i]=(16* SCALE)*contrast_pixels[i]/mean_mse[i]; <dp n="d102"/> Standardizer p.8 /*enhance mouth*/ mask_enhancement[CB+7]+=i+SCALE/4; i=mask_enhancement[CB+12]+mask_enhancement[CB-12]; mask_enhancement[CB+12]+=i+SCALE/2; mask_enhancement[CB+12]/=3; mask_enhancement[CB-12]+=i+SCALE/2; mask_enhancement[CB-12]/=3; /*tone down the lower cheek*/ mask_enhancement[CB+9]-=SCALE/3; mask_en_hancement[CB-9]-=SCALE/3; /*tone down and average the temples*/ i=mask_enhancement[CB+4]; mask_enhancement[CB+4]= (3*mask_enhancement[CB+4]+mask_enhancement[CB-4]-2*SCALE)/4; mask_enhancement[CB-4]=(3*mask_enhancement[CB-4]+i-2*SCALE)/4; /*move side closer to temple value*/ mask_enhancement[CB+3]=(mask_enhancement[CB+3]+ 3*mask_enhancement[CB+4])/4; mask_enhancement[CB-3]=(mask_enhancement[CB-3]+ 3*mask_enhancement[CB-4])/4; mask_enhancement[CB+1]=(mask_enhancement[CB+1]-SCALE +3*mask_en_hancement[CB+4])/4; mask_enhancement[CB-1]=(mask_enhancement[CB-1]-SCALE +3*mask_enhancement[CB-4])/4; mask_enhancement[CB+5]=(mask_enhancement[CB-5] +mask_enhancement[CB+5])/2; mask_enhancement[CB+5]=(mask_enhancement[CB+5]+SCALE)/2; mask_enhancement[CB-5]=mask_enhancement[CB+5]; mask_enhancement[CB+6]= (mask_enhancement[CB+5]+mask_enhancement[CB+6])/2; mask_enhancement[CB-6]= (mask_enhancement[CB-5]+mask_enhancement[CB-6])/2; /*adjust contrast*/ map_ptr=&contrast_map[0][0]; mean_adjust_map_ptr=&contrast_enhancement[0][0]; for(i=0;i<IMAGE_PIXELS;i++) *mean_adjust_map_ptr++=mask_enhancement[CB+*map_ptr++]; /*use specular supressor on the contrast*/ specular_suppressor(contrast_enhancement,300*SCALE/100); smooth_all(contrast_enhancement); <dp n="d103"/> Standardizer p.9 smooth_all(contrast_enhancement); smooth_all(contrast_enhancement); smooth_all(contrast_enhancement); smooth_all(contrast_enhancement); /*adjust mean luminance*/ memcpy(mean_adjustment_map,int_image,sizeof(int)*IMAGE_PIXELS); smooth_all(mean_adjustment_map); smooth_ail(mean_adjustment_map); smooth_all(mean_adjustment_map); /*check on asymmetry in lighting which still remains*/ k=0; for(i=20;i<LINES_PER_IMAGE-8;i++) for(j=14;j<(PIXELS_PER_LINE/2)-1;j++){ m=(mean_adjustment_map[i][j] mean_adjustment_map[i][PIXELS_PER_LINE-j])/2; /*shift towards each other*/ asymmetry_map[i][j]=-1*m; asymmetry_map[i][PIXELS_PER_LINE-j]=m; k+=abs(m); } average_asymmetry=k/ ((LINES_PER_IMAGE-16)*(PIXELS_PER_LINE/2-8)); smooth_all(asymmetry_map); smooth_all(asymmetry_map); smooth_all(asymmetry_map); smooth_all(asymmetry_map); int_image_ptr=&int_image[0][0]; map_ptr=&asymmetry_map[0][0]; for(i=0;i<IMAGE_PIXELS;i++)*(int_image_ptr++)+=*(map_ptr++); /*adjust mean luminance*/ memcpy(mean_adjustment_map,int_image,sizeof(int)*IMAGE_PIXELS); smooth_all(mean_adjustment_map); smooth_all(mean_adjustment_map); standardized_image_ptr=&standardized_image[0][0]; int_image_ptr=&int_image[0][0]; map_ptr=&contrast_enhancement[0][0]; mean_adjust_map_ptr=&mean_adjustment_map[0][0]; for(i=0;i<IMAGE_PIXELS;i++){ k=tone_adjustment+*mean_adjust_map_ptr+ ((*(int_image_ptr++)-*mean_adjust_map_ptr++)*map_ptr++)/SCALE; if(k>254)*(standardized_image_ptr++)=(unsigned char)255; <dp n="d104"/> Standardizer p.10 else if(k<1)*(standardized_image_ptr++)=(unsigned char)0; else*(standardized_image_ptr++)=(unsigned char)k; } standardized_image_ptr=&standardized_image[0][0]; nothing_ptr=&nothing_map[0][0]; for(i=0;i<IMAGE_PIXELS;i++) *standardized_image_ptr++=*(nothing_ptr++)1*standardized_image_ptr; /*write out the standardized file*/ sprintf(stan dardized_filen,"/standardized_images/f%04d",file_number); if((fp=fopen(standardized_filen,"wb"))==NULL){ printf("Cannot write out standardized image file.\n"); exit(-1); } fwrite(header,HEADER_BYTES*sizeof(unsigned char),1,fp); fwrite(standardized_image,IMAGE_PIXELS*sizeof(unsigned char),1,fp); fclose(fp); } } } mask_map_maker(outer,inner,map) int *outer,*inner,*map; { int i,j,k,m; int *map_ptr; int *inner_ptr,*outer_ptr; map_ptr=map; outer_ptr=outer; for(i=0;i<8;i++){ for(j=0;j<7;j++){ for(k=0;k<8;k++){ for(m=0;m<8;m++)*map_ptr++=*outer_ptr; map_ptr+=PIXELS_PER_LINE-8; } map_ptr-=8*PIXELS_PER_LINE-8; outer_ptr++; } map_ptr+=7*PIXELS_PER_LINE; } inner_ptr=inner; map_ptr=map+16*PIXELS_PER_LINE+8; for(i=0;i<8;i++){ for(j=0;j<5;j++){ for(k=0;k<5;k++){ for(m=0;m<8;m++)*map_ptr++=*inner_ptr; <dp n="d105"/> Standardizer p.11 map_ptr+=PIXELS_PER_LINE-8; } map_ptr-=5*PIXELS_PER_LINE-8; inner_ptr++; } map_ptr+=4*PIXELS_PER_LINE+16; } map_ptr=map; } smooth_all(image) int*image; { register int i,j; int temporary_image[LINES_PER_IMAGE][PIXELS_PER_LINE]; int*image_ptr,*temp_ptr; image_ptr=image+3*PIXELS_PER_LINE+3; temp_ptr=&temporary_image[3][3]; memcpy(temporary_image,image,sizeof(int)*IMAGE_PIXELS); for(i=3;i<LINES_PER_IMAGE-3;i++){ for(j=3;j<PIXELS_PER_LINE-3;j++){ *(temp_ptr++)=(*(image_ptr-2*PIXELS_PER_LINE)+*(image_ptr-2)+ 4**image_ptr+*(image_ptr+2)+ *(image_ptr+2*PIXELS_PER_LINE))/8; image_ptr++; } temp_ptr+=6; image_ptr+=6; } memcpy(image,temporary_image,sizeof(int)*IMAGE_PIXELS); } specular_suppressor(image,specular) int *image; int specular; { register int i; int *image_ptr; image_ptr=image; for(i=0;i<IMAGE_PIXELS;i++){ if(*image_ptr>specular)*image_ptr=specular+(*image_ptr-specular)/2; image_ptr++; } } <dp n="d106"/> Trainer p.1 Appendix C-Docket#71,250 1993,1994Eastman Kodak Company,Rochester,N.Y.14650-2201 /* *trainer.c * *Description:Train on standardized images to form codebooks for feature types */ #include<stdio.h> #include<math.h> #define FALSE 0 #define TRUE 1 #define PIXELS_PER_LINE 56 #define LINES_PER_IMAGE 64 #define MAX_CODEVECTORS 256 #define PIXELS_PER_IMAGE PIXELS_PER_LINE*LINES_PER_IMAGE #define MAX_CODEVECTOR_PIXELS 64 #define CLOSE_ENOUGH_TO_MERGE 2 #define OUTLIERS_KILL_PERCENT 2 #define ITERATIONS_MAX 100 #define ITERATIONS_MIN 20 #define CONVERGENCE_CRITERION 0.000002 #define TRAINING_IMAGE_DIR "/standardized_images" #define TRAINING_IMAGE_NAME "f" #define TRAINING_IMAGES_MAX 2000 #define TRAINING_IMAGE_PIXELS PIXELS_PER_IMAGE #define HEADER_BYTES 40 #define HISTORY_MEMORY 8 #define FEATURE_TYPES 13 #define TRAINING_VECTORS_MAX (10*TRAINING_IMAGES_MAX) #define MAX_ELEMENTS 64 struct ElementRecord{ int i_pixel; int j_pixel; int block_height; <dp n="d107"/> Trainer p.2 int block_width; int codevectors_total; int feature_type; int linked_group; int h_flip; int v_flip; int codevalue; int error; }; int number_of_codes; int number_of_vectors; int vector_length; int vector[TRAINING_VECTORS_MAX][MAX_CODEVECTOR_PIXELS]; int input_image[LINES_PER_IMAGE][PIXELS_PER_LINE]; int centroid[MAX_CODEVECTORS][MAX_CODEVECTOR_PIXELS]; int codevector_closest_centroid[TRAINING_VECTORS_MAX]; int centroid_extent[MAX_CODEVECTORS]; int codevector_per_centroid[MAX_CODEVECTORS]; int far_away[MAX_CODEVECTORS]; float mse_history[HISTORY_MEMORY]; float average_mse; float best_mse; int closest_centroid_distance; int mse; int mse_previous; int mse_test; struct ElementRecord element_record[MAX_ELEMENTS]; int feature_type; int training_vectors; int vectors_per_code_min; int iteration; int completion_flag; int convergence_flag; void write_codebook(); int mean_square_error(); int reassign_codevectors(); int find_extent(); void reorder_partitions(); void outlier_zapper(); void explode_a_centroid(); <dp n="d108"/> Trainer p.3 main(argc,argv) char*argv[]; int argc; { register int i,j,k; register int ix,iy; int num_img_vectors; int image_number; int all_codebook_flag; int low_vector; int high_vector; int starting_vectors; int denominator; int max_extent; int max_extent_code; char training_image_path_and_file[80]; char codebook_filename[80]; unsigned char training_image[LINES_PER_IMAGE][PIXELS_PER_LINE]; FILE *fp; int *vector_ptr; int *centroid_ptr; read_feature_template(); strcpy(codebook_filename,"book"); all_codebook_flag=FALSE; if(feature_type<0){ /*do all codebooks*/ all_codebook_flag=TRUE; feature_type=1; } do{ /*Number of Codevectors in codebook*/ best_mse=64.0*256.0*256.0; num_img_vectors=0; vector_length=0; for(i=0;i<MAX_ELEMENTS;i++){ if(element_record[i].feature_type==feature_type){ number_of_codes=element_record[i].codevectors_total; vector_length=element_record[i].block_width* element_record[i].block_height; } if(vector_length!=0)break; } printf("Vector length=%d\n",vector_length); <dp n="d109"/> Trainer p.4 printf("Codebook %d\n",feature_type); /*Read training images*/ image_number=1; training_vectors=0; training_images=0; k=0; wlile(image_number<TRAINING_IMAGES_MAX){ sprintf(training_image_path_and_file,"%s/%s%04d", TRAINING_IMAGE_DIR,TRAINING_IMAGE_NAME,image_number); if((fp=fopen(training_image_path_and_file,"rb"))!=NULL){ fread(training_image,sizeof(char),HEADER_BYTES,fp); fread(training_image,sizeof(char),TRAINING_IMAGE_PIXELS,fp); training_images++; for(i=0;i<LINES_PER_IMAGE;i++) for(j=0;j<PIXELS_PER_LINE;j++) input_image[i][j]=(int)training_image[i][j]; for(i=0;i<MAX_ELEMENTS;i++){ if(element_record[i].feature_type==feature_type){ extract_block(input_image,vector[training_vectors][0],&element_record[i]); /*check if any BLANKS are in training vector*/ for(j=0;j<vector_length;j++)if(vector[training_vectors][j]==255)break; if(j==vector_length){ if(element_record[i].h_flip==1) horrizontal_flip_block(&vector[training_vectors][0], &element_record[i]); if(element_record[i].v_flip==1) vertical_flip_block(&vector[training_vectors][0],&element_record[i]); training_vectors++; } else k++; } } fclose(fp); } image_number++; } printf("Number of vectors selected %d\n",training_vectors); printf("Number of vectors rejected %d\n",k); printf("Images:%4d scanned\r",training_images); fflush(stdout); printf("\n"); /*Number of training vectors included*/ printf("Portraits %d\n",training_images); printf("Total codevectors:%d\n",training_vectors); <dp n="d110"/> Trainer p.5 starting_vectors=training_vectors/number_of_codes; vectors_per_code_min=starting_vectors/10; for(i=0;i<number_of_cocles;i++)memcpy(&centroid[i][0],&vector[i][0], sizeof(int)*vector_length); printf("Initial assignment of codevectors\n"); mse=reassign_codevectors(); /*iterate until converged */ nse=0; iteration=0; convergence_flag=FALSE; printf("Begin Iterations\n"); while((iteration<ITERATIONS_MAX)&&(convergence_flag==FALSE) &&(number_of_codes<training_vectors)){ mse_previous=mse; /*has a partition become an empty set?*/ for(i=0;i<number_of_codes-1;i++) if(codevector_per_centroid[i]==0)add_a_partition(i); /*Are two centroids TOO_CLOSE?*/ closest_centroid_distance=64*256*256; for(i=number_of_codes-1;i>0;i-){ if(codevector_per_centroid[i]!=0){ for(j=numbe_of_codes-1;j>i;j-){ mse=mean_square_error(&centroid[i][0],&centroid[j][0]); if(mse<closest_centroid_distance)closest_centroid_distance=mse; if(mse< ((10+iteration)*CLOSE_ENOUGH_TO_MERGE* vector_length)){ /*witch association from j to i*/ for(k=0;k<training_vectors;k++){ if(codevector_closest_centroid[k]==i) codevector_closest_centroid[k]=j; /*add to j's partition,blank outi*/ codevector_per_centroid[j]+=codevector_per_centroid[i]; codevector_per_centroid[i]=0; /*find new entroid for j*/ find_centroid(j,&centroid[j][0]); centroid_extent[j]=find_extent(j); centroid_extent[i]=0; add_a_partition(i); } } } } printf("Closest pair was atdistance %d\n",closest_centroid_distance); /*Get rid of vectors with few vectors*/ <dp n="d111"/> Trainer p.6 if((float)training_vectors/(float)number_of_codes>3.5) { if(iteration>5){ outlier_zapper(); explode_a_centroid(); } } else prinff("Vector to code ratio=%f too small for reduction\n", (float)training_vectors/(float)number_of_codes); /* merge the closest partitions*/ for(i=number_of_codes-1;i>0;i-){ if(codevector_per_centroid[i]!=0){ for(j=number_of_codes-1;j>i;j-){ mose=mean_square_error(&centroid[i][0],&centroid[j][0]); /*are partitions close?*/ if(100*mse<105*closest_centroid_distance){ /*merge partitions which are closest together*/ /*associate all codevectors to one partition*/ for(k=0;k<training_vectors;k++) if(codevector_dosest_centroid[k]==i) codevector_closest_centroid[k]=j; /*add to one partition,blank out other*/ codevector_per_centroid[j]+=codevector_per_centroid[i]; codevector_per_centroid[i]=0; /*find new entroid for merged partition*/ find_centroid(j,&centroid[j][0]); centroid_extent[j]=find_extent(j); centroid_extent[i]=0; add_a_partition(i); } } } } mse=reassign_codevectors(); /*If fractional change in mse is less than threshold,end iterations*/ average_mse=(float)mse/(float)training_vectors; for(i=0;i<HISTORY_MEMORY-1;i++)mse_history[i]=mse_history[i+1]; mse_history[HISTORY_MEMORY-1]=average_mse; iteration++; if((iteration>ITERATIONS_MIN)&& (CONVERGENCE_CRITERION>fabs(2*mse_history[0]- (mse_history[HSTORY_MEMORY-1]+ mse_history[HISTORY_MEMORY-2])))) convergence_flag=TRUE; printf("\n average mse %d for %d vectors at iteration %d\n", (int)average_mse, training_vectors,iteration); <dp n="d112"/> Trainer p.7 mse_previous=mse; if(average_mse<best_mse){ write_codebook(codebook_filename); best_mse=average_mse; }/*end of iterations*/ printf("\n"); /*End of initial codevector iteration loop*/ if(iteration<4)write_codebook(codebook_flename); feature_type++; }while(all_codebook_flag &&(feature_type<=FEATURE_TYPES)); } extract_block(image,block,element_stuff) int*image; int*block; struct ElementRecord element_stuff; { register int i,j; int*block_ptr; int*image_ptr; block_ptr=block; image_ptr=image+element_stuff.i_pixel*PIXELS_PER_LINE+ element_stuff.j_pixel; for(i=0;i<element_stuff.block_height;i++){ for(j=0;j<element_stuff.block_width;j++)*block_ptr++=*image_ptr++; image_ptr+=PIXELS_PER_LINE-element_stuff.block_width; } } vertical_flip_block(block,element_stuff) int *block; struct Element Record element_stuff; { register int i,j,temp; int*block_ptr; register int offset; block_ptr=block; for(j=0;j<element_stuff.block_height/2;j++){ offset=element_stuff.block_width*(element_stuff.block_height-(2*j+1)); for(i=0;i<element_stuff.block_width;i++){ temp=*block_ptr; *block_ptr=*(block_ptr+offset); *(block_ptr+offset)=temp; block_ptr++; } <dp n="d113"/> Trainer p.8 } } horizontal_flip_block(block,element_stuff) int*block; struct ElementRecord element_stuff; { register int i,j; register int temp; register int width,height; width=element_stuff.block_width; height=element_stuff.block_height; for(i=0;i<width/2;i++) for(j=0;j<height;j++){ temp=*(block+j*width+i); *(block+j*width+i)=*(block+(j+1)*width-(i+1)); *(block+(j+1)*width-(i+1))=temp; } } void write_codebook(codebook_filename) char *codebook_filename; { register int i; register int vector; unsigned char cb_data[MAX_CODEVECTOR_PIXELS]; unsigned char *cb_ptr; int *centroid_ptr; char total_filename[80]; FILE *fp; sprintf(total_filename,"%s_%d",codebook_filename,feature_type); fp=fopen(total_filename,"wb"); if(fp==NULL){ prinff("***Error-opening codebook file for writing\n"); exit(-1); } centroid_ptr=&centroid[0][0]; for(vector=0;vector<number_of_codes;vector++){ cb_ptr=cb_data; for(i=0;i<vector_length;i++) *cb_ptr++=(unsigned char)*(centroid_ptr+i); fwrite(cb_data,vector_length,1,fp); centroid_ptr+=MAX_CODEVECTOR_PIXELS; } fclose(fp); <dp n="d114"/> Trainer p.9 } int mean_square_error(x,y) int *x,*y; { register i; register int result; int final_result; int *x_ptr,*y_ptr; result=0; x_ptr=x; y_ptr=y; for(i=0;i<vector_length;i++){ result+=*((*x_ptr-*y_ptr)*(*x_ptr-*y_ptr)); x_ptr++; y_ptr++; } final_result=result; return final_result; } find_extent(code_value) int code_value; { register int max_extent,current_extent; register int i; max_extent=0; for(i=0;i<training_vectors;i++){ if(codevector_dosest_centroid[i]==code_value){ /*found codevector in partition*/ current_extent=mean_square_error(&vector[i][0],&centroid[code_value][0]); if(max_extent<current_extent){ max_extent=current_extent; far_away[code_value]=i; /*store far away codevector*/ } } } return max_extent; } find_centroid(code_value,centroid) int code_value; int *centroid; { register int i,j,samples; <dp n="d115"/> Trainer p.10 int *centroid_ptr,*vector_ptr; samples=0; centroid_ptr=centroid; for(i=0;i<vector_length;i++)*(centroid_ptr++)=0; for(i=0;i<training_vectors;i++){ if(codevector_closest_centroid[i]==code_value){ samples++; centroid_ptr=centroid; vector_ptr=&vector[i][0]; for(j=0;j<vector_length;j++)*(centroid_ptr++)+=*(vector_ptr++); } } centroid_ptr=centroid; if(samples)for(i=0;i<vector_length;i++)*(centroid_ptr++)/=samples; } add_a_partition(empty_partition) /*passed in value is the index of an empty partition find the partition with the largest extent,split it and put half into the empty partition */ int empty_partition; { register int i; register int mse0,mse1,mse; register int largest_extent; register int widest_partition; register int far_codevector; int other_extreme; int *temp0,*temp1; int centroid_ptr; /*find the widest partition and mark it to be split*/ largest_extent=0; for(i=0;i<number_of_codes;i++) if(centroid_extent[i]>largest_extent){ largest_extent=centroid_extent[i]; widest_partition=i; } codevector_per_centroid[empty_partition]=0; codevector_per_centroid[widest_partition]=0; /*make the extreme point of the widest partition into the centroid of the empty <dp n="d116"/> Trainer p.11 partition*/ memcpy(&centroid[empty_partition][0],&vector[far_away[widest_partition]][0], sizeof(int)*vector_length); for(i=0;i<vector_length;i++){ centroid[empty_partition][i]+=7*centroid[widest_partition][i]; centroid[empty_partition][i]/=8; } /*find codevectors connected to the widest partition*/ far_codevector=far_away[widest_partition]; for(i=0;i<training_vectors;i++){ if(codevector_dosest_centroid[i]==widest_partition){ mse0=mean_square_error(&centroid[empty_partition][0],&vector[i][0]); mse1=mean_square_error(&centroid[widest_partition][0],&vector[i][0]); if(mse0<mse1){ codevector_closest_centroid[i]=empty_partition; codevector_per_centroid[empty_partition]++; } else{ codevector_closest_centroid[i]=widest_partition; codevector_per_centroid[widest_partition]++; } } } /*partition now split,get stats for further splitting operations*/ find_centroid(empty_partition,&centroid[empty_partition][0]); centroid_extent[empty_partition]=find_extent(empty_partition); find_centroid(widest_partition,&centroid[widest_partition][0]); centroid_extent[widest_partition]=find_extent(widest_partition); } int reassign_codevectors() { register int i,j,code_value; register int mse,mse_challenge,mse_aggregate; int max_extent; int max_extent_code; int *count_ptr; int *vector_ptr; printf("Reassigning codevectors to centroids\n"); mse_aggregate=0; count_ptr=codevector_per_centroid; for(i=0;i<number_of_codes;i++)*count_ptr++=0; for(i=0;i<training_vectors;i++){ <dp n="d117"/> Trainer p.12 vector_ptr=&vector[i][0]; /*initialize based on last location value+1*/ mse=1+mean_square_error(&centroid[codevector_closest_centroid[i]][0], vector_ptr); for(j=0;j<number_of_codes;j++){ mse_challenge=mean_square_error&centroid[j][0],vector_ptr); if(mse_challenge<mse){ mse=mse_challenge; code_value=j; } } codevector_per_centroid[code_value]++; codevector_closest_centroid[i]=code_value; mse_aggregate+=mse; } /*renumber the partitions based on quantity of codevectors*/ reorder_partitions(); /*New centroids*/ max_extent=0; max_extent_code=-1; printf("Calculating new centroids and extents...\n"); for(code_value=0;code_value<number_of_codes;code_value++){ find_centroid(code_value,&centroid[code_value][0]); centroid_extent[code_value]=find_extent(code_value); if(centroid_extent[code_value]>max_extent){ max_extent=centroid_extent[code_value]; max_extent_code=code_value; } } printf("max extent->code:%4d,extent:%d,Codebook:%d\n", max_extent_code,max_extent,feature_type); return mse_aggregate; } void reorder_partitions() { register int i,j,k; register int temp; int*codevector_ptr; <dp n="d118"/> Trainer p.13 /* Sort indirect list*/ for(i=0;i<number_of_codes-1;i++) for(j=i+1;j<number_of_codes;j++){ if(codevector_per_centroid[i]<codevector_per_centroid[j]) {/*swap index as well*/ temp=codevector_per_centroid[j]; codevector_percentroid[j]=codevector_per_centroid[i]; codevector_per_centroid[i]=temp; codevector_ptr=codevector_dosest_centroid; for(k=0;k<training_vectors;k++){ if(*codevector_ptr==j) *codevector_ptr=i; else if(*codevector_ptr==i)*codevector_ptr=j;codevector_ptr++; } } } } void outlier_zapper() { register int i,j,k; register int outlier_size,dead_outliers; outlier_size=2; dead_outliers=0; while(100*dead_outliers<OUTLIERS_KILL_PERCENT*number_of_codes){ for(i=number_of_codes-1;i>0;i-){ if(codevector_per_centroid[i]<outlier_size){ k=0; for(j=0;j<training_vectors;j++) if(codevector_dosest_centroid[j]==i){ training_vectors--; memcpy(&vector[j][0],&vector[training_vectors][0], vector_length*sizeof(int)); codevector_closest_centroid[j]= codevector_closest_centroid[training_vectors]; k++; if(k==codevector_per_centroid[i])break; } codevector_per_centroid[i]=0; add_a_partition(i); dead_outliers++; if(100*dead_outliers>OUTLIERS_KILL_PERCENT*number_of_codes)i=0; } } outlier_size++; } <dp n="d119"/> Trainer p.14 } void explode_a_centroid() { register int i,j; int delete_me,wyoming,relocate_me; int mse_best,mse; int new_home; int partition_added; partition_added=0; /*remove centroids if vectors associated with it are below threshold*/ for(i=0;i<number_of_codes;i++){ if(codevector_per_centroid[i]<vectors_per_code_min){ add_a_partition(i); partition_added++; } if(partition_added>10)break; } /*if none below threshold,use smallest one*/ if(partition_added<2){ wyoming=training_vectors; for(i=0;i<number_of_codes;i++) if(codevector_per_centroid[i]<wyoming){ wyoming=codevector_per_centroid[i]; delete_me=i; } relocate_me=0; for(j=0;j<wyoming;j++){ mse_best=1E+20; while(codevector_closest_centroid[relocate_me]!=delete_me)relocate_me++; for(i=0;i<number_of_codes;i++){ if(i!=delete_me){ mse=mean_square_error(&vector[relocate_me][0],&centroid[i][0]); if(mse<mse_best){ new_home=i; mse_best=mse; } } } codevector_closest_centroid[relocate_me]=new_home; } add_a_partition(delete_me); } } <dp n="d120"/> Trainer p.15 read_feature_template() { register int i; FILE *fp; fp=fopen("feature_template","r"); for(i=0;i<MAX_ELEMENTS;i++){ fscanf(fp,"%d",&element_record[i].i_pixel); fscanf(fp,"%d",&element_record[i].j_pixel); fscanf(fp,"%d",&element_record[i].block_height); fscanf(fp,"%d",&element_record[i].block_width); fscanf(fp,"%d",&element_record[i].codevectors_total); fscanf(fp,"% d",&element_record[i].feature_type); fscanf(fp,"% d",&element_record[i].linked_group); fscanf(fp,"%d",&element_record[i].h_flip); fscanf(fp,"%d",&element_record[i].v_flip); } fclose(fp); } <dp n="d121"/> Compressor p.1 Appendix D-Docket # 71,250 1993,1994 Eastman Kodak Company,Rochester,N.Y.14650-2201 /* *compressor.c * *Description:Compress standardized image * *Copyright Eastman Kodak Company,1993-1994 */ #include<stdio.h> #include<malloc.h> #include<math.h> #define FALSE 0 #define TRUE 1 #define MAX_ELEMENTS 64 #define MAX_CODEVECTOR_PIXELS 64 #define PIXELS_PER_LINE 56 #define LINES_PER_IMAGE 64 #define PIXELS_PER_IMAGE PIXELS_PER_LINE*LINES_PER_IMAGE #define FEATURE_TYPES 13 #define HEADER_BYTES 40 #define SIX_BIT_ASCII_CODES 64 #define TRACK_SIZE 76 /*Note this is 76 characters of 6-bit ASCII codes=456 bits*/ /*The compressed image data is 442 bits with 12 bits to record"holes"*/ /* Track one hole definitions*/ #define HOLE0 37-32 /*for start sentinel ETX*/ #define HOLE1 63-32 /*for end sentinel STX*/ typedef struct { unsigned bit0:1; unsigned bit1:1; unsigned bit2:1; unsigned bit3:1; <dp n="d122"/> Compressor p.2 unsigned bit4:1; unsigned bit5:1; unsigned bit6:1; unsigned bit7:1; }CHAR_DETAIL; typedef struct unsigned bit0:1; unsigned bit1:1; unsigned bit2:1; unsigned bit3:1; unsigned bit4:1; unsigned bit5:1; unsigned bit6:1; unsigned bit7:1; unsigned bit8:1; unsigned bit9:1; unsigned bitA:1; unsigned bitB:1; unsigned bitC:1; unsigned bitD:1; unsigned bitE:1; unsigned bitF:1; }INT_DETAIL; typedef union { CHAR_DETAIL byte; unsigned char ch; }char_mapping; typedef union { INT_DETAIL word; short integer; }int_mapping; void extract_block(); int mean_square_error(); int compressor(); void build_bitstream(); void encode_8(); void encode_7(); struct ElementRecord{ <dp n="d123"/> Compressor p.3 int i_pixel; int j_pixel; int block_height; int block_width; int codevectors_total; int feature_type; int linked_group; int h_flip; int v_flip; int codevalue; int error; }; struct ElementRecord element_stuff[MAX_ELEMENTS]; unsigned char vq_image[LINES_PER_IMAGE][PIXELS_PER_LINE]; unsigned char*total_allocation; unsigned char*codebook_address[FEATURE_TYPES]; int distortion,challenge; int total_distortion; main(argc,argv) int argc; char *argv[]; { register int i,j,k; char original_filen[100]; char cb_filen[100]; unsigned char standardized_image[LINES_PER_IMAGE][PIXELS_PER_LINE]; unsigned char header[HEADER_BYTES]; unsigned char compressed_image_bitstream[TRACK_SIZE]; int long memory_offset; unsigned codebook_memory_size; int codevectors_total[FEATURE_TYPES],block_space[FEATURE_TYPES]; FILE *fp; /* *Read in input image */ sprintf(original_filen,"/standardized_image/f%04d.dsi",atoi(argv[1])); if((fp=fopen(original_filen,"rb"))!=NULL){ <dp n="d124"/> Compressor p.4 fread(header,sizeof(unsigned char),HEADER_BYTES,fp); fread(standardized_image,PIXELS_PER_IMAGE*sizeof(char),1,fp); printf("Image used is%s\n",original_filen); } else{ printf("Image file not found\n"); exit(1); } fclose(fp); read_feature_template(); for(i=0;i<MAX_ELEMENTS;i++){ codevectors_total[element_stuff[i].feature_type-1]= element_stuff[i].codevectors_total; block_space[element_stuff[i].feature_type-1]= element_stuff[i].block_height*element_stuff[i].block_width; } memory_offset=0; codebook_memory_size=0; for(i=0;i<FEATURE_TYPES;i++)codebook_memory_size+= codevectors_total[i]*block_space[i]; total_allocation=(unsigned char*)calloc(codebook_memory_size, (unsigned)sizeof(unsigned char)); if(total_allocation==NULL){ printf("memory allocation failed\n"); exit(1); } for(i=0;i<FEATURE_TYPES;i++){ codebook_address[i]=total_allocation+memory_offset; memory_offset+=block_space[i]*codevectors_total[i]; sprintf(cb_filen,"book_%d",i+1); init_codebook(cb_fiIen,codebook_address[i],codevectors_total[i],block_space[i]); } distortion=compressor(standardized_image); build_bitstream(compressed_image_bitstream); fwrite(compressed_image_bitstream,TRACK_SIZE, *sizeof(unsigned char),1,fp); } void extract_block(image,block,element_stuff) unsigned char *image; unsigned char *block; <dp n="d125"/> Compressor p.5 struct ElementRecord element_stuff; { int i,j; int width,height,row,col; unsigned char*block_ptr,*image_ptr; width=element_stuff.block_width; height=element_stuff.block_height; row=element_stuff.i_pixel; col=element_stuff.j_pixel; block_ptr=block; image_ptr=image+row*PIXELS_PER_LINE+col; for(i=0;i<height;i++){ for(j=0;j<width;j++)*block_ptr++=*image_ptr++; image_ptr+=PIXELS_PER_LINE-width; } } vertical_block_flip(block,element_stuff) unsigned char *block; struct ElementRecord element_stuff; { int i,j,temp; unsigned char*block_ptr; int offset; int width,height; width=element_stuff.block_width; height=element_stuff.block_height; block_ptr=block; for(j=0;j<height/2;j++){ offset=width*(height-(2*j+1)); for(i=0;i<width;i++){ temp=*block_ptr; *block_ptr=*(block_ptr+offset); *(block_ptr+offset)=temp; block_ptr++; } } } horizontal_block_flip(block,element_stuff) unsigned char *block; struct ElementRecord element_stuff; { register int i,j,temp; <dp n="d126"/> Compressor p.6 int width,height; width=element_stuff.block_width; height=element_stuff.block_height; for(i=0;i<width/2;i++) for(j=0;j<height;j++){ temp=*(block+j*width+i); *(block+j*width+i)=*(block+(j+1)*width-(i+1)); *(block+(j+1)*width-(i+1))=temp; } } init_codebook(cb_filen,codebook,num_vectors,vector_length) char*cb_filen; unsigned char*codebook; int num_vectors; int vector_length; { FILE *fp; if((fp=fopen(cb_filen,"rb"))==NULL){ printf("***Error-opening %s for reading\n",cb_filen); exit(-1); } else{ fread(codebook,num_vectors*sizeof(unsigned char),vector_length,fp); fclose(fp); } } vq_encode(block,element_stuff) unsigned char *block; struct ElementRecord element_stuff; { register int i,j,k; int pix_per_block; int num_vectors; int mse; unsigned char*codebook; /* * Initialize the codebook that is going to be used. */ pix_per_block=element_stuff.block_height*element_stuff.block_width; num_vectors=element_stuff.codevectors_total; codebook=codebook_address[element_stuff.feature_type-1]; if(element_stuff.h_flip==1)horizontaI_block_flip(block,&element_stuff); <dp n="d127"/> Compressor p.7 if(element_stuff.v_flip==1)vertical_block_flip(block,&element_stuff); /* *Determine the best codevector for the image block */ element_stuff.error=mean_square_error(block,codebook,pix_per_block); element_stuff.codevalue=0; for(k=1;k<num_vectors;k++){ codebook+=pix_per_block; mse=mean_square_error(block,codebook,pix_per_block); if(mse<element_stuff.error){ element_stuff.error=mse; element_stuff.codevalue=k; } } } /*x=block,y=codevector*/ int mean_square_error(x,y,length) unsigned char *x,*y; int length; { register i; int result; unsigned char *x_ptr,*y_ptr; result=0; x_ptr=x; y_ptr=y; for(i=0;i<length;i++){ if(*x_ptr!=255)result+=((int)*x_ptr-(int)*y_ptr)*((int)*x_ptr-(int)*y_ptr)); x_ptr++; y_ptr++; } return result; } int compressor(image) unsigned char *image; { register int i; register int mate; int mse_distortion; unsigned char block_data[MAX_CODEVECTOR_PIXELS]; for(i=0;i<MAX_ELEMENTS;i++)element_stuff[i].error=0; <dp n="d128"/> Compressor p.8 for(i=0;i<MAX_ELEMENTS;i++){ extract_block(image,block_data,&element_stuff[i]); vq_encode(block_data,&element_stuff[i]); vq_reconstruct(block_data,&element_stuff[i]); insert_block(vq_image,block_data,&element_stuff[i]); } for(i=0;i<MAX_ELEMENTS;i++){ if(element_stuff[i].linked_group>=0){ mate=element_stuff[i].linked_group; if(element_stuff[i].error>element_stuff[mate].error){ element_stuff[i].cocevalue=element_stuff[mate].codevalue; element_stuff[i].error=element_stuff[mate].error; vq_reconstruct(block_data,&element_stuff[i]); insert_block(vq_image,block_data,&element_stuff[i]); } } } mse_distortion=0; for(i=0;i<MAX_ELEMENTS;i++)mse_distortion+=element_stuff[i].error; return mse_distortion; } read_feature_template() { register int i; FILE*fp; fp=fopen("feature_template","r"); for(i=0;i<MAX_ELEMENTS;i++){ fscanf(fp,"%d",&element_stuff[i].i_pixel); fscanf(fp,"%d",&element_stuff[i].j_pixel); fscanf(fp,"%d",&element_stuff[i].block_height); fscanf(fp,"%d",&element_stuff[i].block_width); fscanf(fp,"%d",&element_stuff[i].codevectors_total); fscanf(fp,"%d",&element_stuff[i].feature_type); fscanf(fp,"%d",&element_stuff[i].linked_group); fscanf(fp,"%d",&element_stuff[i].h_flip); fscanf(fp,"%d",&element_stuff[i].v_flip); } fclose(fp); } build_bitstream(CompressedImageBits) char *CompressedImageBits; <dp n="d129"/> Compressor p.9 { int i,bit_position,temp,Hole; int first_link; unsigned char*card_format; unsigned char*card_ptr; char*compressed_image_bits_ptr; unsigned char holes[2]={0,0}; int vacancy[SIX_BIT_ASCII_CODES]; int tmp[64]; unsigned char card_format[TRACK_SIZE]; for(i=0;i<64;i++)tmp[i]=element_stuff[i].codevalue; compressed_image_bits_ptr=CompressedImageBits; /*convert the 7&8 bit code values into 6-bit packets*/ for(i=0;i<TRACK_SIZE;i++)card_format[i]=(unsigned char)0; bit_position=0; card_ptr=card_format; for(i=0;i<TOTAL_BLOCKS;i++){ first_link=TRUE; if(element_stuff[i].linked_group>=0) for(j=0;j<i;j++) if(element_stuff[j].linked_group==element_stuff[i].linked_group) first_link=FALSE; if(first_link==TRUE){ if(element_stuff[i].codevectors_total==128) encode_7((unsigned char**)&card_ptr,&bit_position, element_stuff[i].codevalue); else encode_8((unsigned char**)&card_ptr,&bit_position, element_stuff[i].codevalue); } } /*Search for unused characters*/ /*Make all entries vacant*/ for(i=0;i<SIX_BIT_ASCII_CODES;i++)vacancy[i]=TRUE; /*Make used entries not vacant*/ for(i=0;i<SIX_BIT_ASCII_CODES;i++)vacancy[(int)card_format[i]]=FALSE; /*Collect list of two vacancies which are not HOLES*/ temp=0; i=0; <dp n="d130"/> Compressor p.10 do{ if(vacancy[i]&&(i!=HOLE0)&&(i!=HOLE1)holes[temp++]=(unsigned char)i; i++; }while((temp<2)&&(i<SIX_BIT_ASCII_CODES)); if(i==SIX_BIT_ASCII_CODES)exit(SIX_BIT_ASCII_CODES); /*Check values for holes*/ if((int)holes[0]>31)exit(-700-holes[0]); if(((int)holes[1]-(int)holes[0])>15)exit(-800-holes[1]); /*shifts HOLES to vacancies*/ for(i=0;i<TRACK_SIZE-2;i++){ if(card_format[i]==(unsigned char)HOLE0)card_format[i]=holes[0]; if(card_format[i]==(unsigned char)HOLE1)card_format[i]=holes[1]; } /* Record location of the holes in 74 and 75*/ card_format[TRACK_SIZE-2]=(unsigned char)holes[0]; card_format[TRACK_SIZE-1]=(unsigned char)holes[1]; } /*Shift characters into magnetic writing range*/ /*Move range 0-63 to 32-95*/ for(i=0;i<TRACK_SIZE;i++) *(compressed_image_bits_ptr++)=(char)((int)card_format[i]+32); delete(unsigned char*)card_format; } void encode_7(card_ptr,bit_position,value) unsigned char **card_ptr; int *bit_position; int value; { INT_DETAIL seven_bit; CHAR_DETAIL six_bit; int_mapping int_stuff; char_mapping char_stuff; int i,temp; int_stuff.integer=(short)value; char_stuff.ch=**card_ptr; six_bit=char_stuff.byte; seven_bit=int_stuff.word; <dp n="d131"/> Compressor p.11 for(i=0;i<7;i++){ switch(i){ case0: temp=seven_bit.bit0; break; case1: temp=seven_bit.bit1; break; case2: temp=seven_bit.bit2; break; case3: temp=seven_bit.bit3; break; case4: temp=seven_bit.bit4; break; case5: temp=seven_bit.bit5; break; case6: temp=seven_bit.bit6; break; } switch(*bit_position){ case0: six_bit.bit0=temp; break; case1: six_bit.bit1=temp; break; case2: six_bit.bit2=temp; break; case3: six_bit.bit3=temp; break; case4: six_bit.bit4=temp; break; case5: six_bit.bit5=temp; break; } <dp n="d132"/> Compressor p.12 *bit_position+=1; if(*bit_position==6){ *bit_position=0; char_stuff.byte=six_bit; **card_ptr=char_stuff.ch; *card_ptr+=1; char_stuff.ch=**card_ptr; six_bit=char_stuff. byte; } } if(*bit_position!=0){ char_stuff.byte=six_bit; **card_ptr=char_stuff.ch; } } void encode_8(card_ptr,bit_position,value) unsigned char **card_ptr; int *bit_position; int value; { INT_DETAIL eight_bit; CHAR_DETAIL six_bit; int_mapping int_stuff; char_mapping char_stuff; int i,temp; int_stuff.integer=(short)value; char_stuff.ch=**card_ptr; six_bit=char_stuff.byte; eight_bit=int_stuff.word; for(i=0;i<8;i++){ switch(i){ case 0: temp=eight_bit.bit0; break; case1: temp=eight_bit.bit1; break; case2: temp=eight_bit.bit2; break; case3: temp=eight_bit.bit3; break; <dp n="d133"/> Compressor p.13 case4: temp=eight_bit.bit4; break; case5: temp=eight_bit.bit5; break; case6: temp=eight_bit.bit6; break; case7: temp=eight_bit.bit7; break; } switch(*bit_position){ case0: six_bit.bit0=temp; break; case1: six_bit.bit1=temp; break; case2: six_bit.bit2=temp; break; case3: six_bit.bit3=temp; break; case4: six_bit.bit4=temp; break; case5: six_bit.bit5=temp; break; } *bit_position+=1; if(*bit_position==6){ *bit_position=0; char_stuff.byte=six_bit; **card_ptr=char_stuff.ch; *card_ptr+=1; char_stuff.ch=**card_ptr; six_bit=char_stuff.byte; } } if(*bit_p6sition!=0){ char_stuff.byte=six_bit; <dp n="d134"/> Compressor p.14 **card_ptr=char_stuff.ch; } } <dp n="d135"/> Decompressor p.1 Appendix E-Docket #71,250 1993,1994 Eastman Kodak Company,Rochester,N.Y.14650-2201 /* *decompressor.c * *Description:Decompress the compressed image bitstream * *Copyright Eastman Kodak Company,1993-1994 */ #include<stdio.h> #include<malloc.h> #include<math.h> #define FALSE 0 #define TRUE 1 #define MAX_ELEMENTS 64 #define MAX_CODEVECTOR_PIXELS 64 #define PIXELS_PER_LINE 56 #define LINES_PER_IMAGE 64 #define PIXELS_PER_IMAGE PIXELS_PER_LINE * LINES_PER_IMAGE #define COMPRESSED_IMAGE_BYTES 76/*six-bits per character*/ #define FEATURE_TYPES 13 #define HOLE037-32 /*for start sentinel ETX*/ #define HOLE1 63-32 /*for end sentinel STX*/ void smooth_image(); void extract_block(); void insert_block(); unsigned char add_and_trim(); int decode7(); int decode8(); struct ElementRecord{ int i_pixel; int j_pixel; int block_height; int block_width; int codevectors_total; int feature_type; int linked_group; <dp n="d136"/> Decompressor p.2 int h_flip; int v_flip; int codevalue; int error; }; struct CHAR_DETAIL{ unsigned bit0:1, unsigned bit1:1; unsigned bit2:1; unsigned bit3:1; unsigned bit4:1; unsigned bit5:1; unsigned bit6:1; unsigned bit7:1; }; struct INT_DETAIL{ unsigned bit0:1; unsigned bit1:1; unsigned bit2:1; unsigned bit3:1; unsigned bit4:1; unsigned bit5:1; unsigned bit6:1; unsigned bit7:1; unsigned bit8:1; unsigned bit9:1; unsigned bitA:1; unsigned bitB:1; unsigned bitC:1; unsigned bitD:1; unsigned bitE:1; unsigned bitF:1; }; union char_mapping{ struct CHAR_DETAIL byte; unsigned char ch; }; union int_mapping{ struct INT_DETAIL word; int integer; }; <dp n="d137"/> Decompressor p.3 struct ElementRecord element_stuff[MAX_ELEMENTS]; unsigned char decompressed_image[LINES_PER_IMAGE][PIXELS_PER_LINE]; unsigned char *codebook_address[FEATURE_TYPES]; unsigned char *total_allocation; int distortion,challenge; int total_distortion; main(argc,argv) int argc; char *argv[]; { register int i,j,k; char compressed_filen[200]; char decompressed_filen[200]; unsigned char compressed_image_bitstream[COMPRESSED_IMAGE_BYTES]; char cb_filen[400]; int long memory_offset; unsigned codebook_memory_size; int codevectors_total[FEATURE_TYPES],block_space[FEATURE_TYPES]; int temp; int original_type; FILE *fp; int first_linked; int bit_position; int i,j,*bit_ptr,*code_ptr; unsigned char *card_ptr,holes[2]; /* *Read in compressed image bitstream */ sprintf(compressed_filen,"/compressed_image/f%04d",atoi(argv[1])); if((fp=fopen(compressed_filen,"rb"))!=NULL){ fread(compressed_image_bitstream, COMPRESSED_IMAGE_BYTES*sizeof(char),1,fp); printf("Image used is%s\n",compressed_filen); } else{ printf("Compressed image file not found\n"); exit(1); } <dp n="d138"/> Decompressor p.4 fclose(fp); holes[0]=compressed_image_bitstream[74]; holes[1]=compressed_image_bitstream[75]; for(i=0;i<74;i++){ if(compressed_image_bitstream[i]==holes[0]) compressed_image_bitstream[i]=HOLE0; if(compressed_image_bitstream[i]==holes[1]) compressed_image_bitstream[i]=HOLE1; } read_feature_template(); for(i=0;i<MAX_ELEMENTS;i++){ codevectors_total[element_stuff[i].feature_type-1]= element_stuff[i].codevectors_total; block_space[element_stuff[i].feature_type-1]= element_stuff[i].block_height*element_stuff[i].block_width; } memory_offset=0; codebook_memory_size=0; for(i=0;i<FEATURE_TYPES;i++) codebook_memory_size+= codevectors_total[i]*block_space[i]; total_allocation=(unsigned char*)calloc(codebook_memory_size, (unsigned)sizeof(unsigned char)); if(total_allocation==NULL){ printf("memory allocation failed\n"); exit(1); } for(i=0;i<FEATURE_TYPES;i++){ codebook_address[i]=total_allocation+memory_offset; memory_offset+=block_space[i]*codevectors_total[i]; sprintf(cb_filen,"book_%d",i+1); irit_codebook(cb_filen,codebook_address[i],codevectors_total[i],block_space[i]); } /* * Determine the codebook index for each feature element and reconstruct it. */ card_ptr=&compressed_image_bitstream[O]; bit_position=0; for(i=0;i<MAXIMUM_ELEMENTS;i++){ first_linked=0; if(element_stuff[i].linked_group!=0){ <dp n="d139"/> Decompressor p.5 /* We have a linked group member....is it the first??*/ for(j=0;j<i;j++) if(element_stuff[j].linked_group== element_stuff.linked_group){ first_linked=1; element_stuff[i].codevalue=element_stuff[j].codevalue; break; } } if(first_linked==0){ bit_ptr=element_stuff[i].codevectors_total; if(bit_ptr==128) element_stuff[i].codevalue=decode_7(&card_ptr,&bit_position); else if(bit_ptr==256) element_stuff[i].codevalue=decode_8(&card_ptr,&bit_position); } } for(i=0;i<MAXIMUM_ELEMENTS;i++){ vq_reconstruct(block_data,&element_stuff[i]); insert_block(decompressed_image,block_data,&element_stuff[i]); } knock_out_blocks(decompressed_image); smooth_image(decompressed_image); whitener(decompressed_image); /* * Write out smoothed decompressed image */ sprintf(decompressed_filen,"/decompressed_image/f% 04d",atoi(argv[1])); fp=fopen( decompressed_filen,"wb"); if(fp==NULL){ printf("***Error-opening%s for writing\n",decompressed_filen); exit(-1); } fwrite(decompressed_image,PIXELS_PER_IMAGE *sizeof(unsigned char),1,fp); } void extract_block(image,block,element_stuff) unsigned char *image; unsigned char *block; struct Element Record element_stuff; { int i,j; int width,height,row,col; unsigned char *block_ptr,*image_ptr; <dp n="d140"/> Decompressor p.6 width=element_stuff. block_width; height=element_stuff.block_height; row=element_stuff.i_pixel; col=element_stuff.j_pixel; block_ptr=block; image_ptr=image+row*PIXELS_PER_LINE+col; for(i=0;i<height;i++){ for(j=0;j<width;j++)*block_ptr++=*image_ptr++; image_ptr+=PIXELS_PER_LINE-width; } } void insert_block(image,block,element_stuff) unsigned char *image; unsigned char *block; struct Element Record element_stuff; { register int i,j; int row,col,width,height; unsigned char *block_ptr; unsigned char *image_ptr; width=element_stuff.block_width; height=element_stuff.block_height; row=element_stuff.i_pixel; col=element_stuff.j_pixel; block_ptr=block; image_ptr=image+row*PIXELS_PER_LINE+col; for(i=0;i<height;i++){ for(j=0;j<width;j++)*image_ptr++=*block_ptr++; image_ptr+=PIXELS_PER_LINE-width; } } vertical_block_flip(block,element_stuff) unsigned char *block; struct Element Record element_stuff; { int i,j,temp; unsigned char *block_ptr; int offset; int width,height; width=element_stuff.block_width; height=element_stuff.block_height; block_ptr=block; <dp n="d141"/> Decompressor p.7 for(j=0;j<height/2;j++){ offset=width*(height-(2*j+l)); for(i=0;i<width;i++){ temp=*block_ptr; *block_ptr=*(block_ptr+offset); *(block_ptr+offset)=temp; block_ptr++; } } } horizontal_block_flip(block,element_stuff) unsigned char *block; struct ElementRecord element_stuff; { register int i,j,temp; int width,height; width=element_stuff.block_width; height=element_stuff.block_height; for(i=0;i<width/2;i++) for(j=0;j<height;j++){ temp=*(block+j*width+i); *(block+j*width+i)=*(block+(j+1)*width-(i+1)); *(block+(j+1)*width-(i+1))=temp; } } init_codebook(cb_filen,codebook,num_vectors,vector_length) char*cb_filen; unsigned char*codebook; int num_vectors; int vector_length; { FILE *fp; if((fp=fopen(cb_filen,"rb"))==NULL){ printf("***Error-opening%s for reading\n",cb_filen); exit(-1); } else{ fread(codebook,num_vectors*sizeof(unsigned char),vector_length,fp); fclose(fp); } } <dp n="d142"/> Decompressor p.8 vq_reconstruct(block,element_stuff) unsigned char *block; struct ElementRecord element_stuff; { register int pix_per_block; unsigned char *index; int codebook_size; pix_per_block=element_stuff.block_height*element_stuff.block_width; codebook_size=element_stuff.codevectors_total; index=pix_per_block*element_stuff.codevalue+ codebook_address[element_stuff.feature_type-1]; memcpy(block,index,pix_per_block); if(element_stuff.h_flip==1)horizontal_block_flip(block,&element_stuff); if(element_stuff.v_flip==1)vertical_block_flip(block,&element_stuff); } void smooth_image(image) unsigned char *image; { unsigned char smooth_map[LINES_PER_IMAGE][PIXELS_PER_LINE]; unsigned char temporary_image[LINES_PER_IMAGE][PIXELS_PER_LINE]; unsigned char *image_ptr,*temp_ptr; register int i,j; unsigned char smooth_count; FILE *gp; seam_map(smooth_map); image_ptr=image+1; temp_ptr=&temporary_image[0][1]; memcpy(temporary_image,image,PIXELS_PER_IMAGE); /*Smooth vertical seams*/ for(i=0;i<LINES_PER_IMAGE;i++){ for(j=1;j<PIXELS_PER_LINE-1;j++){ smooth_count=smooth_map[i][j-1]+smooth_map[i][j]+smooth_map[i][j+1]; if(smooth_count==2) *temp_ptr=(unsigned char)(((int)*(image_ptr-1)+2*(int)(*image_ptr)+ (int)(*(image_ptr+1)))/4); temp_ptr++; image_ptr++; } temp_ptr+=2; image_ptr+=2; } <dp n="d143"/> Decompressor p.9 /*Smooth Horizontal seams*/ image_ptr=image+PIXELS_PER_LINE; temp_ptr=&temporary_image[1][0]; for(i=1;i<LINES_PER_IMAGE-1;i++){ for(j=0;j<PIXELS_PER_LINE;j++){ smooth_count=smooth_map[i-1][j]+smooth_map[i][j]+smooth_map[i+1][j]; if(smooth_count==2)*temp_ptr=(unsigned char)(((int)(*(image_ptr- PIXELS_PER_LINE))+ 2*(int)(*image_ptr)+(int)(*(image_ptr+PIXELS_PER_LINE)))/4); temp_ptr++; image_ptr++; } } /*Smooth the comers */ temp_ptr=&temporary_image[1][1]; image_ptr=image+PIXELS_PER_LINE+1; for(i=1;i<LINES_PER_IMAGE-1;i++){ for(j=1;j<PIXELS_PER_LINE-1;j++){ if(smooth_map[i][j]==1&&smooth_map[i-1][j]==1&&smooth_map[i][j-1]==10 &&smooth_map[i][j+1]==1&&smooth_map[i+1][j]==1)*temp_ptr= (unsigned char)( ((int)*(image_ptr-1)+4*(int)*image_ptr+ (int)*(image_ptr+1)+(int)*(image_ptr-PIXELS_PER_LINE)+ (int)*(image_ptr+PIXELS_PER_LINE))/8); image_ptr++; temp_ptr++; } image_ptr+=2; temp_ptr+=2; } memcpy(image,temporary_image,PIXELS_PER_IMAGE); } knock_out_bIocks(image) unsigned char *image; { /*0=no reflection*/ /*1=reflect about vertical*/ /*2=reflect about horizontal*/ /*3=reflect about horizontal and vertical*/ linear_block_fill(image,0,0,0);1 inear_block_fill(image,0,47,1); linear_block_fill(image,47,0,2); linear_block_fill(image,55,8,2); linear_block_fill(image,55,0,2); linear_block_fill(image,47,47,3); <dp n="d144"/> Decompressor p.10 linear_block_fill(image,55,39,3); linear_block_fill(image,55,47,3); } unsigned char add_and_trim(value1,value2) unsigned char value1; int value2; { register int combined; unsigned char result; combined=(int)value1+value2; if(combined>255)combined=255; if(combined<0)combined=0; result=(unsigned char)combined; return result; } whitener(image) unsigned char *image; { #define MUTE 72 register int i,j,noise,volume; unsigned char *image_ptr; image_ptr=image; for(i=0;i<LINES_PER_IMAGE;i++) for(j=0;j<PIXELS_PER_LINE;j++)[ volume=((i-28)*(i-28)+(j-32)*(j-32))/MUTE; noise=-volume/2+rand()%(volume+1); *image_ptr=add_and_trim(*image_ptr,noise); image_ptr++; } } image_architecture() { register int i; FILE *fp; fp=fopen("feature_template","r"); for(i=0;i<MAX_ELEMENTS;i++){ fscanf(fp,"%d",&element_stuff[i].i_pixel); fscanf(fp,"%d",&element_stuff[i].j_pixel); fscanf(fp;"%d",&element_stuff[i].block_height); fscanf(fp,"%d",&element_stuff[i].block_width); <dp n="d145"/> Decompressor p.11 fscanff(fp,"%d",&element_stuff[i].codevectors_total); fscanf(fp,"%d",&element_stuff[i].feature_type); fscanf(fp,"%d",&element_stuff[i].linked_group); fscanff(fp,"%d",&element_stuff[i].h_flip); fscanf(fp,"%d",&element_stuff[i].v_flip); } fclose(fp); } linear_block_fill(image,row,col,class) int row,col,class; unsigned char *image; { register int i,j; unsigned char chunk[81]; unsigned char *chunk_ptr; struct ElementRecord filler; iller.i_pixel=row; filler.j_pixel=col; filler.block_height=9; filler.block_width=9; filler.v_flip=class/2; filler.h_flip=class%2; extract_block(image,chunk,&filler); if(filler.h_flip==1)horizontal_block_flip(chunk,&filler); if(filler.v_flip==1)vertical_block_flip(chunk,&filler); filler_up(chunk); if(filler.h_fiip==1)horizontal_block_flip(chunk,&filler); if(filler.v_flip==1)vertical_block_flip(chunk,&filler); insert_block (image,chunk,&filler); } filler_up(block) unsigned char *block; { register int i,j; unsigned char array[8],*array_ptr,*block_ptr; /* 0aaaaaaa8 b///////. b//////\. b/////\\. b////\\\. b///\\\\. b//\\\\\. <dp n="d146"/> Decompressor p.12 b/\\\\\\. 72.......80*/ /*average near comers*/ *(block+17)=*(block+8); *(block+72)=*(block+73); *block=(*(block+8)+*(block+72))/2; /*calduate row a*/ linear(*block,*(block+8),array,7); array_ptr=array; for(i=l;i<8;i++)*(block+i)=*array_ptr++; /*calculate column b*/ linear(*block,*(block+72),array,7); array_ptr=array; for(i=9;i<72;i+=9)*(block+i)=*array_ptr++; /*calculate upper left triangle*/ for(i=2;i<9;i++){ linear(*(block+i),*(block+9*i),array,i-1); array_ptr=array; block_ptr=block+8+i; for(j=0;j<i-1;j++){ *block_ptr=*array_ptr++; block_ptr+=8; } } /*calculate lower right triangle*/ for(i=0;i<6;i++){ linear(*(block+24+8*i),*(block+26+9*i),array,i+1); array_ptr=array; block_ptr=block+25+8*i; for(j=0;j<i+1;j++){ *block_ptr=*array_ptr++; block_ptr++; } } /*now average with linear inter in other direction*/ for(i=0;i<6;i++){ linear(*(block+ 24+8*i),*(block+79-i),array,6-i); array_ptr=array; block_ptr=block+33+8*i; for(j=0;j<6-i;j++){ *block_ptr=(*block_ptr+*array_ptr++)/2; block_ptr+=9; } } } <dp n="d147"/> Decompressor p.13 linear(start,end,array,length) unsigned char start,end,*array; int length; { register int i; unsigned char *array_ptr; array_ptr=array; for(i=0;i<length;i++) *(array_ptr++)=(unsigned char)(((length-i)*(int)start+(i+1)*(int)end)/ (length+1)); } seam_map(smooth_map) unsigned char smooth_map[][PIXELS_PER_LINE]; { register int i,j; register int row,col; for(i=0;i<LINES_PER_IMAGE;i++) for(j=0;j<PIXELS_PER_LINE;j++) smooth_map[i][j]=0; for(i=0;i<MAX_ELEMENTS;i++){ row=element_stuff[i].i_pixel; col=element_stuff[i].j_pixel; for(j=0;j<element_stuff[i].block_width;j++){ smooth_map[row][col+j]=1; smooth_map[row+element_stuff[i].block_height-1][col+j]=1; } for(j=0;j<element_stuff[i].block_height;j++){ smooth_map[row+j][col]=1; smooth_map[row+j][col+element_stuff[i].block_width-1]=1; } } } int decode_7(card_ptr,bit_position) int *bit_position; unsigned char **card_ptr; { struct INT_DETAIL seven_bit; struct CHAR_DETAIL six_bit; union int_mapping int_stuff; union char_mapping char_stuff; int i,temp; <dp n="d148"/> Decompressor p.14 char_stuff.ch=**card_ptr; six_bit=char_stuff.byte; int_stuff.integer=0; seven_bit=int_stuff.word; for(i=0;i<7;i++){ switch(*bit_position){ case0: temp=six_bit.bit2; break; case1: temp=six_bit.bit3; break; case2: temp=six_bit.bit4; break; case3: temp=six_bit.bit5; break; case4: temp=six_bit.bit6; break; case5: temp=six_bit.bit7; break; } *bit_position+=1; if(*bit_position==6){ *card_ptr+=1; *bit_position=0; char_stuff.ch=**card_ptr; six_bit=char_stuff.byte; } switch(i){ case0: seven_bit.bit9=temp; break; case1: seven_bit.bitA=temp; break; case2: seven_bit.bitB=temp; break; case3: seven_bit.bitC=temp; <dp n="d149"/> Decompressor p.15 break; case4: seven_bit.bitD=temp; break; case5: seven_bit.bitE=temp; break; case6: seven_bit.bifF=temp; break; } } int_stuff.word=seven_bit; return int_stuff.integer; } int decode_8(card_ptr,bit_position) int *bit_position; unsigned char **card_ptr; { struct INT_DETAIL eight_bit; struct CHAR_DETAIL six_bit; union int_mapping int_stuff; union char_mapping char_stuff; int i,temp; char_stuff.ch=**card_ptr; six_bit=char_stuff.byte; int_stuff.integer=0; eight_bit=int_stuff.word; for(i=0;i<8;i++){ switch(*bit_position){ case0: temp=six_bit.bit2; break; case1: temp=six_bit.bit3; break; case2: temp=six_bit.bit4; break; case3: temp=six_bit.bit5; <dp n="d150"/> Decompressor p.16 break; case4: temp=six_bit.bit6; break; case5: temp=six_bit.bit7; break; } *bit_position+=1; if(*bit_position==6){ *card_ptr+=1; *bit_position=0; char_stuff.ch=**card_ptr; six_bit=char_stuff.byte; } switch(i){ case0: seven_bit.bit7=temp; break; case1: seven_bit.bit8=temp; break; case2: seven_bit.bit9=temp; break; case3: seven_bit.bitA=temp; break; case4: seven_bit.bitB=temp; break; case5: seven_bit.bitC=temp; break; case6: seven_bit.bitD=temp; break; case7: seven_bit.bitE=temp; break; } } int_stuff.word=eight_bit; return int_stuff.integer; }
Claims (50)
1、一种用于形成一组可寻址的图像特征的方法,上述图像特征体现了一类选定数字图像中的特征,所说的方法包括下列步骤:
a、使来自选定类的数字图像标准化,以便将至少一个预定的特征置于标准的方向和位置;
b、确定上述选定类中标准图像所代表的特征的预期位置;
c、从上述选定类中标准图像内抽取出图像内容,该内容出现在各特征的预期位置处;以及
d、根据步骤c所抽取的图像内容为每一特征形成一组可寻址的相同特征。
2、如权利要求1所述的方法,其特征在于,上述标准化的步骤包括:
测定出现在至少一个数字图像中的至少两个特征的位置,而所说的数字图像则构成了上述选定的类;以及
使上述测出位置的特征定位于预定的部位。
3、如权利要求1所述的方法,其特征在于,上述标准化的步骤还包括:
在进行标准化步骤a时保持数字图像中特征的相对方向与位置。
4、如权利要求1所述的方法,其特征在于,上述标准化的步骤包括:
将数字图像的每个图像特征均表示为一组像素值;以及
将至少一组代表图像特征的像素值调节成具有预定的均值。
5、一种利用码向量来形成一组可寻址的图像特征的方法,上述码向量代表一类选定的图像,所说的方法包括下列步骤:
a、为上述选定类的图像建立一种规范,它包括用于选定图像特征的最佳部位;
b、从上述选定类的图像中选出一个图像;
c、测出选定图像内至少一个选定图像特征的位置;
d、处理上述选定的图像以形成一标准化的几何图像,其中,根据步骤a所建立的规范使至少一个选定图像特征定位;
e、从上述标准化几何图像中抽取出特征块,每个特征块均表示一有意义的图像特征;
f、对选定类中的多个其它图像重复步骤b至步骤e;
g、将所有相同特征块聚成一组;以及
h、为每一组形成一组可寻址的特征码向量,该组码向量代表上述相应的组。
6、如权利要求5所述的方法,其特征在于,它还包括下列步骤:
形成一模板元素,它表示上述标准化几何图像内的特征块的位置和大小与上述一组可寻址特征码向量中的一个的联系。
7、如权利要求6所述的方法,其特征在于,它还包括下列步骤:
将一垂直对称属性与至少一个模板元素联系起来;以及
在上述抽取步骤之后根据垂直对称属性使所抽出的用于模板元素的图像块垂直地翻转。
8、如权利要求6所述的方法,其特征在于,它还包括下列步骤:
将一水平对称属性与至少一个模板元素联系起来;以及
在上述抽取步骤之后根据水平对称属性使所抽出的用于模板元素的图像块水平地翻转。
9、如权利要求5所述的方法,其特征在于,它还包括用下列步骤压缩特征化的图像:
i、对特征化的图像进行步骤c至步骤e;
II、将从步骤i中抽出的特征块与上述和该特征块有关的一组可寻址的特征码向量作比较;以及
III、记录每个特征块的最佳匹配的地址。
10、如权利要求9所述的方法,其特征在于,它还包括下列步骤:
形成一系列模板元素,每个模板元素均表示标准化几何图像内的特征块的位置和大小与上述一组可寻址码向量中的一个的联系。
11、如权利要求10所述的方法,其特征在于,它还包括下列步骤:
确定与各个模板元素相关的最佳匹配码向量;以及
将每个模板的最佳匹配码向量的一系列索引存储在存储装置内,其中,所述的索引顺序对应于模板元素的次序。
12、如权利要求10所述的方法,其特征在于,它还包括下列步骤:
链接相同特征类型的模板元素以形成一组链接的模板元素;
确定与各个模板元素以及上述一组链接模板元素相关的最佳匹配码向量;
存储模板元素的最佳匹配码向量的索引于上述模板元素序列所指示的位置处;以及
除上述模板元素序列中第一次出现的每组链接模板元素系列中模板元素的相关索引以外,从存储的索引序列中删除与任何链接元素相关的索引。
13、如权利要求11所述的方法,其特征在于,用少于512位就可表示和存储所说的索引序列。
14、如权利要求11所述的方法,其特征在于,所说的存储装置是交易卡。
15、如权利要求14所述的方法,其特征在于,所说的交易卡是一磁卡,该磁卡上以与ISO 7811/2标准相一致的方式存储着数据。
16、如权利要求14所述的方法,其特征在于,所说的交易卡带有多个磁道,索引序列就存储在这些磁道中的一个上。
17、一种用于对编码成一系列特征码向量索引的图像进行解压缩以形成特征化图像的方法,它包括下列步骤:
确定与各个索引相关的特征类型;
抽出与各个索引相对应的特征码向量;以及
利用抽出的特征码向量去形成所述的特征化的图像。
18、一种用来利用一系列模板元素对编码成多个特征码向量索引的图像进行解压缩以形成特征化图像的方法,其中,每个模板元素均表示解压缩图像内特征块的位置和大小与一组可寻址特征码向量的联系,所说的方法包括下列步骤:
确定与各个索引相关的模板元素;
根据在模板元素序列中的位置确定与各索引相关的特征类型;
为每个索引从上述一组可寻址的特征码向量中抽出一特征码向量;以及
将每个抽出的码向量插入它所表示的位置以形成所说的特征化图像。
19、如权利要求18所述的方法,其特征在于,它还包括下列步骤:
将一垂直对称属性与至少一个模板元素联系起来;以及
在上述插入步骤之前根据垂直对称属性使所抽出的用于模板元素的特征码向量垂直地翻转。
20、如权利要求18所述的方法,其特征在于,它还包括下列步骤:
将一水平对称属性与至少一个模板元素联系起来;以及
在上述插入步骤之前根据水平对称属性使所抽出的用于模板元素的特征码向量水平地翻转。
21、一种用来利用一系列模板元素对编码成特征码向量索引的图像进行解压缩以形成特征图像的方法,其中,每个模板元素均表示解压缩图像内特征块的位置和大小与一组可寻址特征码向量的联系,并且,至少有一个模板元素与至少另一个模板元素相链接以形成一组相链接的模板元素,所说的方法包括下列步骤:
确定与各个索引相关的模板元素;
根据在模板元素序列中的位置确定与各索引相关的特征类型;
为每个索引从上述一组可寻址的特征码向量中抽出一特征码向量;以及
将每个抽出的码向量插入它所记录的用于模板元素以及任何其它与该元素相链接的模板元素的位置以形成所说的特征化图像。
22、如权利要求18所述的解压缩方法,其特征在于,它还包括下列步骤:
修匀所插入的码向量的边界。
23、如权利要求21所述的解压缩方法,其特征在于,它还包括下列步骤:
修匀所插入的码向量的边界。
24、如权利要求18所述的解压缩方法,其特征在于,它还包括下列步骤:
根据相邻区域内像素的特征在解压缩图像未分配给任何模板元素的区域内形成像素。
25、如权利要求21所述的解压缩方法,其特征在于,它还包括下列步骤:
根据相邻区域内像素的特征在解压缩图像未分配给任何模板元素的区域内形成像素。
26、如权利要求18所述的解压缩方法,其特征在于,它还包括下列步骤:
将随机数添加至解压缩图像以减少人为现象。
27、如权利要求21所述的解压缩方法,其特征在于,它还包括下列步骤:
将随机数添加至解压缩图像以减少人为现象。
28、如权利要求18所述的解压缩方法,其特征在于,它还包括下列步骤:
显示所形成的特征化解压缩图像。
29、如权利要求21所述的解压缩方法,其特征在于,它还包括下列步骤:
显示所形成的特征化解压缩图像。
30、一种用于对特征化图像进行压缩的方法,它包括下列步骤:
a、为图像建立一种规范,它包括用于选定图像特征的最佳部位;
b、从多个图像中选出一个图像;
c、测出选定图像内至少一个选定特征的位置;
d、处理所选定的图像以形成一标准化的几何图像,其中,使该至少一个选定的特征是根据所述的规范定位的;
e、根据标准化几何图像中的图像特征改变标准化的几何图像以形成一标准化的图像;
f、从上述标准化图像中抽出特征块,每个特征块均表示一有意义的特征;
g、对多个其它图像重复步骤b至步骤f;
h、将所有相同的特征化图像块聚成一组;
i、为每一组形成一组可寻址的特征码向量,该组码向量代表所说的组;
j、对所要压缩的特征化图像进行步骤c至步骤f以形成抽出的特征块;
k、将在步骤j中抽出的特征块与步骤i中的一组可寻址特征码向量相比较;以及
l、记录每个特征块的最佳匹配的地址。
31、一种交易卡,它记录有表示压缩图像的数字数据,其中,所说的数字数据在4000至442位的范围内,并且,该数字数据代表每个特征块的最佳匹配的地址,而前述特征块则是权利要求30中的压缩方法所得出的。
32、一种交易卡,它以压缩的方式记录有表示肖像图像的数字数据,其中,所说的数字数据占据4000至442位。
33、一种用于将表示特征化图像的数据压缩到交易卡记录磁道上的方法,它包括下列步骤:
a、为特征化图像建立一种规范,它包括用于选定图像的最佳部位;
b、从多个特征化图像中选出一个图像;
c、测出选定图像内至少一个选定特征的位置;
d、处理所选定的一个图像以形成一标准化的几何图像,其中,使该至少一个选定的特征是根据所述的规范定位的;
e、根据标准化几何图像内图像特征的位置改变标准化几何图象以形成标准化的图像;
f、从上述标准化图像中抽取特征块,每个特征块均表示一有意义的特征;
g、对多个其它特征化图像重复步骤b至步骤f;
h、将所有相同的特征化图像块聚成一组;
i、为每一组形成一组可寻址的特征码向量,该组码向量代表所说的组;
j、对所要压缩的特征化图像进行步骤c至步骤f以形成抽出的特征块;
k、将在步骤j中抽出的特征块与步骤i中的一组可寻址的特征码向量相比较;以及
l、将表示每个特征块最佳匹配的地址的数据记录到交易卡的记录磁道上。
34、一种用于通过下列手段用最少的数据位表示肖像图像的方法:
形成一组可按位寻址的特征,这些特征通过取自多个表示脸部类型的有意义的样本的特征构成了一肖像图像,所说的每个特征是用数据位表示的并可分成若干组相同的特征;
通过用与上述一组可按位寻址的相同特征中最匹配的特征相关的数据位来表示肖像图像内的各个特征,从而形成肖像图像的数据位表示;以及
检查肖像图像的特征以确定特征的对称性,并且,只利用与对称特征相关的数据位一次使表示肖像图像所需的数据位数量减至最小。
35、一种交易卡,它存储有数据位,这些数据位表示按权利要求31的方法所获得的肖像图像。
36、用于重构肖像图像的方法,所说的肖像图像由与多个肖像特征相关的数据位所表示,上述方法包括下列步骤:
从一组可按数据位寻址的特征中抽出各个由数据位所表示的肖像特征;
将抽出的各个特征置于和肖像图像的几何形状相对应的位置,以便根据抽出的肖像特征逐块地形成重构的肖像图像。
37、如权利要求36所述的方法,其特征在于,它还包括:修匀抽出的肖像特征之间边缘以使人为现象减至最少。
38、用于通过码向量来形成一组可寻址的图像特征的设备,所说的码向量表示一类选定的图像,上述设备包括:
用于为上述选定类的图像建立一种规范的装置,所说的规范包括用于选定图像特征的最佳部位;
用于测出各选定类图像内至少一个选定图像特征位置的装置;
用于处理各个选定类图像以形成标准几何图像的装置,其中,使该至少一个选定的图像特征是根据所建立的规范定位的;
用于从上述标准几何图像中抽取特征块的装置,每个特征块均表示一有意义的图像特征;
分组装置,它用于将所有相同的特征块聚成一组;以及
利用表示上述各组的码向量为每一组均形成一组可寻址的图像特征的装置。
39、如权利要求38所述的设备,其特征在于,它还包括:
用于形成一模板元素的装置,所说的模板元素表示标准几何图象内特征块位置及大小与上述一组码向量的联系。
40、如权利要求39所述的设备,其特征在于,它还包括:
用于将一垂直对称属性与至少一个模板元素联系起来的装置;以及
根据垂直对称属性使所有抽出的用于模板元素的图像块垂直翻转的装置。
41、如权利要求39所述的设备,其特征在于,它还包括:
用于将一水平对称属性与至少一个模板元素联系起来的装置;以及
根据水平对称属性使所有抽出的用于模板元素的图像块水平翻转的装置。
42、如权利要求38所述的设备,它还包括用于对特征化图象进行压缩的装置,该装置包括:
用于将抽出的特征块与和抽出的特征块相关的一组可寻址码向量相比较以指示匹配程度的装置;以及
用于记录各特征块的最佳码向量匹配的地址的装置;
43、如权利要求42所述的设备,其特征在于,它还包括:
用于形成一系列模板元素的装置,所说的每个模板元素均表示标准几何图像内特征块的位置和尺寸与上述一组可寻址码向量之一的联系。
44、如权利要求43所述的设备,其特征在于,它还包括:
用于将各个模板元素的一系列最佳匹配的码向量索引存储到存储装置上的装置,其中,所说的索引序列对应于模板元素的次序。
45、如权利要求43所述的设备,其特征在于,它还包括:
用于指示相同特征类型的模板元素链接情况以形成一组链接模板元素的装置;
用于确定最佳匹配的码向量的装置,而所说的码向量则与各模板元素及上述一组链接的模板元素相关;
用于存储模板元素的最佳匹配码向量索引在上述模板元素序列所指示的位置的装置;以及
用于除上述模板元素序列中第一次出现的每组模板元素的索引以外从存储的索引序列中删除与任何链接元素相关的索引的装置。
46、如权利要求44所述的设备,其特征在于,用少于512位就可以表示和存储所说的索引序列。
47、如权利要求44所述的设备,其特征在于,所说的存储装置是交易卡。
48、如权利要求47所述的设备,其特征在于,所说的交易卡是一种磁卡,该磁卡上以与ISO-7811/2标准相一致的方式存储着数据。
49、如权利要求47所述的设备,其特征在于,所说的交易卡带有多个磁道,索引序列就存储在这些磁道中的一个上。
50、一种用于对编码成一系列特征码向量索引的图像进行解压缩以形成特征化图像的设备,它包括:
用于确定与各个索引相关的特征类型的装置;
用于抽出与各个索引相关的特征码向量的装置;以及
用于利用抽出的特征码向量去形成特征化图像的装置。
Applications Claiming Priority (2)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
US36133894A | 1994-12-21 | 1994-12-21 | |
US361338 | 1994-12-21 |
Publications (1)
Publication Number | Publication Date |
---|---|
CN1150282A true CN1150282A (zh) | 1997-05-21 |
Family
ID=23421636
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN95121165A Pending CN1150282A (zh) | 1994-12-21 | 1995-12-21 | 对标准肖像图像进行压缩和解压缩的方法 |
Country Status (7)
Country | Link |
---|---|
EP (1) | EP0718807B1 (zh) |
JP (1) | JPH08265753A (zh) |
CN (1) | CN1150282A (zh) |
AR (1) | AR000238A1 (zh) |
BR (1) | BR9505965A (zh) |
DE (1) | DE69504289T2 (zh) |
ZA (1) | ZA959491B (zh) |
Cited By (2)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN103020576A (zh) * | 2011-09-20 | 2013-04-03 | 华晶科技股份有限公司 | 特征数据压缩装置、多方向人脸侦测系统及其侦测方法 |
CN104012093A (zh) * | 2012-04-20 | 2014-08-27 | 华为技术有限公司 | 用于处理图像的方法 |
Families Citing this family (3)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
GB2319380B (en) * | 1996-11-15 | 1998-09-30 | Daewoo Electronics Co Ltd | Method and apparatus for controlling a descrambling device |
EP1091560A1 (en) | 1999-10-05 | 2001-04-11 | Hewlett-Packard Company | Method and apparatus for scanning oversized documents |
CN100369049C (zh) * | 2005-02-18 | 2008-02-13 | 富士通株式会社 | 灰度字符的精确分割装置及方法 |
Family Cites Families (5)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
GB8710737D0 (en) * | 1987-05-06 | 1987-06-10 | British Telecomm | Video image encoding |
CA2087523C (en) * | 1990-07-17 | 1997-04-15 | Mark Andrew Shackleton | Method of processing an image |
US5331544A (en) * | 1992-04-23 | 1994-07-19 | A. C. Nielsen Company | Market research method and system for collecting retail store and shopper market research data |
US5574573A (en) * | 1993-10-29 | 1996-11-12 | Eastman Kodak Company | Compression method for a standardized image library |
US5466918A (en) * | 1993-10-29 | 1995-11-14 | Eastman Kodak Company | Method and apparatus for image compression, storage, and retrieval on magnetic transaction cards |
-
1995
- 1995-11-08 ZA ZA959491A patent/ZA959491B/xx unknown
- 1995-11-30 AR AR33446795A patent/AR000238A1/es unknown
- 1995-12-05 EP EP95420341A patent/EP0718807B1/en not_active Expired - Lifetime
- 1995-12-05 DE DE69504289T patent/DE69504289T2/de not_active Expired - Fee Related
- 1995-12-20 JP JP7332355A patent/JPH08265753A/ja active Pending
- 1995-12-20 BR BR9505965A patent/BR9505965A/pt not_active Application Discontinuation
- 1995-12-21 CN CN95121165A patent/CN1150282A/zh active Pending
Cited By (3)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN103020576A (zh) * | 2011-09-20 | 2013-04-03 | 华晶科技股份有限公司 | 特征数据压缩装置、多方向人脸侦测系统及其侦测方法 |
CN104012093A (zh) * | 2012-04-20 | 2014-08-27 | 华为技术有限公司 | 用于处理图像的方法 |
CN104012093B (zh) * | 2012-04-20 | 2018-02-02 | 华为技术有限公司 | 用于处理图像的方法 |
Also Published As
Publication number | Publication date |
---|---|
JPH08265753A (ja) | 1996-10-11 |
EP0718807A3 (zh) | 1996-07-10 |
DE69504289T2 (de) | 1999-03-04 |
AR000238A1 (es) | 1997-05-28 |
BR9505965A (pt) | 1997-12-23 |
EP0718807A2 (en) | 1996-06-26 |
DE69504289D1 (de) | 1998-10-01 |
EP0718807B1 (en) | 1998-08-26 |
ZA959491B (en) | 1996-06-29 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
US11010955B2 (en) | Point cloud mapping | |
CN1253010C (zh) | 图像压缩方法及装置、图像编码装置及图像编码方法 | |
CN1214349C (zh) | 处理视觉图像的方法和装置以及图像压缩方法 | |
US20210174551A1 (en) | Mesh compression via point cloud representation | |
JP2968582B2 (ja) | デジタルデータを処理するための方法および装置 | |
CN100342399C (zh) | 提取用作面貌识别和重现的特征向量的方法和装置 | |
US7317838B2 (en) | Compression of bi-level images with explicit representation of ink clusters | |
CN1458791A (zh) | 分段分层的图像系统 | |
CN1681330A (zh) | 自适应2n叉树生成方法及3D体数据编码和解码方法和设备 | |
CN1898700A (zh) | 图像处理 | |
JP4679425B2 (ja) | 画像処理装置、画像処理方法およびプログラム | |
CN101060629A (zh) | 图像压缩/解压方法及图像编/解码器和解码电路 | |
US20080031549A1 (en) | Image processing apparatus, image reading apparatus, image forming apparatus, image processing method, and recording medium | |
CN1604647A (zh) | 给数字视频加水印的方案 | |
CN1180627C (zh) | 图像编码/解码方法,图像编码装置和图像解码装置 | |
CN1525403A (zh) | 图像处理装置 | |
EP1309200A3 (en) | Image coding and decoding using mapping coefficients corresponding to class information of pixel blocks | |
CN1627325A (zh) | 色彩变换方法及装置 | |
JP2007241328A (ja) | プログラム、情報記憶媒体、2次元コード生成システム、画像生成システム及び印刷物 | |
CN1150282A (zh) | 对标准肖像图像进行压缩和解压缩的方法 | |
CN1179558C (zh) | 图象记录装置与方法、图象再现装置与方法、以及上面记录有图象处理程序的记录介质 | |
WO2003060829A1 (en) | Processing boundary information of a graphical object | |
CN100341331C (zh) | 基于区域的规模可变的图像编码 | |
US7298894B2 (en) | Color image conversion method and system for reducing color image data size | |
CN1135849C (zh) | 一个数字化图像的向量量化和逆向量量化的方法和设备 |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
C06 | Publication | ||
PB01 | Publication | ||
C10 | Entry into substantive examination | ||
SE01 | Entry into force of request for substantive examination | ||
C01 | Deemed withdrawal of patent application (patent law 1993) | ||
WD01 | Invention patent application deemed withdrawn after publication |