Files
XplorePlane/XP.ImageProcessing.Processors/图像增强/SubPixelZoomProcessor.cs
T
2026-04-13 14:36:18 +08:00

127 lines
4.7 KiB
C#

// ============================================================================
// Copyright © 2016-2025 Hexagon Technology Center GmbH. All Rights Reserved.
// 文件å? SubPixelZoomProcessor.cs
// æè¿°: 亚åƒç´ æ”¾å¤§ç®—å­ï¼Œé€šè¿‡é«˜è´¨é‡æ’值实现图åƒçš„亚åƒç´ çº§æ”¾å¤§
// 功能:
// - 支æŒä»»æ„å€çŽ‡æ”¾å¤§ï¼ˆå«å°æ•°å€çއå¦?1.5xã€?.3xï¼?
// - å¤šç§æ’值方法(最近邻ã€åŒçº¿æ€§ã€åŒä¸‰æ¬¡ã€Lanczosï¼?
// - å¯é€‰é”化补å¿ï¼ˆæŠµæ¶ˆæ’值模糊)
// - å¯é€‰æŒ‡å®šè¾“出尺å¯?
// 算法: 基于 OpenCV Resize çš„é«˜è´¨é‡æ’值放å¤?
// 作è€? æŽä¼Ÿ wei.lw.li@hexagon.com
// ============================================================================
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Serilog;
using System.Drawing;
using XP.ImageProcessing.Core;
namespace XP.ImageProcessing.Processors;
/// <summary>
/// 亚åƒç´ æ”¾å¤§ç®—å­?
/// </summary>
public class SubPixelZoomProcessor : ImageProcessorBase
{
private static readonly ILogger _logger = Log.ForContext<SubPixelZoomProcessor>();
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<Gray, byte> Process(Image<Gray, byte> inputImage)
{
double scaleFactor = GetParameter<double>("ScaleFactor");
string interpolation = GetParameter<string>("Interpolation");
bool sharpenAfter = GetParameter<bool>("SharpenAfter");
double sharpenStrength = GetParameter<double>("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<Gray, byte>(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;
}
}