Browse Source

feat: 完成计算部分

master
fajiao 2 years ago
parent
commit
7a820ef5f1
  1. 4
      Cis.Application/Cis.Application.csproj
  2. 48
      Cis.Application/Cm/Entity/CmMarkLabel.cs
  3. 77
      Cis.Application/Core/Algo/HikMarkSeacher.cs
  4. 205
      Cis.Application/Core/Algo/MarkSearcherBase.cs
  5. 8
      Cis.Application/Core/Center/CameraDataCenter.cs
  6. 82
      Cis.Application/Core/Entity/CameraCalcInfo.cs

4
Cis.Application/Cis.Application.csproj

@ -18,6 +18,10 @@
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Cis.Core\Cis.Core.csproj" /> <ProjectReference Include="..\Cis.Core\Cis.Core.csproj" />
</ItemGroup> </ItemGroup>

48
Cis.Application/Cm/Entity/CmMarkLabel.cs

@ -7,6 +7,18 @@
[Tenant(CmInfo.DbName)] [Tenant(CmInfo.DbName)]
public class CmMarkLabel : EntityBase public class CmMarkLabel : EntityBase
{ {
/// <summary>
/// 相机 Id
/// </summary>
[SugarColumn(ColumnDescription = "相机Id")]
public long CbCameraId { get; set; }
/// <summary>
/// 标记组 Id
/// </summary>
[SugarColumn(ColumnDescription = "标记组Id")]
public long CmMarkGroupId { get; set; }
/// <summary> /// <summary>
/// 名称 /// 名称
/// </summary> /// </summary>
@ -14,39 +26,39 @@ public class CmMarkLabel : EntityBase
public string Name { get; set; } public string Name { get; set; }
/// <summary> /// <summary>
/// Pan 位置 /// Pan 坐标
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "Pan位置")] [SugarColumn(ColumnDescription = "Pan坐标")]
public double PanPosition { get; set; } public double PanPosition { get; set; }
/// <summary> /// <summary>
/// Tilt 位置 /// Tilt 坐标
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "Tilt位置")] [SugarColumn(ColumnDescription = "Tilt坐标")]
public double TiltPosition { get; set; } public double TiltPosition { get; set; }
/// <summary> /// <summary>
/// Zoom 位置 /// Zoom 坐标
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "Zoom位置")] [SugarColumn(ColumnDescription = "Zoom坐标")]
public double ZoomPosition { get; set; } public double ZoomPosition { get; set; }
[SugarColumn(ColumnDescription = "画布宽度")]
public double CanvasWidth { get; set; }
[SugarColumn(ColumnDescription = "画布高度")]
public double CanvasHeight { get; set; }
[SugarColumn(ColumnDescription = "画布 left 距离")]
public double CanvasLeft { get; set; }
[SugarColumn(ColumnDescription = "画布 top 距离")]
public double CanvasTop { get; set; }
/// <summary> /// <summary>
/// 备注 /// 备注
/// </summary> /// </summary>
[SugarColumn(ColumnDescription = "备注", Length = 256)] [SugarColumn(ColumnDescription = "备注", Length = 256)]
[MaxLength(256)] [MaxLength(256)]
public string Remark { get; set; } public string Remark { get; set; }
/// <summary>
/// 相机 Id
/// </summary>
[SugarColumn(ColumnDescription = "相机Id")]
public long CbCameraId { get; set; }
/// <summary>
/// 标记组 Id
/// </summary>
[SugarColumn(ColumnDescription = "标记组Id")]
public long CmMarkGroupId { get; set; }
} }

77
Cis.Application/Core/Algo/HikMarkSeacher.cs

