// ============================================================================ // Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved. // 文件名: RotateProcessor.cs // 描述: 图像旋转算子 // 功能: // - 任意角度旋转 // - 支持保持原始尺寸或自适应扩展画布 // - 可选背景填充值 // - 支持双线性插值 // 算法: 仿射变换旋转 // 作者: 李伟 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 RotateProcessor : ImageProcessorBase { private static readonly ILogger _logger = Log.ForContext(); public RotateProcessor() { Name = LocalizationHelper.GetString("RotateProcessor_Name"); Description = LocalizationHelper.GetString("RotateProcessor_Description"); } protected override void InitializeParameters() { Parameters.Add("Angle", new ProcessorParameter( "Angle", LocalizationHelper.GetString("RotateProcessor_Angle"), typeof(double), 90.0, -360.0, 360.0, LocalizationHelper.GetString("RotateProcessor_Angle_Desc"))); Parameters.Add("ExpandCanvas", new ProcessorParameter( "ExpandCanvas", LocalizationHelper.GetString("RotateProcessor_ExpandCanvas"), typeof(bool), false, null, null, LocalizationHelper.GetString("RotateProcessor_ExpandCanvas_Desc"))); Parameters.Add("BackgroundValue", new ProcessorParameter( "BackgroundValue", LocalizationHelper.GetString("RotateProcessor_BackgroundValue"), typeof(int), 0, 0, 255, LocalizationHelper.GetString("RotateProcessor_BackgroundValue_Desc"))); Parameters.Add("Interpolation", new ProcessorParameter( "Interpolation", LocalizationHelper.GetString("RotateProcessor_Interpolation"), typeof(string), "Bilinear", null, null, LocalizationHelper.GetString("RotateProcessor_Interpolation_Desc"), new string[] { "Nearest", "Bilinear", "Bicubic" })); _logger.Debug("InitializeParameters"); } public override Image Process(Image inputImage) { double angle = GetParameter("Angle"); bool expandCanvas = GetParameter("ExpandCanvas"); int bgValue = GetParameter("BackgroundValue"); string interpolation = GetParameter("Interpolation"); Inter interMethod = interpolation switch { "Nearest" => Inter.Nearest, "Bicubic" => Inter.Cubic, _ => Inter.Linear }; int srcW = inputImage.Width; int srcH = inputImage.Height; PointF center = new PointF(srcW / 2.0f, srcH / 2.0f); // 获取旋转矩阵 using var rotMat = new Mat(); CvInvoke.GetRotationMatrix2D(center, angle, 1.0, rotMat); int dstW, dstH; if (expandCanvas) { // 计算旋转后能容纳整幅图像的画布尺寸 double rad = Math.Abs(angle * Math.PI / 180.0); double sinA = Math.Abs(Math.Sin(rad)); double cosA = Math.Abs(Math.Cos(rad)); dstW = (int)Math.Ceiling(srcW * cosA + srcH * sinA); dstH = (int)Math.Ceiling(srcW * sinA + srcH * cosA); // 调整旋转矩阵的平移分量,使图像居中 double[] m = new double[6]; rotMat.CopyTo(m); m[2] += (dstW - srcW) / 2.0; m[5] += (dstH - srcH) / 2.0; // 写回矩阵 using var adjusted = new Mat(2, 3, Emgu.CV.CvEnum.DepthType.Cv64F, 1); System.Runtime.InteropServices.Marshal.Copy(m, 0, adjusted.DataPointer, 6); var result = new Image(dstW, dstH, new Gray(bgValue)); CvInvoke.WarpAffine(inputImage, result, adjusted, new Size(dstW, dstH), interMethod, Warp.Default, BorderType.Constant, new MCvScalar(bgValue)); _logger.Debug("Process: Angle={Angle}, ExpandCanvas=true, Size={W}x{H}", angle, dstW, dstH); return result; } else { dstW = srcW; dstH = srcH; var result = new Image(dstW, dstH, new Gray(bgValue)); CvInvoke.WarpAffine(inputImage, result, rotMat, new Size(dstW, dstH), interMethod, Warp.Default, BorderType.Constant, new MCvScalar(bgValue)); _logger.Debug("Process: Angle={Angle}, ExpandCanvas=false", angle); return result; } } }