范文一:代码相似度
计 算 机 工 程 卷 第4期 第 36
Vol.36 No.4 Computer Engineering · 软件技术与数据库 ·
文章编号:1000—3428(2010)04—0045—02
文献标识码:A
2010年2月
February2010
中图分类号:N945
程序代码相似度度量的研究与实现
于海英
(内蒙古财经学院计算机信息管理学院,呼和浩特 010070)
摘 要:针对程序代码相似度的度量问题,提出一种属性计数和结构度量相结合的方法,通过统计程序源代码的操作符和操作数个数,产生Halstead长度、Halstead词汇和Halstead容量3个程序的特征向量,利用向量夹角的余弦计算属性相似度,采用最长公共子序列算法获取结构相似度,从而衡量程序对间的相似程度。实验结果表明,该方法能够有效检测出学生作业中的相似程序代码。 关键词:属性计数;结构度量;程序代码相似度
Research and Implementation of Program Code
Similarity Measurement
YU Hai-ying
(College of Computer Information Management, Inner Mongolia Finance and Economics College, hohhot 010070)
【Abstract】Aiming at the problem of program code similarity measurement, a combined method of attribute counting and structure metrics is proposed. Attribute counting produces Halstead length, Halstead vocabulary and Halstead volume which constitute feature vector by counting the operator and operand of program source code, and attribute similarity can be calculated by using the cosine of vector included angle. The longest common subsequence algorithm is used to obtain structure similarity. The similar degree between two programs can be measured with the two similarities. Experimental results show the method can effectively detect similar programs of the students’ homework. 【Key words】attribute counting; structure metrics; program code similarity
1 概述
一种程序语言,对于同一逻辑的表达形式往往是多样的,还有可能一些人为了节省时间和力气,将别人的程序更改一下作为自己的。文献[1]将更改手段(在不影响结果的情况下)总结如下:(1)逐字拷贝;(2)更改注释语句;(3)更改空白区域和格式;(4)重新命名标识符;(5)改变代码块的顺序;(6)改变代码块中语句的顺序;(7)改变表达式中操作符和操作数的顺序;(8)更改数据类型;(9)增加冗余的语句和变量;(10)用等价的控制结构替换原有控制结构。这些更改都是表面的、少量的,而程序中内含的属性和结构没有改变。因此,这样的程序具有内在的相似性,且这种相似性是可以度量的。本文主要探讨这种相似性的度量方法。
的张文典、任冬伟研制了一个PASCAL程序抄袭判定系统,利用属性计数的方法能够度量PASCAL程序的相似度。以后很少有人在该领域进行研究。
3 程序代码相似度度量
以C语言为度量语言,测试数据选用某班学生上传到FTP上的同一批次的数据结构堆栈操作作业(用C语言实现)文本文件。属性计数时用到C语言的关键字和操作符号字典,需要预先建立。实现时分为3步:
第1步 预处理:删除注释语句;将语句中出现的如“___”这样的系统不能识别的绘图符号,用系统能够识别的符号(如“*”号)代替,避免出现运行错误。
第2步 属性计数:将每个程序读进内存并按程序语句自顶向下和代码行从左向右的顺序进行分解,得到构成程序的标识符序列,统计各属性的值,并将标识符序列依次存入数据库中,为下一阶段做好准备。
第3步 结构度量:比较构成2个程序的标识符序列,获取最长公共标识符子序列的长度,如果需要也可以获取最长公共标识符子序列。
3.1 程序属性相似度的度量
文献[3]认为任何计算机程序能够被统计或度量的属性包括:η1(程序中唯一的操作符数);η2(程序中唯一的操作数数);N1(程序中总的操作符数);N2(程序中总的操作数数)。
基金项目:内蒙古财经学院科研基金资助重点项目(KY0642);内蒙古自治区高等学校科学研究基金资助项目(NJ09125)
作者简介:于海英(1976-),女,讲师、硕士,主研方向:数据挖掘 收稿日期:2009-11-10 E-mail:yuhaiying@163.com
2 相关研究
程序代码相似度是指利用一定的检测方法度量程序代码间的相似程度,主要应用在程序的复制检测上,因此,程序代码相似度度量技术的发展是随着程序复制检测技术的发展而发展的。除了逐字拷贝的情况,使用直接比较2个程序文本文件字符串的方法来度量相似度的策略效率非常低。在国外,最早在20世纪70年代初就有学者研究度量程序代码相似度的技术和软件。Ottenstein在1976年首次提出基于属性计数法度量相似度的方法,也有学者沿用了属性计数的方法。Plague、YAP系列工具、SIM[2]、JPlag使用结构度量的方法来度量程序的相似度。Verco等人指出,单纯的属性计数法抛弃了太多的程序结构信息,增加向量维数并不能改善错误率。改进属性计数法的措施就是加入程序的结构信息,结合结构度量来度量相似度。在国内,1988年中国人民警官大学
—45—
从基本的度量值很容易得到程序的词汇数:η=η1+η2;程序的实施长度:N=N1+N2;程序的容量:Nlbη。这成为程序可以度量的理论基础。 3.1.1 Halstead属性
本研究采用M.Halstead对程序属性的分析方法,根据程序标识符的类型和它们出现的频度来标识程序。主要统计 2种类型的标识符:操作符和操作数。对于不可执行代码行,如注释、空行和空格,将其忽略。操作符标识符包括源程序设计语言的关键字、操作符号和标准函数名。操作数是由程序设计者自定义的标识符。这些数值用来产生:Halstead长度(N),Halstead词汇(η),Halstead容量(Nlbη)。由于属性统计的不止一个方面,因此每个程序的属性构成一个特征向量vi,进而可以将属性相似度的度量问题转化为特征向量的距离计算问题。
3.1.2 属性相似度计算
2个程序的特征向量获取后,可以通过向量夹角的余弦来计算相似度。为了避免在向量空间中过于强调向量的各个坐标的绝对值,将向量进行归一化处理。假设vi为归一化后的向量,由于归一化后向量夹角的余弦正好是2个向量之间的点乘,则相似度计算公式为
sim(vm
i,vj)=vi?vj=∑Vki×Vkj 0≤sim(vi,vj)≤1 (1)
k=1sim(vi,vj)越接近1,说明作比较的2个程序vi与vj相似
越密切;若等于1,则说明2个程序vi与vj为同一个程序或 2个程序完全相同,或者是在没有改变程序结构和标识符个数的情况下拷贝生成另一个程序;反之亦然,但由于C语言程序的总体结构相同(使用同样的操作符号和关键字),sim(vi,vj)=0的情况很难达到。
3.2 结构相似度度量
最长公共子序列[4](Longest Common Subsequence, LCS)是将2个给定字符串分别删去零个或多个字符,但不改变剩余字符的顺序后得到的长度最长的相同字符序列。在结构度量时,要查找2个标识符序列的最长公共子序列,称之为最长公共标识符子序列,它的长度称为最优值。
通过属性度量获取程序对的标识符序列后,根据应用动态规划思想的最长公共子序列算法计算最优值,进而得到最长公共标识符子序列。要计算标识符表Pi和Qj的最优值,用初值为0的c(m,n)数组,其中,m和n分别为Pi和Qj的长度。记录整个计算过程中的最优值矩阵,当i=0或j=0时,空序列是Pi和Qj的最长公共标识符子序列,故c(i,j)=0。其他情况下,可自底向上建立递推关系如下:
?当i=0或j=0时
c(i,j)=?
0?c(i+1,j+1)+1
当i,j>0且p?i=qj时 (2) ?
max(c(i+1,j),c(i,j+1))当i,j>0且pi≠qj时
由递推关系结合动态规划算法很容易写出自底向上计算最优值c(i,j)的算法LCS-LENGTH及自顶向下获取最长公共标识符子序列算法LCS,2个程序的最长公共标识符子序列存入数据表中,以供查看。程序对的最优值c(0,0)获取后,通过计算Strus1=c(0, 0)/m和Strus2=c(0,0)/n,获取结构相似度值。结构相似度取值范围为:0%~100%;Strus1和Strus2越接近100%,说明2个程序代码结构相似越密切;都等于100%,说明作比较的2个程序为同一个程序或2个程序完全相同;反之亦然,但由于C语言程序的总体结构相同(使用同—46 —
样的操作符号和关键字),都等于0的情况很难达到。程序对的属性和结构相似度获取后,可以将其以降序排列方式写入文本文件进行保存和查看。
3.3 程序代码相似度的阈值
阈值的大小决定程序间相似到一种什么程度才称之为相似程序。如阈值偏大,则找到的相似程序就少;若阈值偏小,则找到的相似程序就过多。对于不同批次的作业,可以得到不同范围和分布的相似度值,但是并没有一个确定的临界值(阈值),超过该阈值可以准确判断2个程序是相似的[1]。由此可以看出,阈值必须选得恰当。因此,每次只能根据手边的数据和实际情况,利用统计规律,反复比较、反复修改来确定阈值。
4 实验测试与结果分析
4.1 简单程序测试与分析
对于SIM中的2个实验程序TEST1和TEST2(TEST1是原始程序,TEST2是由TEST1经过删除注释、改变所有变量和函数名称、尽可能颠倒相邻语句的顺序、改变函数的顺序等操作得到的),本研究报告Halstead相似度为:0.999 997 7;结构相似度为:46.89%和44.39%。虽然结构相似度不高,但Halstead相似度偏高,说明2个程序是相似的。由于TEST2在TEST1的基础上做了若干结构的改变,因此结构相似度值不高,这是可以理解的。SIM对这2个程序进行测试时,最后获取的相似度值为0.4(相似度取值范围为0.0~1.0,值越大程序越相似)。SIM认为这2个程序有相似的可能,值得做进一步考察。
4.2 批量程序测试与分析
利用本研究对小批量的39个实验程序进行测试,其中最小为272 Byte,最大为2 532 Byte,共有741个程序对。运行后根据相似度值用Minitab15统计软件生成分析如图1、 图2所示,其中,图1的属性相似度均值为0.999 8,标准差为0.000 474 5;图2中2个变量的均值与标准差分别为
(下转第49页)
范文二:源代码相似度比较
#include #include #include #include #define N 32//关键字个数 #define size 256 #define maxlen 9 #define hashlen 41//哈希表长度 #define Smax 0.9//相似度 s 的阈值 #define Dmin 2 struct hashtable { char *hash1;//指向关键字的指针 int count; }hashtt[hashlen]; using namespace std; void Hashfunc(char str[]); //将关键字根据哈希函数放入哈希表中的指定位置 int Hashfind(char *words);//在哈希表中找是否该 words 为关键字,并统计频度 int isletter(char ch); //判断是否为字母 float Mol(int *x); //取模函数 int Dot(int *x1, int *x2); //点积函数 float D(int *x1, int *x2); //求距离 D 的函数 float S(int *x1,int *x2); //求相似度 S 的函数 int readc(char * filename); //读取源程序文件中的单词 int getkey(char *str,int len); //获取该单词的 key void resethash(int n); //重置哈希表 void copycount(int x[],int n); //将频道拷贝到数组里 if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='z'))return>='z'))return> return 0; } int readc(char *filename) { //读取源程序文件中的单词 FILE *fp1=NULL; char words[maxlen],ch; int i; if((fp1=fopen (filename, { cout exit(0); } while (!feof(fp1)) //结束返回 1 { i=0; ch=fgetc(fp1); //一个字符一 个字符的读 while (isletter(ch)==0&&feof(fp1)==0) { ch=fgetc(fp1); } while (isletter(ch)==1&&feof(fp1)==0) { if (i==maxlen) { while (isletter(ch)==1&&feof(fp1)==0) { ch=fgetc(fp1); } i=0; break; } //超过最大关键字长度将会跳过当前识别区域,读取下一个单词 else { words[i++]=ch; ch=fgetc(fp1); } } words[i]='\0'; Hashfind (words); //将得到的该单词调入 Hashfind 函数,来判断是否为关键字,并统计频度 } fclose(fp1); return 0; } float Mol(int *x) //取模函数 { int i = 0, sum = 0; for (i = 0; i < n;="" i++)="" {="" sum="" +="(x[i]" *="" x[i]);=""> return (float)pow((float)sum,0.5); } int Dot(int *x1, int *x2) { //点积函数 int i = 0, sum = 0; for (i = 0; i < n;=""> { sum += x1[i] * x2[i]; } return sum; } float S(int *x1,int *x2) { return Dot(x1, x2)/(Mol(x1)*Mol(x2)); //求相似度 S } float D(int *x1, int *x2) //求几何距离 { int x[N], i = 0; for (i = 0; i < n;=""> //向量相减 { x[i]= x1[i] - x2[i]; } return Mol(x); //再求模 } void check(int *x1, int *x2) { float xs = 0, xd = 0; xs = S(x1, x2); cout if (xs > Smax) //先判断 S ,若 S 大于阈值再计算几何距离 { xd = D(x1, x2); cout if (xd <> //如果几何距离小于阈值则判断为相似 cout <> else cout <> return; } cout <> Form: http://hlzhou.iteye.com/blog/687345 6805 package hlzhou; import java.util.ArrayList; import java.util.List; public class ComputerDecision { List List public ComputerDecision(String string1, String string2) { //把输入字符串中多个空格变为一个 String[] vector1String = string1.trim().replaceAll("\\s+", " ").split(" "); String[] vector2String = string2.trim().replaceAll("\\s+", " ").split(" "); for (String string : vector1String) { vector1.add(Integer.parseInt(string)); } for (String string : vector2String) { vector2.add(Integer.parseInt(string)); } } // 求余弦相似度 public double sim() { double result = 0; result = pointMulti(vector1, vector2) / sqrtMulti(vector1, vector2); return result; } private double sqrtMulti(List double result = 0; result = squares(vector1) * squares(vector2); result = Math.sqrt(result); return result; } // 求平方和 private double squares(List double result = 0; for (Integer integer : vector) { result += integer * integer; } return result; } // 点乘法 private double pointMulti(List double result = 0; for (int i = 0; i < vector1.size();="" i++)="" {=""> result += vector1.get(i) * vector2.get(i); } return result; } public static void main(String[] args) { String string = "0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0"; String string2 = "0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0"; ComputerDecision computerDecition = new ComputerDecision(string, string2); System.out.println(computerDecition.sim()); } } 案例10基于WinMerge的软件侵权推理研究案例 软件代码相似度分析 案例主要信息提示 , 案例内容:使用WinMerge量化分析两个软件代码的相似度 , 关键词:软件侵权,代码,相似度,WinMerge , 建议课时:2课时 , 适合专业:法律及文理科各专业 , 数字资源: WinMerge工具软件(WinMerge-2.14.0-Setup.exe) WinMerge帮助文件(WinMerge.chm) 实验数据:原告代码文件1(code1.cpp) 被告代码文件1(code2.cpp) 原告代码文件2(code3.cpp) 被告代码文件2(code4.cpp) 一、 实验内容 专业律师在计算机软件侵权案的实际工作中,常常碰到这样的问题,原告指控被告的软件侵犯了自己的著作权,向法庭提供大量证据证明其主张。而被告也同时向法庭提供许多证据证明其软件不构成侵权。在原、被告双方均以证据证明自己的软件是独立开发完成的情况下,法官在庭审过程中通常采用什么样的方法和准则来判断被控软件侵权与否呢, 计算机软件的侵权行为,一般有两种形式:一是复制程序的基本要素或结构,这一点是较容易证实的,因为复制即表明是完全的翻版,只要完全一样就构成侵权。二是按一定的规则、顺序只复制部分软件代码。在第二种情况下,法院在判定时通常要审查被告是否窃取了足够多的软件程序表达形式。 因此,可以借助计算机进行软件代码相似度分析,以辅助法官判决。 本实验是使用WinMerge工具,进行两个软件代码的相似度分析,以辅助软件侵权案的推理。 二、 预备知识 2.1软件侵权取证方法之一——相似性判断 软件侵权是知识产权侵权的一个组成部分,对比其他类型的侵犯知识产权案例来说,软件的侵权要隐蔽得多,取证也困难得多。自2005年全国人大常委会《关于司法鉴定管理问题的决定》施行以来,在我国的司法鉴定活动中尚未在软件侵权的取证方法上形成一套成熟的取证方法,或者只侧重于著作权的侵权取证,不利于我国的计算机软件保护。因此,需要根据知识产权保护的相关法律知识和计算机专业知识两方面结合,建立软件侵权的计算机取证方法。 司法鉴定的结论只需要指明被告软件与原告软件的相似度定性就可以了,因此,使用比较法来进行软件相似度定性。 对被告的软件与原告的软件直接进行内容对比,如果被告的软件是原告的软件的直接拷贝,可以采用此方法,即对比被告软件与原告软件的源程序或目标程序,如果它们完全一致,就可以认定被告为软件侵权者。这种方法可以用专业工具进行对比,如MD5 校验,WinMerge对比,Beyond Compare 对比等。 事实上,两个软件作品安全一致的可能性很小,实践中判定的是两个软件作品“实质性相似”,其准则是:被指控的计算机程序是否极其类似于原告的计算机软件产品。 计算机软件程序的“实质性相似”有两类:一是文字成分的相似,它以程序代码中引用的百分比为依据进行判断;二是非文字成分的相似,强调应该以整体上的相似作为确认两个软件之间实质上相似的依据。 2.2WinMerge工具简介 WinMerge是一款运行于Windows系统下的免费开源的文件比较/合并工具,使用它可以非常方便地比较多个文档内容以及文件夹与文件夹之间的文件差异。适合程序员或者经常需要撰写文稿的人使用。 当有两个以上的内容相似的文字文件时,WinMerge就可以帮助检查两个文件的不同之处。WinMerge会将两个文件内容做比对,并在相异之处以高亮度的方式显示,让使用者可以很快的查知,并且可以直接让左方的文件内容直接覆盖至右方,或者右方的文件内容直接覆盖至左方,这对需要常常修改文件内容的人来说,会是相当便利的一个功能。 三、 实验方法 软件产品都是以电子文档的形式呈现。WinMerge可以非常方便地比较多个文档内容甚至是文件夹与文件夹之间的文件差异,可以用来辅助分析两个软件产品的相似性。下面使用WinMerge工具来比较软件源程序文档的相似性。 四、 实验操作 4.1(WinMerge的安装 安装WinMerge非常简单。具体操作步骤如下: 双击数字资源中“案例10基于WinMerge的软件侵权推理研究案例——软件代码相似度分析”目录下的WinMerge-2.14.0-Setup.exe文件开始进行安装。在依次出现的6个窗口中单击“下一步”按钮(在第6个窗口中选中在“桌面创建图标”复选框);然后依次在新出现的窗口中单击“安装”按钮和“下一步”按钮;在最后一个安装界面中单击“完成”按钮,完成安装,并开始运行WinMerge程序。安装过程依次出现的界面如图10-1所示。 图10-1WinMerge的安装 4.2 使用WinMerge进行两个软件代码的相似度分析 1(实验数据 在数字资源“案例10基于WinMerge的软件侵权推理研究案例——软件代码相似度分析”目录下,已经存放了两组4个用于比较的C++程序代码:code1.cpp、code2.cpp、code3.cpp和code4.cpp,可用来直接进行练习。 同学们也可用自己的文件进行练习。 2(使用WinMerge进行两个软件代码相似度分析 (1)对两个完全一致的C++程序(code1.cpp和code2.cpp)进行判断相似度的实验。 具体操作步骤如下: ?启动后的WinMerge如图10-2所示。单击工具栏上的“打开”按钮,开始选取你要对比的文件。 图10-2 WinMerge启动主界面 ?在出现的如图10-3所示的“选择文件或文件按夹”窗口中,分别在“左侧”和“右侧”两栏选取要对比的两个文件:code1.cpp和code2.cpp。下面的“过滤器”可过滤要对比的文件类型或文件名称,如无特别的需求,可以保留“*.*”,预设为要对比全部类型的文件。 图10-3选择要对的文件 ?选择好要对比的文件后,单击图10-3中的“确定”按钮,开始进行两个文件的对比。对比窗口如图10-4所示。由于code1.cpp和code2.cpp代码完全相同,在窗口中间弹出一个消息框,显示“选择的文件完全相同”的提示。 图10-4 程序代码完全一致的对比结果窗口 ?据此,可以判定软件侵权。 (2)对两个不完全一致的C++程序(code3.cpp和code4.cpp)进行判断相似度的实验。具体操作步骤同前,仅仅是步骤?中选择用来对比的文件为:code3.cpp和code4.cpp。对 5所示。 比窗口如图10- 图10-5程序代码完全一致的对比结果窗口 基于WinMerge的对比结果进行推理。在图10-5右下角中可以看到,共找到15处不同。在图10-5文件内容下部可以根据鼠标单击代码的位置,显示当前光标所在的行数、列数以及当前行的字符总数等信息,帮助你判断文档的区别。可见两个程序代码的相似度极高。进一步查看15处不同,可以发现,code4.cpp文件仅仅将code3.cpp中的“stu”替换成“Student”。据此,可以判定软件侵权。 五、 拓展实验 本实验是两个简单的使用WinMerge进行C++程序代码相似度比较的实验,仅仅起到抛砖引玉的作用,目的就是使法律及文科各专业大学生充分领略到使用工具的解决实际问题的方便之处,并建立起主动使用计算机及工具软件解决专业问题的意识。 WinMerge除了可以针对文件内容进行对比,还可以对名称、文件内容与文件日期等等细节来做比对,可以直接在对比的报表中执行文件复制的操作,可以将缺少的文件复制到另外一边的文件中去。 同学们常常会备份电脑中的资料,如果有时不小心弄乱了,搞不清楚备份的文件、文件夹是否有漏掉或多了什么文件,那该怎么找出到底是多了还是少了文件或文件夹呢,请用WinMerge来解决这个问题。 图像相似度算法的C#实现及测评 近日逛博客的时候偶然发现了一个有关图片相似度的Python算法实现。想着很有意思便搬到C#上来了,给大家看看。 闲言碎语 才疏学浅,只把计算图像相似度的一个基本算法的基本实现方式给罗列了出来,以至于在最后自己测评的时候也大发感慨,这个算法有点不靠谱。不管怎么样,这个算法有时候还是有用的,所以还是列出来跟大家伙一起分享分享~~ PS:图像处理这一块博大精深,个人偶尔发现了点东西拿来分享。说的不好的地方,写得太糟的地方,诸位准备扔砖头还望淡定,淡定~~ 基本知识介绍 颜色直方图 颜色直方图是在许多图像检索系统中被广泛采用的颜色特征,它所描述的是不同色彩在整幅图像中所占的比例,而并不关心每种色彩所处的空间位置,即无法描述图像中的对象或物体。颜色直方图特别适用于描述那些难以进行自动分割的图像。 灰度直方图 灰度直方图是灰度级的函数,它表示图像中具有每种灰度级的像素的个数,反映图像中每种灰度出现的频率。灰度直方图的横坐标是灰度级,纵坐标是该灰度级出现的频率,是图像的最基本的统计特征。 本文中即是使用灰度直方图来计算图片相似度,关于算法那一块也不赘言了,毕竟图像学图形学,直方图我是门儿都不懂,我也不准备打肿脸充胖子,只想实现一个最基本的算法,然后从最直观的角度看看这个算法的有效性,仅此而已。 算法实现 诸位看官休怪笔者囫囵吞枣,浅尝辄止的学习态度。额毕竟是因兴趣而来,于此方面并无半点基础(当然,除了知道RGB是啥玩意儿——这还幸亏当年计算机图形学的老师是个Super美女,因此多上了几节课的缘故),更谈不上半点造诣,看官莫怪莫怪,且忍住怒气,是走是留,小生不敢有半点阻拦~~ 大致步骤如下: 1, 将图像转换成相同大小,以有利于计算出相像的直方图来 2, 计算转化后的灰度直方图 3, 利用XX公式,得到直方图相似度的定量度量 4, 输出这些不知道有用没用的相似度结果数据 代码实现 步骤1, 将图像转化成相同大小,我们暂且转化成256 X 256吧。 public Bitmap Resize(string imageFile, string newImageFile) { img = Image.FromFile(imageFile); Bitmap imgOutput = new Bitmap(img, 256, 256); imgOutput.Save(newImageFile, System.Drawing.Imaging.ImageFormat.Jpeg); imgOutput.Dispose(); return (Bitmap)Image.FromFile(newImageFile); } 这部分代码很好懂,imageFile为原始图片的完整路径,newImageFile为强转大小后的256 X 256图 片的路径,为了“赛”后可以看到我们转化出来的图片长啥样,所以我就把它保存到了本地了,以至于有 了上面略显丑陋的代码。 步骤2,计算图像的直方图 public int[] GetHisogram(Bitmap img) { BitmapData data = img.LockBits( new System.Drawing.Rectangle( 0 , 0 , img.Width , img.Height ), ImageLockMode.ReadWrite , PixelFormat.Format24bppRgb ); int[ ] histogram = new int[ 256 ]; unsafe { byte* ptr = ( byte* )data.Scan0; int remain = data.Stride - data.Width * 3; for( int i = 0 ; i < histogram.length="" ;="" i="" ++="" )=""> histogram[ i ] = 0; for( int i = 0 ; i < data.height="" ;="" i="" ++="" )=""> { for( int j = 0 ; j < data.width="" ;="" j="" ++="" )=""> { int mean = ptr[ 0 ] + ptr[ 1 ] + ptr[ 2 ]; mean /= 3; histogram[ mean ] ++; ptr += 3; } ptr += remain; } } img.UnlockBits( data ); return histogram; } 这段就是惊天地泣鬼神的灰度直方图计算方法,里面的弯弯绕还是留给诸位自己 去掺和。 步骤3,计算直方图相似度度量 这一步骤的法宝在于这个: Sim(G,S)= 其中G,S为直方图,N 为颜色空间样点数 为了大家少敲两行字儿,也给出一堆乱七八糟的代码: //计算相减后的绝对值 private float GetAbs(int firstNum, int secondNum) { float abs = Math.Abs((float)firstNum - (float)secondNum); float result = Math.Max(firstNum, secondNum); if (result == 0) result = 1; return abs / result; } //最终计算结果 public float GetResult(int[] firstNum, int[] scondNum) { if (firstNum.Length != scondNum.Length) { return 0; } else { float result = 0; int j = firstNum.Length; for (int i = 0; i < j;="" i++)=""> { result += 1 - GetAbs(firstNum[i], scondNum[i]); Console.WriteLine(i + "----" + result); } return result/j; } } 步骤4,输出 这个??诸位爱怎么输出就怎么输出吧。直接Console也好,七彩命令行输出也罢,亦或者保存到文本文件中留作纪念啦啦,诸位“好自为之”~~ 算法测评 真对不住大家,忘了跟大家说,我也不是一个专业的算法测评人员,但是作为一个半拉子测试人员免不了手痒痒想要看看这个算法到底有多大能耐,就拿出几张图片出来验验货吧。 以下是算法测评结果。以下部分内容话带调侃,绝无恶意,开开玩笑,娱乐大众~~ 路人甲 路人乙 图像恶搞 相似点评 度 100里面 % 什么都没有~, 恭喜你,如果你看不 出来这是两张白底图片,那么你还真是小白,因为你连自家人都认不出来啊~~ 100天下% 乌鸦 一般 黑,这 个算 法在 这一 点上 立场 还算 坚定, 表现 不错~ 100碰到% Win7 也不 动心, 意志 坚定 地给 出了 100% 的正 确答 案。 这算 法比我意志坚定多了,我可是win7 刚出来个7000 就装了,还一直用到现在,不过确实好用~~ 88.8明明 4% 很不一样的 “我”跟 “你”摆在 那里, 怎么就相似度这么高 咧,, 难道,“我”,“你”都认不出来,, 哦,我忘了,这两张图片的大背景是一样的,难怪? ? 16.0MS跟8% Apple 这么 水火 不相 容, 【均 使用 默认 桌面 ~~】 50.6终于4% 了解 了Jack 跟 Rose 不能 在一 起的 真正 原因: 不是 爱的 不够 深,也 不是 泰坦尼克号沉了,用老妈的话说“没有‘夫妻’相” —— 还是老妈这个过来人老道~~ 99.2哇,太 1% 不可思议了,竟然是这样。 这算法这 样 “黑” “白”不 分,, 我得向Jack 跟 Rose 的忠实 Fans 道歉了,上面的话是一时失言~~祝他们俩白头偕老,下辈子千万别做船了,坐船 也不 出海, 出海 也不 去北 极,… … 经过我略显玩世不恭的测评活动,说实话,我对这个算法是相当的失望,尤其是最后一次对比中的结果,目前情绪低落中。这倒不是说这算法的一无是处,应该是我或者某些前辈用错了地方,个人觉得算法使用的局限性太大,也或许是我的期望值太高了吧。 后记 开始看到这玩意儿的时候觉得这玩意儿很简单啊,可是一想不对劲,没有这么容易的事情,要不Google,MS这些大牛们做了这么久还没有像样的玩意儿出来。果不其然,为了多了解一点相关的内容,我不得不Google了一下,觉得那些术语完全不知所云,看不懂啊;看来我得祭出我一般不使用的大杀器了——百度一搜。嘿,还真找出来了一堆东西,比Google上面的看起来容易多了,可是打开链接进去瞅瞅,发现还是非我当前能力之所及。没学到东西,但是好歹还是了解了一点皮毛上的皮毛。 全文完 诸位看官若觉得讲得没有意义,浪费了你的时间,那就权当作冷笑话听听缓解一下紧张的神经~~范文三:余弦相似度_代码实现
范文四:案例10 基于winmerge的软件侵权推理研究案例——软件代码相似度分析
范文五:图像相似度算法的C#代码