比较图像数据的相似性 - C# .NET 6
LEADTOOLS SDK 本教程介绍如何使用各种图像处理命令来比较两幅图像,以确定它们在使用 LEADTOOLS SDK 的 C# .NET 6 应用程序中的相似程度。
概述 | |
---|---|
概括 | 本教程介绍如何使用各种图像处理命令在 C# .NET 6 控制台应用程序中比较图像。 |
完成时间 | 30分钟 |
Visual Studio 项目 | 下载教程项目 (2 KB) |
平台 | C# .NET 6 控制台应用程序 |
集成开发环境 | Visual Studio 2022 |
运行时目标 | .NET 6 或更高版本 |
开发许可证 | 下载 LEADTOOLS |
尝试使用其他语言 |
|
所需知识
在开始本教程之前,请先查看添加引用和设置许可证教程,熟悉创建项目的基本步骤。
创建项目并添加 LEADTOOLS 引用
从“添加引用”和“设置许可证”教程中创建的项目副本开始。如果您没有该项目,请按照该教程中的步骤创建它。
所需的参考文献取决于项目的目的。可以通过以下两种方法之一添加参考文献(但不能同时使用)。
如果使用 NuGet 引用,本教程需要以下 NuGet 包:
Leadtools.Image.Processing
如果使用本地 DLL 引用,则需要以下 DLL。
DLL 位于<INSTALL_DIR>\LEADTOOLS23\Bin\net
:
Leadtools.dll
Leadtools.Codecs.dll
Leadtools.Core.dll
Leadtools.ImageProcessing.Color.dll
Leadtools.ImageProcessing.Core.dll
Leadtools.ImageProcessing.Effects.dll
有关您的应用程序所需的 DLL 文件的完整列表,请参阅应用程序中要包含的文件。
设置许可证文件
许可证用于解锁项目所需的功能。必须在调用任何工具包函数之前设置许可证。有关详细信息(包括不同平台的教程),请参阅设置运行时许可证。
运行时许可证有两种类型:
- 评估许可证,在下载评估工具包时获得。它允许对工具包进行评估。
- 部署许可证。如果需要部署许可证文件和开发者密钥,请参阅获取许可证。
添加图像比较代码
创建项目、添加参考并设置许可证后,就可以开始编码了。
CombineCommand
本教程将通过计算使用带有标志的后黑色像素的比例OperationXor
、使用 计算所有像素的平均强度StatisticsInformationCommand
以及使用 计算平均色调和饱和度值来比较两幅图像ColorSeparateCommand
。
在解决方案资源管理器中,打开Program.cs
。将以下语句添加到顶部的 using 块中Program.cs
:
using System;
using Leadtools;
using Leadtools.Codecs;
using Leadtools.ImageProcessing;
using Leadtools.ImageProcessing.Color;
using Leadtools.ImageProcessing.Core;
using Leadtools.ImageProcessing.Effects;
在该Main
方法中添加两个新的字符串变量,并将它们设置为两个单独的图像文件路径,如下所示。为了方便本教程,您可以在此处下载测试图像。例如,1stRed.png
与 进行比较2ndRed.png
。
static void Main(string[] args)
{
string image1Filename = @"FILEPATH TO FIRST IMAGE";
string image2Filename = @"FILEPATH TO SECOND IMAGE";
InitLEAD();
// RasterImages are IDisposable so they must be in using blocks if not calling .Dispose() later
using RasterImage image1 = LoadImage(image1Filename);
using RasterImage image2 = LoadImage(image2Filename);
Console.WriteLine($"Image 1: {image1Filename}");
Console.WriteLine($"Image 2: {image2Filename}\n");
CompareXOR(image1, image2);
CompareIntensities(image1, image2);
CompareHSV(image1, image2);
}
Program
向名为 的类添加一个新方法。在方法中的语句中,在方法调用下方调用该方法LoadImage(string _filePath)
两次,如上所示。将以下代码添加到方法中,以将给定的文件加载为对象。using
Main
InitLEAD
LoadImageRasterImage
static RasterImage LoadImage(string filename)
{
using RasterCodecs codecs = new RasterCodecs();
return codecs.Load(filename);
}
Program
向名为 、 和 的类CompareXOR(RasterImage image1, RasterImage image2)
中CompareIntensities(RasterImage image1, RasterImage image2)
添加四个新方法CompareHSV(RasterImage image1, RasterImage image2)
。在方法调用下方的语句中调用这四个方法LoadImage
,using
如上所示。
为方法添加以下代码CompareXOR
。在此方法中,我们将使用CombineCommand
。这会将一个图像放置在另一个图像的某个位置和某个矩形内。底层图像的像素受覆盖图像影响的方式取决于我们使用的标志。在这种情况下,我们将使用LeadRect
与底部图像大小相同的来使用整个图像。我们将使用OperationXor
标志,该标志将对每个图像的每一组顶部和底部像素执行按位异或运算。这应该在任一图像中相同位置的两个像素相同的地方创建黑色像素,在其他地方创建白色。为了计算两个图像之间有多少相同之处,我们将仅由黑色像素创建一个区域,并将其与所有像素的总和进行比较。
private static void CompareXOR(RasterImage image1, RasterImage image2)
{
using RasterImage image2Copy = image2.Clone();
// Combine the images with XOR
new CombineCommand()
{
DestinationRectangle = new LeadRect(0, 0, image1.Width, image1.Height),
Flags = CombineCommandFlags.OperationXor,
SourceImage = image1,
SourcePoint = new LeadPoint(0, 0)
}.Run(image2Copy);
// Calculate the percentage of black pixels (where XOR was identical)
image2Copy.AddColorToRegion(RasterColor.Black, RasterRegionCombineMode.Set);
double ratio = (double)image2Copy.CalculateRegionArea() / (image2Copy.Width * image2Copy.Height);
Console.WriteLine($"Individual pixels: {100.0 * ratio:0.00}% match");
}
为方法添加以下代码CompareIntensities
,以创建 的实例StatisticsInformationCommand
,这允许您在统计总体中仅包含特定范围或颜色的像素。我们将使用主通道中 0-255 之间的所有像素。我们将收集图像的平均值并比较两者,将其重新缩放为 0-1.00 而不是 0-255。这将提供平均强度或亮度的差异。
我们还可以像之前一样,通过此命令进行异或运算,得出这些图像差异的强度CombineCommand
。这将通过相同像素值与不同像素值的比率来计算。
private static void CompareIntensities(RasterImage image1, RasterImage image2)
{
using RasterImage image1Gray = image1.Clone();
using RasterImage image2Gray = image1.Clone();
// Convert both images to grayscale
GrayscaleCommand grayscale = new GrayscaleCommand()
{
BitsPerPixel = 8
};
grayscale.Run(image1Gray);
grayscale.Run(image2Gray);
// Compare the average overall intensities
StatisticsInformationCommand statistics = new StatisticsInformationCommand()
{
Channel = RasterColorChannel.Master,
End = 255,
Start = 0
};
statistics.Run(image1Gray);
double leftIntensity = statistics.Mean;
statistics.Run(image2Gray);
double rightIntensity = statistics.Mean;
double similarity = 1.0 - (Math.Abs(leftIntensity - rightIntensity) / 255.0);
Console.WriteLine($"Overall image intensities: {100.0 * similarity:0.00}% match");
// Check the intensity of the difference
new CombineCommand()
{
DestinationRectangle = new LeadRect(0, 0, image1Gray.Width, image1Gray.Height),
Flags = CombineCommandFlags.OperationXor,
SourceImage = image1Gray,
SourcePoint = new LeadPoint(0, 0)
}.Run(image2Gray);
statistics.Run(image2Gray);
similarity = 1.0 - (statistics.Mean / 255.0);
Console.WriteLine($"Image difference intensity: {100.0 * similarity:0.00}% match");
}
添加以下代码,用于CompareHSV
将图像分离为色相、饱和度和值通道(而非红、绿、蓝通道)。这将创建一个DestinationImage
包含三页的对象,每个通道一页。然后,我们可以StatisticsInformationCommand
再次使用该方法,通过在分离后图像的每一页上运行该函数来找到两幅图像的平均色相和饱和度。平均值本质上是图像的亮度,但用处不大。然后,我们可以比较平均色相和饱和度的差异,同样将其从 0-255 缩放到 0-100。
private static void CompareHSV(RasterImage image1, RasterImage image2)
{
ColorSeparateCommand colorSeparate = new ColorSeparateCommand()
{
Type = ColorSeparateCommandType.Hsv
};
StatisticsInformationCommand statistics = new StatisticsInformationCommand()
{
Channel = RasterColorChannel.Master,
End = 255,
Start = 0
};
// Separate the first image, and calculate the average values
colorSeparate.Run(image1);
double image1Hue, image1Saturation;
using RasterImage image1Separated = colorSeparate.DestinationImage;
image1Separated.Page = 1;
statistics.Run(image1Separated);
image1Hue = statistics.Mean;
image1Separated.Page = 2;
statistics.Run(image1Separated);
image1Saturation = statistics.Mean;
// Separate the second image, and calculate the average values
colorSeparate.Run(image2);
double image2Hue, image2Saturation;
using RasterImage image2Separated = colorSeparate.DestinationImage;
image2Separated.Page = 1;
statistics.Run(image2Separated);
image2Hue = statistics.Mean;
image2Separated.Page = 2;
statistics.Run(image2Separated);
image2Saturation = statistics.Mean;
// Calculate the hue difference
// Note: 0 is next to 255, so need to compensate for this
double hueDiff = Math.Abs(image1Hue - image2Hue);
if (hueDiff > 127)
hueDiff = Math.Abs(hueDiff - 255);
// Log the hue similarity
double similarity = 1.0 - (hueDiff / 255.0);
Console.WriteLine($"Average hue values: {100.0 * similarity:0.00}% match");
// Log the saturation similarity
similarity = 1.0 - (Math.Abs(image1Saturation - image2Saturation) / 255.0);
Console.WriteLine($"Average saturation values: {100.0 * similarity:0.00}% match");
}
处理流
要与本教程一起使用MemoryStream
,请将方法中的现有代码替换Main()
为以下内容:
static void Main(string[] args)
{
string image1Filename = @"FILEPATH TO FIRST IMAGE";
string image2Filename = @"FILEPATH TO SECOND IMAGE";
try
{
InitLEAD();
Console.WriteLine();
// Use Memory Stream
using (RasterCodecs rasterCodecs = new RasterCodecs())
{
// RasterImages are IDisposable so they must be in using blocks if not calling .Dispose() later
byte[] bytes1 = File.ReadAllBytes(image1Filename);
byte[] bytes2 = File.ReadAllBytes(image2Filename);
MemoryStream memoryStream1 = new MemoryStream(bytes1);
MemoryStream memoryStream2 = new MemoryStream(bytes2);
using (RasterImage image1 = rasterCodecs.Load(memoryStream1))
using (RasterImage image2 = rasterCodecs.Load(memoryStream2))
{
Console.WriteLine($"Image 1: {image1}");
Console.WriteLine($"Image 2: {image2}");
Console.WriteLine();
CompareXOR(image1, image2);
CompareIntensities(image1, image2);
CompareHSV(image1, image2);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
Console.WriteLine();
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
运行项目
按F5或选择“调试”->“开始调试”来运行项目。
如果正确遵循这些步骤,应用程序将对两幅图像执行多次计算,并将相似度统计数据输出到控制台。
本教程展示了如何使用各种图像处理命令(包括CombineCommand
、、、和)来获取两幅图像的相似性统计数据CombineCommand
, GrayscaleCommand
, StatisticsInformationCommand
, ColorSeparateCommand
, and SizeCommand