@ -0,0 +1,77 @@
using System.Drawing;
namespace Cis.Application.Core;
public class HikMarkSeacher : MarkSearcherBase
{
public HikMarkSeacher(CameraCalcInfo cameraCalcInfo) : base(cameraCalcInfo)
{
}
#region Implement
protected override double ConvertPanPosToAngle(double panPos)
{
double ret = (0.1 * HexToDecMa(panPos)) / (180 * Math.PI);
ret = (ret >= 0) ? ret : (2 * Math.PI + ret);
return ret;
}
protected override double ConvertTiltPosToAngle(double tiltPos, double tiltMinPos = 0)
{
double ndiff;
if (tiltPos > tiltMinPos)
ndiff = HexToDecMa(tiltPos) - HexToDecMa(tiltMinPos);
else
ndiff = HexToDecMa(tiltPos) + HexToDecMa(13824) - HexToDecMa(tiltMinPos);
double ret = (0.1 * ndiff) / (180 * Math.PI);
return ret;
}
protected override PointF GetFOfMatrixByZoomPos(double zoomPos)
{
PointF pointF = new()
{
X = (float)GetFx(zoomPos),
Y = (float)GetFy(zoomPos)
};
return pointF;
}
protected override void CalcSensor()
{
CameraCalcInfo.MinFocusX = 1783.6 / CameraCalcInfo.ImageWidth;
CameraCalcInfo.MinFocusY = 1781.4 / CameraCalcInfo.ImageHeight;
}
#endregion Implement
#region Util
protected virtual double GetFx(double zoomPos)
{
CameraCalcInfo calcInfo = CameraCalcInfo;
return calcInfo.MinFocusX * GetZoomTag(zoomPos);
}
protected virtual double GetFy(double zoomPos)
{
CameraCalcInfo calcInfo = CameraCalcInfo;
return calcInfo.MinFocusY * GetZoomTag(zoomPos);
}
protected virtual double GetZoomTag(double zoomPos)
{
double ret = HexToDecMa(zoomPos) * 0.1;
ret = (ret - 1) * 0.65 + 1;
return ret;
}
protected double HexToDecMa(double wHex)
{
double ret = (wHex / 4096) * 1000 + ((wHex % 4096) / 256) * 100 + ((wHex % 256) / 16) * 10 + (wHex % 16);
return ret;
}
#endregion Util
}

205
Cis.Application/Core/Algo/MarkSearcherBase.cs

