本教程展示了如何使用图像处理技术来计算图像相似性的不同措施在WinForms c#应用程序使用LEADTOOLS SDK。
概述 | |
---|---|
总结 | 本教程展示了如何使用图像处理比较图像在WinForms c#应用程序。 |
完成时间 | 30分钟 |
Visual Studio项目 | 下载教程项目(12 KB) |
平台 | Windows WinForms c#应用程序 |
IDE | Visual Studio 2017中,2019年 |
开发许可 | 下载LEADTOOLS |
熟悉基本的步骤创建一个项目的审查添加引用和设置一个许可证教程,在工作之前比较图像和图像处理- WinForms c#教程。
从项目中创建的副本添加引用和设置一个许可证教程。如果项目是不可用,按照这个教程中的步骤创建它。
的引用需要取决于项目的目的。引用可以通过添加一个或另一个下面的两种方法(但不是全部)。
如果使用NuGet引用,本教程需要以下NuGet包:
Leadtools.Image.Processing
Leadtools.Viewer.Controls.WinForms
如果使用本地DLL的引用,下面的DLL是必要的。
dll位于< INSTALL_DIR > \ LEADTOOLS22 \ Bin \ Dotnet4 \ x64
:
Leadtools.dll
Leadtools.Codecs.dll
Leadtools.Codecs.Cmp.dll
Leadtools.Codecs.Tif.dll
Leadtools.Controls.WinForms.dll
Leadtools.ImageProcessing.Color.dll
Leadtools.ImageProcessing.Core.dll
Leadtools.ImageProcessing.Effects.dll
对于一个完整的列表的应用程序所需的DLL文件,请参考文件包含在您的应用程序。
许可解锁项目需要的特性。它必须设置工具箱函数被调用之前。详情,包括教程为不同的平台,请参考设置一个运行时许可。
有两种类型的运行时许可证:
请注意
添加LEADTOOLS NuGet和本地引用设置许可中会详细介绍添加引用和设置一个许可证教程。
与项目创建、添加引用,许可,可以开始编码。
在解决方案资源管理器,双击Form1.cs
来显示设计师
。打开工具箱和添加两个标签的顶部Form1
,如下面屏幕截图所示。离开的名字标签
因为它们。编辑文本的地方label1的
文本物业说1日图片
,label2的
文本说2图像
。
添加两个面板中间的形式,如下所示。保持默认的名称面板。
添加5个新按钮左下角的一面Form1
。见下表按钮的的名字和文本属性。
的名字 | 文本 |
---|---|
btnLoadFirst |
加载第一映像 |
btnLoadSecond |
加载第二图像 |
btnCompare |
比较 |
btnCopy |
是结果 |
btnClearList |
明确的结果 |
添加一个列表框右边的按钮如下所示。的名字列表框lstResult
。
UI设计,点击Form1
的设计师。去Form1
属性和双击负载
事件创建一个负载
事件处理程序的形式。这将弹出背后的代码形式。添加使用
下面的语句。
使用系统;
使用System.Drawing;
使用先;
使用System.Windows.Forms;
使用Leadtools;
使用Leadtools.Codecs;
使用Leadtools.Controls;
使用Leadtools.ImageProcessing;
使用Leadtools.ImageProcessing.Color;
使用Leadtools.ImageProcessing.Core;
使用Leadtools.ImageProcessing.Effects;
添加下面的全局变量Form1
类。
私人imageview _viewer1;
私人imageview _viewer2;
私人RasterCodecs _codecs;
私人RasterImage _image1;
私人RasterImage _image2;
将下面的代码添加到Form1_Load
事件处理程序初始化imageview对象。
私人无效Form1_Load (对象发送方的EventArgs e)
{
试一试
{
_viewer1 =新imageview ();
_viewer1。码头= DockStyle.Fill;
_viewer1。背景色= Color.DarkGray;
panel1.Controls.Add (_viewer1);
_viewer1.BringToFront ();
_viewer1.Zoom (ControlSizeMode。健康,1.0,_viewer1.DefaultZoomOrigin);
_viewer2 =新imageview ();
_viewer2。码头= DockStyle.Fill;
_viewer2。背景色= Color.DarkGray;
panel2.Controls.Add (_viewer2);
_viewer2.BringToFront ();
_viewer2.Zoom (ControlSizeMode。健康,1.0,_viewer1.DefaultZoomOrigin);
_codecs =新RasterCodecs ();
}
抓(异常交货)
{
MessageBox.Show (ex.ToString ());
}
}
使用解决方案资源管理器,导航回Form1
设计师。双击两加载第一映像
和加载第二图像
按钮,创建一个事件处理程序按钮并提出形式背后的代码。将下面的代码添加到相应的事件处理程序来加载两个图像比较。
私人无效btnLoadFirst_Click (对象发送方的EventArgs e)
{
试一试
{
字符串_filePath = GetFilePath ();
字符串_fileName = Path.GetFileName (_filePath);
_image1 = _codecs.Load (_filePath);
_viewer1。形象= _image1;
label1。文本= $“1号图片:{_fileName}”;
}
抓(异常交货)
{
MessageBox.Show (ex.ToString ());
}
}
私人无效btnLoadSecond_Click (对象发送方的EventArgs e)
{
试一试
{
字符串_filePath = GetFilePath ();
字符串_fileName = Path.GetFileName (_filePath);
_image2 = _codecs.Load (_filePath);
_viewer2。形象= _image2;
label2。文本= $图片2:{_fileName}”;
}
抓(异常交货)
{
MessageBox.Show (ex.ToString ());
}
}
处理文件使用MemoryStream
,取代现有的代码在两个负载按钮事件处理程序如下:
私人无效btnLoadFirst_Click (对象发送方的EventArgs e)
{
试一试
{
字符串_filePath = GetFilePath ();
字符串_fileName = Path.GetFileName (_filePath);
字节[]_fileData = File.ReadAllBytes (_filePath);
使用(MemoryStream _fileStream =新MemoryStream (_fileData))
_image1 = _codecs.Load (_fileStream);
_viewer1。形象= _image1;
label1。文本= $“1号图片:{_fileName}”;
}
抓(异常交货)
{
MessageBox.Show (ex.ToString ());
}
}
私人无效btnLoadSecond_Click (对象发送方的EventArgs e)
{
试一试
{
字符串_filePath = GetFilePath ();
字符串_fileName = Path.GetFileName (_filePath);
字节[]_fileData = File.ReadAllBytes (_filePath);
使用(MemoryStream _fileStream =新MemoryStream (_fileData))
_image2 = _codecs.Load (_fileStream);
_viewer2。形象= _image2;
label2。文本= $图片2:{_fileName}”;
}
抓(异常交货)
{
MessageBox.Show (ex.ToString ());
}
}
使用内存流需要添加Leadtools.Codecs.Fax。dll项目。
在创建一个新的方法Form1
类命名GetFilePath ()
。调用这个方法在上面所示的事件处理程序。添加下面的代码使用OpeFileDialog选择您希望的图像比较。
私人字符串GetFilePath ()
{
字符串_filePath =零;
OpenFileDialog dlg =新OpenFileDialog ();
了解地理。InitialDirectory =@“C: \ LEADTOOLS22 \ Resources \图片”;
如果(dlg.ShowDialog (这)= = DialogResult.OK)
{
_filePath = dlg.FileName;
}
返回_filePath;
}
导航回Form1
设计师,使用解决方案资源管理器。双击比较
,复制的结果
,明确的结果
按钮创建事件处理程序和形式背后的代码。
将下面的代码添加到btnCompare_Click
事件处理程序运行5的6本教程中使用图像处理算法对图像进行比较。
私人无效btnCompare_Click (对象发送方的EventArgs e)
{
如果(_viewer1。形象= =零| | _viewer2。形象= =零)
{
MessageBox.Show (“请先加载图片”);
返回;
}
lstResult.Items.Add (“* * * * * * * * * * * * * *比较……* * * * * * * * * * * * * *”);
intnewItem;
/ /第一个措施:比较像素XOR-ing他们
使用(RasterImage dstImage = _image2.Clone ())
{
LeadRect rc =新LeadRect (0, 0, _viewer1.Image。宽度,_viewer1.Image.Height);
CombineCommand结合=新CombineCommand (_image1 rc,新LeadPoint (0, 0),
CombineCommandFlags.OperationXor);
combine.Run (dstImage);
/ /相同的像素将导致XOR后黑色。接下来的代码将计算黑比产生的形象
/ /定义一个地区所有的黑色像素
dstImage.AddColorToRegion (RasterColor。黑色,RasterRegionCombineMode.Set);
/ /找到黑色区域的面积和除以总图像面积
双percentBlack = dstImage.CalculateRegionArea () * 100.0 / (dstImage。宽度* dstImage.Height);
newItem = lstResult.Items.Add (字符串.Format (“比较精确的像素:{0:N2} %相同”percentBlack));
lstResult。TopIndex = newItem;
}
/ /复制灰度计算强度值
GrayscaleCommand灰色=新GrayscaleCommand (8);
/ /统计信息命令将使用在找到图像像素的平均值
StatisticsInformationCommand统计=新StatisticsInformationCommand (RasterColorChannel。主人,0,255);
使用(RasterImage image2Gray = _image2.Clone ())
使用(RasterImage image1Gray = _image1.Clone ())
{
LeadRect rc =新LeadRect (0, 0, image2Gray。宽度,image2Gray.Height);
/ /获得强度值,转换为灰度
gray.Run (image1Gray);
gray.Run (image2Gray);
/ /第二个措施:整体强度值
stats.Run (image1Gray);
双intensityAverage1 = stats.Mean;
stats.Run (image2Gray);
双intensityAverage2 = stats.Mean;
双AvgSimilarity = 100.0 -(数学。Abs (intensityAverage2 - intensityAverage1) * 100.0/255);
newItem = lstResult.Items.Add (字符串.Format (“整体形象强度:{0:N2} %相似”AvgSimilarity));
lstResult。TopIndex = newItem;
/ /第三个措施:pixel-wise强度相似
CombineCommand结合=新CombineCommand (image1Gray rc,新LeadPoint (0, 0),
CombineCommandFlags.AbsoluteDifference);
combine.Run (image2Gray);
/ / image2Gray现在的减法结果2图像的强度。
/ /均值的平均强度的差异
stats.Run (image2Gray);
双pixelsSimilarity = 100.0 -(统计数据。意味着* 100.0/255);
newItem = lstResult.Items.Add (字符串.Format (“相应的像素强度:{0:N2} %相似”,
pixelsSimilarity));
lstResult。TopIndex = newItem;
}
/ /第四和第五措施:比较平均色调和饱和度平均水平
/ /颜色宽大获得色相和饱和度的飞机
ColorSeparateCommand colorSep =新ColorSeparateCommand (ColorSeparateCommandType.Hsv);
colorSep.Run (_image1);
colorSep.DestinationImage。页面= 1;
stats.Run (colorSep.DestinationImage);
/ /存储第一色调飞机的平均值
双averageHue1 = stats.Mean;
/ /从色相饱和度平面平面,这是在第二页
colorSep.DestinationImage。页面= 2;
stats.Run (colorSep.DestinationImage);
/ /存储第一饱和飞机的平均值
双averageSat1 = stats.Mean;
/ /执行颜色分离的第二图像
colorSep.Run (_image2);
colorSep.DestinationImage。页面= 1;
stats.Run (colorSep.DestinationImage);
/ /存储平均值的第二平面图像的色相
双averageHue2 = stats.Mean;
/ /从色相饱和度平面平面,这是在第二页
colorSep.DestinationImage。页面= 2;
stats.Run (colorSep.DestinationImage);
/ /存储平均值的第二平面图像的饱和度
双averageSat2 = stats.Mean;
双HueDiff =数学。Abs (averageHue1 averageHue2);
/ /如果一个色调非常高,另一个是非常低的,他们实际上
/ /接近彼此,因为0 255旁边
如果(HueDiff > 127)
HueDiff =数学。Abs (HueDiff - 254);
双SatDiff =数学。Abs (averageSat1 averageSat2);
双hueSimilarity = (255 - HueDiff) * 100/255.0;
双satSimilarity = (255 - SatDiff) * 100/255.0;
lstResult.Items.Add (字符串.Format (“平均颜色值2图片:{0:N2} %相似”hueSimilarity));
newItem = lstResult.Items.Add (字符串.Format (“平均饱和度值2图片:{0:N2} %相似”,
satSimilarity));
lstResult。TopIndex = newItem;
/ / 6日测量:fequency内容值得自己的函数
_image2.Clone CompareFrequencyContent (_image1.Clone () ());
}
添加一个新方法Form1
类命名CompareFrequencyContent (RasterImage img1, RasterImage img2)
。调用这个方法结束的时候btnCompare_Click
事件处理程序,如上所示。将下面的代码添加到运行6日图像处理算法,将计算频率的内容。
公共无效CompareFrequencyContent (RasterImage img1, RasterImage img2)
{
/ /确保图片是相同的大小
如果((img1。宽度! = img2.Width) | | (img1。高度! = img2.Height))
{
SizeCommand SizeCommand =新SizeCommand (256、256、Leadtools.RasterSizeFlags.Bicubic);
sizecommand.Run (img1);
sizecommand.Run (img2);
}
/ /使用相同的标记的图像
/ /包括填充国旗这样FFT将与非2的幂的大小的图像
FastFourierTransformCommandFlags fftFlags = FastFourierTransformCommandFlags.FastFourierTransform
| FastFourierTransformCommandFlags。灰色| FastFourierTransformCommandFlags.PadOptimally;
/ / 2数组来保存FFT的结果
FourierTransformInformation FTArray1 =新FourierTransformInformation (img1 fftFlags);
FourierTransformInformation FTArray2 =新FourierTransformInformation (img2 fftFlags);
/ /应用FFT第一形象
FastFourierTransformCommand命令=新FastFourierTransformCommand (FTArray1 fftFlags);
command.Run (img1);
/ /应用FFT第二图像
命令。FourierTransformInformation = FTArray2;
command.Run (img2);
/ /求和的区别每个频率分量大小和其对应的形象
双magDiff = 0;
/ / 2级的求和值从图像的所有频率成分
双magSum = 0;
intdataLen = FTArray1.Data.Length;
不安全的/ /进程最快的方法是使用提供的数据指针命令
{
双* pData1 = (双*)FTArray1.DataPointer;
双* pData2 = (双*)FTArray2.DataPointer;
为(int我= 0;我< dataLen;+ + i)
{
双r1 = * pData1;
+ + pData1;
双i1 = * pData1;
+ + pData1;
/ /大小是根的实部和虚部
双mag1 =数学。Sqrt (r1 * r1 + i1 * i1);
双r2 = * pData2;
+ + pData2;
双i2 = * pData2;
+ + pData2;
双mag2 =数学。√r2 * r2 + i2 * i2);
/ /统计金额大小
magSum + = (mag1 + mag2);
/ /记录大小差异
magDiff + =数学。Abs (mag1 mag2);
}
}
如果(magSum = = 0)
magSum = 1;/ /不除以零
双freqSimilarity = (magSum - magDiff) * 100 / magSum;
intnewItem = lstResult.Items.Add (字符串.Format (“频率内容2的图片:{0:N2} %相似”freqSimilarity));
lstResult。TopIndex = newItem;
img1.Dispose ();
img2.Dispose ();
}
接下来,将以下代码添加到btnCopy_Click
事件处理程序复制的结果列表框到您的剪贴板。
私人无效btnCopy_Click (对象发送方的EventArgs e)
{
字符串listText =”“;
foreach(字符串三种在lstResult.Items)
listText + = txt + Environment.NewLine;
如果(listText = =”“)
返回;
Clipboard.Clear ();
Clipboard.SetText (listText);
MessageBox.Show (“结果复制到剪贴板”);
}
最后,将下面的代码添加到btnClearList_Click
事件处理程序的结果列表框。
私人无效btnClearList_Click (对象发送方的EventArgs e)
{
lstResult.Items.Clear ();
}
按运行项目F5,或通过选择调试- >开始调试。
如果步骤正确之后,应用程序运行和形式出现。测试,遵循以下步骤:
点击加载第一映像弹出OpenFileDialog。
选择你的第一映像加载。
重复前面的步骤,但加载第二图像按钮。
一旦你有2图片你想比较,单击比较按钮。
本教程展示了如何比较两个图像使用多个图像处理算法。