140 lines
4.9 KiB
C#
140 lines
4.9 KiB
C#
// ============================================================================
|
|
// 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;
|
|
|
|
/// <summary>
|
|
/// 图像旋转算子
|
|
/// </summary>
|
|
public class RotateProcessor : ImageProcessorBase
|
|
{
|
|
private static readonly ILogger _logger = Log.ForContext<RotateProcessor>();
|
|
|
|
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<Gray, byte> Process(Image<Gray, byte> inputImage)
|
|
{
|
|
double angle = GetParameter<double>("Angle");
|
|
bool expandCanvas = GetParameter<bool>("ExpandCanvas");
|
|
int bgValue = GetParameter<int>("BackgroundValue");
|
|
string interpolation = GetParameter<string>("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<Gray, byte>(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<Gray, byte>(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;
|
|
}
|
|
}
|
|
} |