本教程展示了如何使用图像处理技术来计算WinForms c#应用程序中使用LEADTOOLS SDK的两个图像之间的不同相似性度量。
概述 | |
---|---|
总结 | 本教程展示了如何在WinForms c#应用程序中使用图像处理来比较图像。 |
完成时间 | 30分钟 |
Visual Studio项目 | 下载教程项目(12kb) |
平台 | Windows WinForms c#应用程序 |
IDE | Visual Studio 2017, 2019 |
开发许可 | 下载LEADTOOLS |
来熟悉创建项目的基本步骤添加引用和设置License教程,在工作之前比较图像与图像处理- WinForms c#教程。
中创建的项目的副本开始添加引用和设置License教程。如果您没有该项目,请按照该教程中的步骤创建它。
所需的参考资料取决于项目的目的。可以通过以下两种方法中的一种或另一种添加引用(但不能同时添加)。
如果使用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文件的完整列表,请参阅与您的应用程序包含的文件.
许可证解锁项目所需的特性。它必须在调用任何工具包函数之前设置。有关详细信息,包括针对不同平台的教程,请参阅设置运行时License.
有两种类型的运行时许可证:
请注意
中更详细地介绍了添加LEADTOOLS NuGet和本地引用以及设置许可证添加引用和设置License教程。
随着项目的创建、引用的添加和许可证的设置,编码就可以开始了。
在解决方案资源管理器,双击Form1.cs
来显示设计师
.打开工具箱加上2标签到…的顶端Form1
,如下面的截图所示。留下新的名字标签
事实就是这样。编辑他们的文本到哪里label1的
文本物业说1日图片
,label2的
文本说2图像
.
添加两个面板在表单的中间,如下所示。的默认名称面板.
添加五个新的按钮在左下方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
{
试一试
{
_viewer1 =新imageview ();
_viewer1。Dock = DockStyle.Fill;
_viewer1。BackColor = Color.DarkGray;
panel1.Controls.Add (_viewer1);
_viewer1.BringToFront ();
_viewer1.Zoom (ControlSizeMode。Fit, 1.0, _viewer1.DefaultZoomOrigin);
_viewer2 =新imageview ();
_viewer2。Dock = DockStyle.Fill;
_viewer2。BackColor = Color.DarkGray;
panel2.Controls.Add (_viewer2);
_viewer2.BringToFront ();
_viewer2.Zoom (ControlSizeMode。Fit, 1.0, _viewer1.DefaultZoomOrigin);
_codecs =新RasterCodecs ();
}
抓(异常交货)
{
MessageBox.Show (ex.ToString ());
}
}
使用解决方案资源管理器,导航回Form1
设计师。双击两者加载第一张图片
而且加载第二张图片
按钮,为两者分别创建一个事件处理程序按钮然后打开表单后面的代码。将下面的代码添加到各自的事件处理程序中,以加载两个图像进行比较。
私人无效btnLoadFirst_Click (对象发送器,EventArgs
{
试一试
{
字符串_filePath = GetFilePath();
字符串_fileName = Path.GetFileName(_filePath);
_image1 = _codecs.Load(_filePath);
_viewer1。Image = _image1;
label1。文本= $"第一个图像:{_fileName}";
}
抓(异常交货)
{
MessageBox.Show (ex.ToString ());
}
}
私人无效btnLoadSecond_Click (对象发送器,EventArgs
{
试一试
{
字符串_filePath = GetFilePath();
字符串_fileName = Path.GetFileName(_filePath);
_image2 = _codecs.Load(_filePath);
_viewer2。Image = _image2;
label2。文本= $"第二张图片:{_fileName}";
}
抓(异常交货)
{
MessageBox.Show (ex.ToString ());
}
}
方法中创建一个新方法Form1
类命名GetFilePath ()
.在上面显示的事件处理程序中调用此方法。添加下面的代码以使用OpeFileDialog选择您想要比较的图像。
私人字符串GetFilePath ()
{
字符串_filePath =零;
OpenFileDialog dlg =新OpenFileDialog ();
了解地理。InitialDirectory =@“C: \ LEADTOOLS22 \ Resources \图片”;
如果(了解。ShowDialog (这) ==对话sult. ok)
{
_filePath = dgl . filename;
}
返回_filePath;
}
导航回Form1
设计器,使用解决方案资源管理器.双击比较
,复制的结果
,明确的结果
按钮来创建它们的事件处理程序并打开表单背后的代码。
将下面的代码添加到btnCompare_Click
事件处理程序,以运行本教程中用于图像比较的6种图像处理算法中的5种。
私人无效btnCompare_Click (对象发送器,EventArgs
{
如果(_viewer1。形象= =零| | _viewer2。形象= =零)
{
对话框。显示(“请先加载图片”);
返回;
}
lstResult.Items.Add ("************** 比较……**************");
intnewItem;
//第一个方法:通过XOR-ing逐像素进行比较
使用(RasterImage dstImage = _image2.Clone())
{
LeadRect rc =新LeadRect(0,0, _viewer1.Image.)宽度,_viewer1.Image.Height);
CombineCommand combine =新CombineCommand (_image1 rc,新LeadPoint (0, 0),
CombineCommandFlags.OperationXor);
combine.Run (dstImage);
// XOR后,相同像素将显示为黑色。接下来的代码将计算结果图像的黑比
//定义一个所有黑色像素的区域
dstImage.AddColorToRegion (RasterColor。黑色,RasterRegionCombineMode.Set);
//找到黑色区域的面积,除以图像的总面积
双percentBlack = dstImage. calculateregionarea () * 100.0 / (dstImage. calculateregionarea)。宽度* dstImage.Height);
newItem = lstResult.Items.Add(字符串.Format (“比较精确像素:{0:N2}%相同”percentBlack));
lstResult。TopIndex = newItem;
}
//制作灰度副本来计算强度值
grayscalcommand gray =新GrayscaleCommand (8);
// Statistics info命令将始终用于查找图像像素的平均值
statisticinformationcommand stats =新StatisticsInformationCommand (RasterColorChannel。Master, 0, 255);
使用(rasterimage2gray = _image2.Clone())
使用(rasterimage1gray = _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;
//第三种方法:像素强度相似度
CombineCommand combine =新CombineCommand (image1Gray rc,新LeadPoint (0, 0),
CombineCommandFlags.AbsoluteDifference);
combine.Run (image2Gray);
// image2Gray现在有两个图像的强度的减法结果。
//平均值将是强度差的平均值
stats.Run (image2Gray);
双pixelsSimilarity = 100.0 -(统计。平均值* 100.0 / 255);
newItem = lstResult.Items.Add(字符串.Format (对应像素强度:{0:N2}%相似,
pixelsSimilarity));
lstResult。TopIndex = newItem;
}
//第四个和第五个测量:比较平均色相和平均饱和度
//分离颜色以获得色相和饱和度平面
colorseparatcommand colorSep =新ColorSeparateCommand (ColorSeparateCommandType.Hsv);
colorSep.Run (_image1);
colorSep.DestinationImage.Page = 1;
stats.Run (colorSep.DestinationImage);
//存储第一个色调平面的平均值
双averageHue1 = stats.Mean;
//从色相平面移动到第二页的饱和度平面
colorSep.DestinationImage.Page = 2;
stats.Run (colorSep.DestinationImage);
//存储第一个饱和平面的平均值
双averageSat1 = stats.Mean;
//对第二幅图像进行分色
colorSep.Run (_image2);
colorSep.DestinationImage.Page = 1;
stats.Run (colorSep.DestinationImage);
//存储第二个图像的色调平面的平均值
双averageHue2 = stats.Mean;
//从色相平面移动到第二页的饱和度平面
colorSep.DestinationImage.Page = 2;
stats.Run (colorSep.DestinationImage);
//存储第二幅图像饱和平面的平均值
双averageSat2 = stats.Mean;
双HueDiff =数学。Abs(averageHue1 - averageHue2);
//如果一个色调很高,另一个很低,它们实际上是
//彼此很接近,因为0在255的旁边
如果(HueDiff > 127)
HueDiff =数学。Abs(HueDiff - 254);
双SatDiff =数学。Abs(averageSat1 - averageSat2);
双husimilarity = (255 - HueDiff) * 100 / 255.0;
双satSimilarity = (255 - SatDiff) * 100 / 255.0;
lstResult.Items.Add (字符串.Format (两个图像的平均色调值:{0:N2}%相似hueSimilarity));
newItem = lstResult.Items.Add(字符串.Format (2幅图像的平均饱和度:{0:N2}%相似,
satSimilarity));
lstResult。TopIndex = newItem;
//第六种方法:频率内容应该有自己的功能
_image2.Clone CompareFrequencyContent (_image1.Clone () ());
}
对象中添加一个新方法Form1
类命名比较频率内容(RasterImage img1, RasterImage img2)
.的末尾调用此方法btnCompare_Click
事件处理程序,如上所示。添加下面的代码,运行第6个图像处理算法,该算法将计算频率内容。
公共无效比较频率内容(RasterImage img1, RasterImage img2)
{
//确保图像大小相同
如果((img1。= img1. Width) || (img1. Width)高度!= img2.Height)
{
SizeCommand =新SizeCommand(256,256, Leadtools.RasterSizeFlags.Bicubic);
sizecommand.Run (img1);
sizecommand.Run (img2);
}
//为两个图像使用相同的标志
//包含填充标志,以便FFT能够处理非2次方大小的图像
fftFlags = FastFourierTransformCommandFlags。FastFourierTransform
| FastFourierTransformCommandFlags。灰色| fastfouriertransformcommandflags . padadoptimally;
//存放FFT结果的2个数组
傅里叶变换信息FTArray1 =新FourierTransformInformation (img1 fftFlags);
FTArray2 =新FourierTransformInformation (img2 fftFlags);
//对第一张图像进行FFT处理
FastFourierTransformCommand命令=新FastFourierTransformCommand (FTArray1 fftFlags);
command.Run (img1);
//对第二幅图像进行FFT处理
命令。傅立叶变换信息= FTArray2;
command.Run (img2);
//每个频率分量幅值与其对应图像的幅值之差的总和
双magDiff = 0;
//两幅图像中所有频率分量的两个幅值的总和
双magSum = 0;
intdataLen = FTArray1.Data.Length;
不安全的//最快的处理方法是使用命令提供的数据指针
{
双* pData1 = (双*) FTArray1.DataPointer;
双* pData2 = (双*) FTArray2.DataPointer;
为(intI = 0;i < dataLen;+ + i)
{
双r1 = *pData1;
+ + pData1;
双i1 = *pData1;
+ + pData1;
//大小是实部和虚部的平方根
双mag1 =数学。根号(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;//不除以0
双= (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
{
字符串listText ="";
foreach(字符串三种在lstResult.Items)
listText += txt + Environment.NewLine;
如果(listText = ="")
返回;
Clipboard.Clear ();
Clipboard.SetText (listText);
对话框。显示("结果已复制到剪贴板");
}
最后,将下面的代码添加到btnClearList_Click
事件处理程序来清除列表框.
私人无效btnClearList_Click (对象发送器,EventArgs
{
lstResult.Items.Clear ();
}
通过按运行项目F5,或选择调试->开始调试.
如果正确地执行了这些步骤,应用程序就会运行,表单就会出现。要进行测试,请遵循以下步骤:
点击加载第一张图片提出OpenFileDialog.
选择要加载的第一个图像。
重复前面的步骤,但是使用加载第二张图片按钮。
有了想要比较的2张图片后,单击比较按钮。
本教程展示了如何使用多种图像处理算法比较两幅图像。