@ -1,6 +1,207 @@
namespace Cis.Application.Core; using MathNet.Numerics.LinearAlgebra;
using System.Drawing;
public class MarkSearcherBase namespace Cis.Application.Core;
public abstract class MarkSearcherBase
{
#region Attr
/// <summary>
/// 当前相机参数信息
/// </summary>
protected CameraCalcInfo CameraCalcInfo { get; set; }
protected List<MarkLabelCalcInfo> MarkLabelInfoList { get; set; } = new();
protected MatrixBuilder<double> MBuilder { get; set; } = Matrix<double>.Build;
/// <summary>
/// 世界坐标转化为相机坐标矩阵
/// </summary>
protected Matrix<double> World2CameraMatrix { get; set; }
#endregion Attr
public MarkSearcherBase(CameraCalcInfo cameraCalcInfo)
{
InitCameraCalcInfoRelated(cameraCalcInfo);
}
protected void InitCameraCalcInfoRelated(CameraCalcInfo cameraCalcInfo)
{
CameraCalcInfo = cameraCalcInfo;
CalcSensor();
World2CameraMatrix = ConvertWorldToCamera(cameraCalcInfo);
}
#region Calc
/// <summary>
/// 计算标签位置过程
/// </summary>
/// <returns></returns>
public void Calc(CameraCalcInfo cameraCalcInfo)
{
//判断
if (IsCameraRotate(cameraCalcInfo))
InitCameraCalcInfoRelated(cameraCalcInfo);
if (World2CameraMatrix == null || MarkLabelInfoList.Count == 0)
return;
for (int index = 0; index < MarkLabelInfoList.Count; index++)
{
MarkLabelCalcInfo label = MarkLabelInfoList[index];
Matrix<double> labelC2WMatrix = ConvertCameraToWorld(label);
Matrix<double> labelPointMatrix = MBuilder.DenseOfArray(new double[,]
{
{ label.CanvasWidth / CameraCalcInfo.ImageWidth - 0.5 },
{ label.CanvasHeight / CameraCalcInfo.ImageHeight - 0.5 },
{ 1 }
});
Matrix<double> lResult = labelC2WMatrix.Multiply(labelPointMatrix);
Matrix<double> pResult = World2CameraMatrix.Multiply(lResult);
double x = pResult[0, 0] / pResult[2, 0] + 0.5;
double y = pResult[1, 0] / pResult[2, 0] + 0.5;
MarkLabelCalcResult labelCalcResult = new();
if (x > 0.99 || x < 0.01 || y > 0.99 || y < 0.01 || pResult[2, 0] < 0)
{
labelCalcResult.InFlag = false;
}
else
{
labelCalcResult.InFlag = true;
labelCalcResult.CanvasLeft = x * CameraCalcInfo.ImageWidth;
labelCalcResult.CanvasTop = y * CameraCalcInfo.ImageHeight;
}
}
}
/// <summary>
/// 判断相机是否进行了转动,转动了则需要重新计算世界坐标到相机坐标的转换矩阵
/// </summary>
/// <param name="newInfo"></param>
/// <returns></returns>
protected bool IsCameraRotate(CameraCalcInfo newInfo)
{ {
return CameraCalcInfo == null ||
CameraCalcInfo.PtzInfo.Pan != newInfo.PtzInfo.Pan ||
CameraCalcInfo.PtzInfo.Tilt != newInfo.PtzInfo.Tilt ||
CameraCalcInfo.PtzInfo.Zoom != newInfo.PtzInfo.Zoom;
}
/// <summary>
/// 获取将世界坐标系中的点转化为相机坐标系中的点的转换矩阵
/// </summary>
/// <param name="cameraCalcInfo"></param>
/// <returns></returns>
protected Matrix<double> ConvertWorldToCamera(CameraCalcInfo cameraCalcInfo)
{
double panAngle = ConvertPanPosToAngle(cameraCalcInfo.PtzInfo.Pan);
double tiltAngle = ConvertTiltPosToAngle(cameraCalcInfo.PtzInfo.Tilt);
PointF pointF = GetFOfMatrixByZoomPos(cameraCalcInfo.PtzInfo.Zoom);
double sinPan = Math.Sin(panAngle);
double cosPan = Math.Cos(panAngle);
double sinTilt = Math.Sin(tiltAngle);
double cosTilt = Math.Cos(tiltAngle);
Matrix<double> fMatrix = MBuilder.DenseOfArray(new double[,]
{
{ pointF.X, 0, 0 },
{ 0, pointF.Y, 0 },
{ 0, 0, 1 },
});
Matrix<double> rotateTiltMatrix = MBuilder.DenseOfArray(new double[,]
{
{ 1, 0, 0 },
{ 0, cosTilt, sinTilt },
{ 0, -sinTilt, cosTilt },
});
Matrix<double> midResult = fMatrix.Multiply(rotateTiltMatrix);
Matrix<double> rotatePanMatrix = MBuilder.DenseOfArray(new double[,]
{
{ cosPan, 0, sinPan },
{ 0, 1, 0 },
{ -sinPan, 0, cosPan },
});
return midResult.Multiply(rotatePanMatrix);
}
/// <summary>
/// 获取将相机坐标系中的点转化为世界坐标系中的点的转换矩阵
/// </summary>
/// <param name="labelCalcInfo"></param>
/// <returns></returns>
protected Matrix<double> ConvertCameraToWorld(MarkLabelCalcInfo labelCalcInfo)
{
double panAngle = ConvertPanPosToAngle(labelCalcInfo.PtzInfo.Pan);
double tiltAngle = ConvertTiltPosToAngle(labelCalcInfo.PtzInfo.Tilt);
PointF pointF = GetFOfMatrixByZoomPos(labelCalcInfo.PtzInfo.Zoom);
double sinPan = Math.Sin(panAngle);
double cosPan = Math.Cos(panAngle);
double sinTilt = Math.Sin(tiltAngle);
double cosTilt = Math.Cos(tiltAngle);
Matrix<double> rotatePanMatrix = MBuilder.DenseOfArray(new double[,] {
{ cosPan, 0, -sinPan },
{ 0, 1, 0 },
{ sinPan, 0, cosPan }
});
Matrix<double> rotateTiltMatrix = MBuilder.DenseOfArray(new double[,] {
{ 1, 0, 0 },
{ 0, cosTilt, -sinTilt },
{ 0, sinTilt, cosTilt }
});
Matrix<double> midResult = rotatePanMatrix.Multiply(rotateTiltMatrix);
Matrix<double> fMatrix = MBuilder.DenseOfArray(new double[,] {
{ (1 / pointF.X), 0, 0 },
{ 0, (1 / pointF.Y), 0 },
{ 0, 0, 1 }
});
return midResult.Multiply(fMatrix);
}
/// <summary>
/// 此方法计算在球机zoom值最小的情况下成像矩阵中的 f 本质为获取像元大小
/// 尝试方案1:通过计算的方式来获取
/// 尝试方案2:通过张友定相机标定的方法来生成成像矩阵中的 f
/// </summary>
protected virtual void CalcSensor()
{
}
#endregion Calc
#region Util
/// <summary>
/// 将Pan值转化为角度
/// </summary>
/// <returns></returns>
protected abstract double ConvertPanPosToAngle(double panPos);
/// <summary>
/// 将Tilt转化为角度
/// </summary>
/// <returns></returns>
protected abstract double ConvertTiltPosToAngle(double tiltPos, double tiltMinPos = 0);
/// <summary>
/// 根据当前zoom值获取相机矩阵参数
/// </summary>
/// <param name="zoomPos"></param>
/// <returns></returns>
protected abstract PointF GetFOfMatrixByZoomPos(double zoomPos);
#endregion Util
} }

