using System;
using System.IO;
using NetVips;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using Image = NetVips.Image;
namespace API.Extensions;
public static class ImageExtensions
{
public static int GetResolution(this Image image)
{
return image.Width * image.Height;
}
///
/// Smaller is better
///
///
///
///
public static float GetMeanSquaredError(this Image img1, Image img2)
{
if (img1.Width != img2.Width || img1.Height != img2.Height)
{
img2.Mutate(x => x.Resize(img1.Width, img1.Height));
}
double totalDiff = 0;
for (var y = 0; y < img1.Height; y++)
{
for (var x = 0; x < img1.Width; x++)
{
var pixel1 = img1[x, y];
var pixel2 = img2[x, y];
var diff = Math.Pow(pixel1.R - pixel2.R, 2) +
Math.Pow(pixel1.G - pixel2.G, 2) +
Math.Pow(pixel1.B - pixel2.B, 2);
totalDiff += diff;
}
}
return (float)(totalDiff / (img1.Width * img1.Height));
}
public static float GetSimilarity(this string imagePath1, string imagePath2)
{
if (!File.Exists(imagePath1) || !File.Exists(imagePath2))
{
throw new FileNotFoundException("One or both image files do not exist");
}
// Calculate similarity score
return CalculateSimilarity(imagePath1, imagePath2);
}
///
/// Determines which image is "better" based on similarity and resolution.
///
/// Path to first image
/// Path to second image
/// Minimum similarity to consider images similar
/// The path of the better image
public static string GetBetterImage(this string imagePath1, string imagePath2, float similarityThreshold = 0.7f)
{
if (!File.Exists(imagePath1) || !File.Exists(imagePath2))
{
throw new FileNotFoundException("One or both image files do not exist");
}
// Calculate similarity score
var similarity = CalculateSimilarity(imagePath1, imagePath2);
using var img1 = Image.NewFromFile(imagePath1, access: Enums.Access.Sequential);
using var img2 = Image.NewFromFile(imagePath2, access: Enums.Access.Sequential);
var resolution1 = img1.Width * img1.Height;
var resolution2 = img2.Width * img2.Height;
// If images are similar, choose the one with higher resolution
if (similarity >= similarityThreshold)
{
return resolution1 >= resolution2 ? imagePath1 : imagePath2;
}
// If images are not similar, allow the new image
return imagePath2;
}
///
/// Calculate a similarity score (0-1f) based on resolution difference and MSE.
///
///
///
///
private static float CalculateSimilarity(string imagePath1, string imagePath2)
{
if (!File.Exists(imagePath1) || !File.Exists(imagePath2))
{
return -1;
}
using var img1 = Image.NewFromFile(imagePath1, access: Enums.Access.Sequential);
using var img2 = Image.NewFromFile(imagePath2, access: Enums.Access.Sequential);
var res1 = img1.Width * img1.Height;
var res2 = img2.Width * img2.Height;
var resolutionDiff = Math.Abs(res1 - res2) / (float)Math.Max(res1, res2);
using var imgSharp1 = SixLabors.ImageSharp.Image.Load(imagePath1);
using var imgSharp2 = SixLabors.ImageSharp.Image.Load(imagePath2);
var mse = imgSharp1.GetMeanSquaredError(imgSharp2);
var normalizedMse = 1f - Math.Min(1f, mse / 65025f); // Normalize based on max color diff
// Final similarity score (weighted)
return Math.Max(0f, 1f - (resolutionDiff * 0.5f) - (1f - normalizedMse) * 0.5f);
}
}