// ============================================================================ // Copyright © 2016-2025 Hexagon Technology Center GmbH. All Rights Reserved. // 文件名: SubPixelZoomProcessor.cs // 描述: 亚像素放大算子,通过高质量插值实现图像的亚像素级放大 // 功能: // - 支持任意倍率放大(含小数倍率如 1.5x、2.3x) // - 多种插值方法(最近邻、双线性、双三次、Lanczos) // - 可选锐化补偿(抵消插值模糊) // - 可选指定输出尺寸 // 算法: 基于 OpenCV Resize 的高质量插值放大 // 作者: 李伟 wei.lw.li@hexagon.com // ============================================================================ using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Structure; using XP.ImageProcessing.Core; using Serilog; using System.Drawing; namespace XP.ImageProcessing.Processors; /// /// 亚像素放大算子 /// public class SubPixelZoomProcessor : ImageProcessorBase { private static readonly ILogger _logger = Log.ForContext(); public SubPixelZoomProcessor() { Name = LocalizationHelper.GetString("SubPixelZoomProcessor_Name"); Description = LocalizationHelper.GetString("SubPixelZoomProcessor_Description"); } protected override void InitializeParameters() { Parameters.Add("ScaleFactor", new ProcessorParameter( "ScaleFactor", LocalizationHelper.GetString("SubPixelZoomProcessor_ScaleFactor"), typeof(double), 2.0, 1.0, 16.0, LocalizationHelper.GetString("SubPixelZoomProcessor_ScaleFactor_Desc"))); Parameters.Add("Interpolation", new ProcessorParameter( "Interpolation", LocalizationHelper.GetString("SubPixelZoomProcessor_Interpolation"), typeof(string), "Lanczos", null, null, LocalizationHelper.GetString("SubPixelZoomProcessor_Interpolation_Desc"), new string[] { "Nearest", "Bilinear", "Bicubic", "Lanczos" })); Parameters.Add("SharpenAfter", new ProcessorParameter( "SharpenAfter", LocalizationHelper.GetString("SubPixelZoomProcessor_SharpenAfter"), typeof(bool), false, null, null, LocalizationHelper.GetString("SubPixelZoomProcessor_SharpenAfter_Desc"))); Parameters.Add("SharpenStrength", new ProcessorParameter( "SharpenStrength", LocalizationHelper.GetString("SubPixelZoomProcessor_SharpenStrength"), typeof(double), 0.5, 0.1, 3.0, LocalizationHelper.GetString("SubPixelZoomProcessor_SharpenStrength_Desc"))); _logger.Debug("InitializeParameters"); } public override Image Process(Image inputImage) { double scaleFactor = GetParameter("ScaleFactor"); string interpolation = GetParameter("Interpolation"); bool sharpenAfter = GetParameter("SharpenAfter"); double sharpenStrength = GetParameter("SharpenStrength"); Inter interMethod = interpolation switch { "Nearest" => Inter.Nearest, "Bilinear" => Inter.Linear, "Bicubic" => Inter.Cubic, _ => Inter.Lanczos4 }; int newWidth = (int)Math.Round(inputImage.Width * scaleFactor); int newHeight = (int)Math.Round(inputImage.Height * scaleFactor); // 确保最小尺寸为 1 newWidth = Math.Max(1, newWidth); newHeight = Math.Max(1, newHeight); var result = new Image(newWidth, newHeight); CvInvoke.Resize(inputImage, result, new Size(newWidth, newHeight), 0, 0, interMethod); // 锐化补偿 if (sharpenAfter) { // Unsharp Masking: result = result + strength * (result - blur) int ksize = Math.Max(3, (int)(scaleFactor * 2) | 1); // 奇数核 using var blurred = result.SmoothGaussian(ksize); for (int y = 0; y < newHeight; y++) { for (int x = 0; x < newWidth; x++) { float val = result.Data[y, x, 0]; float blur = blurred.Data[y, x, 0]; float sharpened = val + (float)(sharpenStrength * (val - blur)); result.Data[y, x, 0] = (byte)Math.Clamp((int)sharpened, 0, 255); } } } _logger.Debug("Process: Scale={Scale}, Interp={Interp}, Size={W}x{H}, Sharpen={Sharpen}", scaleFactor, interpolation, newWidth, newHeight, sharpenAfter); return result; } }