8
Cis.Application/Core/Center/CameraDataCenter.cs

@ -9,15 +9,15 @@ public class CameraDataCenter
{ {
#region Attr #region Attr
private Thread _thread { get; set; }
private List<TbPtzCamera> _tbPtzCameraList { get; set; }
private ConcurrentDictionary<string, CameraCalcInfo> _cameraPtzInfoDict { get; set; }
private readonly SqlSugarRepository<CbCamera> _cbCameraRep; private readonly SqlSugarRepository<CbCamera> _cbCameraRep;
private readonly SqlSugarRepository<CmMarkLabel> _cmMarkLableRep; private readonly SqlSugarRepository<CmMarkLabel> _cmMarkLableRep;
private readonly SqlSugarRepository<TbPtzCamera> _tbPtzCameraRep; private readonly SqlSugarRepository<TbPtzCamera> _tbPtzCameraRep;
private readonly PtzServerApi _ptzServerApi; private readonly PtzServerApi _ptzServerApi;
private Thread _thread { get; set; }
private List<TbPtzCamera> _tbPtzCameraList { get; set; }
private ConcurrentDictionary<string, CameraCalcInfo> _cameraPtzInfoDict { get; set; }
#endregion Attr #endregion Attr
public CameraDataCenter() public CameraDataCenter()

82
Cis.Application/Core/Entity/CameraCalcInfo.cs

@ -1,32 +1,104 @@
namespace Cis.Application.Core; namespace Cis.Application.Core;
/// <summary> /// <summary>
/// 相机 Ptz 信息 /// 相机计算信息
/// </summary> /// </summary>
public class CameraCalcInfo public class CameraCalcInfo
{ {
/// <summary>
/// Ptz 信息
/// </summary>
public PtzInfo PtzInfo { get; set; }
/// <summary> /// <summary>
/// 图像的宽度 /// 图像的宽度
/// </summary> /// </summary>
public int ImageWidth { get; set; } = 1920; public int ImageWidth { get; set; } = 1920;
/// <summary> /// <summary>
/// 图像的 /// 图像的
/// </summary> /// </summary>
public int ImageHeight { get; set; } = 1080; public int ImageHeight { get; set; } = 1080;
/// <summary> /// <summary>
/// Pan /// 最小焦距
/// </summary>
public double MinFocusX { get; set; } = 0f;
public double MinFocusY { get; set; } = 0f;
}
/// <summary>
/// Ptz 信息
/// </summary>
public class PtzInfo
{
/// <summary>
/// Pan 坐标
/// </summary> /// </summary>
public double Pan { get; set; } public double Pan { get; set; }
/// <summary> /// <summary>
/// Tilt /// Tilt 坐标
/// </summary> /// </summary>
public double Tilt { get; set; } public double Tilt { get; set; }
/// <summary> /// <summary>
/// Zoom /// Zoom 坐标
/// </summary> /// </summary>
public double Zoom { get; set; } public double Zoom { get; set; }
} }
/// <summary>
/// 标记标签计算信息
/// </summary>
public class MarkLabelCalcInfo
{
/// <summary>
/// Ptz 信息
/// </summary>
public PtzInfo PtzInfo { get; set; }
/// <summary>
/// 画布宽度
/// </summary>
public double CanvasWidth { get; set; }
/// <summary>
/// 画布高度
/// </summary>
public double CanvasHeight { get; set; }
/// <summary>
/// 画布 left 距离
/// </summary>
public double CanvasLeft { get; set; }
/// <summary>
/// 画布 top 距离
/// </summary>
public double CanvasTop { get; set; }
}
/// <summary>
/// 标记标签计算结果
/// </summary>
public class MarkLabelCalcResult
{
/// <summary>
/// true 显示(在当前视频画面里面)
/// false 不显示(不在当前视频画面里面)
/// </summary>
public bool InFlag { get; set; }
/// <summary>
/// 画布 left 距离
/// </summary>
public double CanvasLeft { get; set; }
/// <summary>
/// 画布 top 距离
/// </summary>
public double CanvasTop { get; set; }
}
Loading…
Cancel
Save