using System;
using System.IO;
using System.Text;
using System.Linq;
using System.Drawing;
using System.IO.Compression;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using AI.Common;
using AI.Common.Log;
using AI.Common.Tools;
namespace AI.Reconstruction
{
///
/// 模型尺寸
///
public struct ModelSize
{
public int ModelLengthX;
public int ModelLengthY;
public int ModelLengthZ;
public int OneFacePixelsNum;
}
///
/// 模型切片类型
///
public enum ModelSliceType
{
XEqual = 0,
YEqual,
ZEqual,
Normal
}
///
/// 模型切面
///
public struct ModelSlice
{
//切片像素点数据
public byte[] SliceImageData;
//图像的宽
public int SliceWidth;
//图像的高
public int SliceHeight;
}
///
/// cefsharp的输入数据
///
public struct CefInputDatas
{
// Point list
public IList PointsList;
// Clip image name
public string ClipImageName;
}
///
/// 共面的三个点
///
public struct CoplanarPoints
{
private Point3DF _p1;
private Point3DF _p2;
private Point3DF _p3;
///
/// 第一个点
///
public Point3DF Point1 { get => _p1; set => _p1 = value; }
///
/// 第二个点
///
public Point3DF Point2 { get => _p2; set => _p2 = value; }
///
/// 第三个点
///
public Point3DF Point3 { get => _p3; set => _p3 = value; }
///
/// 构造函数
///
///
///
///
public CoplanarPoints(Point3DF point1, Point3DF point2, Point3DF point3)
{
_p1 = point1;
_p2 = point2;
_p3 = point3;
}
///
/// 空的CoplanarPoints
///
public static readonly CoplanarPoints Empty = new CoplanarPoints(Point3DF.Empty, Point3DF.Empty, Point3DF.Empty);
///
/// 判断是否相等
///
///
///
///
public static bool Equals(CoplanarPoints one, CoplanarPoints other)
{
return one.Point1 == other.Point1 && one.Point2 == other.Point2 && one.Point3 == other.Point3;
}
///
/// 判断是否相等
///
///
///
///
public static bool operator ==(CoplanarPoints left, CoplanarPoints right)
{
return Equals(left, right);
}
///
/// 判断是否相等
///
///
///
///
public static bool operator !=(CoplanarPoints left, CoplanarPoints right)
{
return !Equals(left, right);
}
}
///
/// 获得切片图像的类
///
public class SliceHelper
{
//模型边界x最大值
private double _xEdge;
//模型边界y最大值
private double _yEdge;
//模型边界z最大值
private double _zEdge;
//模型的尺寸
private ModelSize _modelSize;
//读取到的模型数据
private byte[][] _modelData;
//一般切片
private ModelSlice _generalModelSlice;
//缩放后切片
private ModelSlice _resizedModelSlice;
//是否已经设置模型源文件
private bool _isSourceBeSet;
//确定一个平面的三个不共线的点
private One3DPlaneThreeBasicPoints _inputThreeBasic3DPoints;
//切片的端点list,世界点坐标
private List _endPointList3D;
//切片的端点list,图像点坐标
private List _endPointList2I;
//切片的端点list,图像端点极坐标点坐标
private readonly List _endPointList2DPolar;
//三维坐标变换参数
private CoordinateTransformation3D _coordinateTransformation3D;
//切片的宽,变成2的n次方
private int _sliceWidth2N;
//切片的高,变成2的n次方
private int _sliceHeight2N;
//切片图像的最大长度
private int _sliceMaxLength;
//扫描深度
private float _scanDepth;
//切片图像坐标系的基础3D点
private One2DPlaneThreeBasic3DPoints _planeBasic3DPoints;
//切片图像坐标系的基础2D点
private One2DPlaneThreeBasic2DPoints _planeBasic2DPoints;
//多线程线程个数
private readonly ParallelOptions _parallelOption = new ParallelOptions { MaxDegreeOfParallelism = 2 * Environment.ProcessorCount };
//private static SliceHelper _instance;
//public static SliceHelper Instance
//{
// get => _instance ?? (_instance = new SliceHelper());
//}
#region dllImport
[DllImport(@"PlaqueProcessingCpp.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
private static extern bool Get2DMeasureImage(AI.Reconstruction.AIReconstructor.StructImageInfo srcImageInfo, int dataSize, ref AI.Reconstruction.AIReconstructor.StructImageInfo dstImageInfo);
#endregion
public SliceHelper()
{
_generalModelSlice = new ModelSlice();
_resizedModelSlice = new ModelSlice();
_inputThreeBasic3DPoints = new One3DPlaneThreeBasicPoints();
_endPointList3D = new List();
_endPointList2I = new List();
_endPointList2DPolar = new List();
}
public ModelSize GetModelSize()
{
return _modelSize;
}
public byte[][] GetModelData()
{
return _modelData;
}
///
/// 设置模型来源
///
/// mdl file
/// model's width distance
/// model's height distance
/// model's depth distance
/// scan depth
/// Whether set model source successfully
public bool SetModelSource(string mdlFilePath, int width, int height, int depth, float scanDepth)
{
try
{
if (depth < 5)
{
LogHelper.ErrorLog("SliceHelper,Do SetModelSource,depth<5.");
return false;
}
if (_isSourceBeSet)
{
Release();
}
_isSourceBeSet = false;
_modelSize = new ModelSize
{
ModelLengthX = width,
ModelLengthY = height,
ModelLengthZ = depth,
OneFacePixelsNum = width * height
};
_modelData = new byte[_modelSize.ModelLengthZ][];
for (var i = 0; i < _modelSize.ModelLengthZ; ++i)
{
_modelData[i] = new byte[_modelSize.OneFacePixelsNum];
}
if (!ParseMdl(mdlFilePath, depth))
{
return false;
}
_sliceMaxLength = GetMaxImageLength();
_generalModelSlice.SliceImageData = new byte[_sliceMaxLength];
_resizedModelSlice.SliceImageData = new byte[_sliceMaxLength];
//计算模型边界
_xEdge = _modelSize.ModelLengthX - 1 + MathTools3D.Precision;
_yEdge = _modelSize.ModelLengthY - 1 + MathTools3D.Precision;
_zEdge = _modelSize.ModelLengthZ - 1 + MathTools3D.Precision;
_inputThreeBasic3DPoints = new One3DPlaneThreeBasicPoints
{
PointA = new Point3DF(0, 0, 0),
PointB = new Point3DF(0, 0, 0),
PointC = new Point3DF(0, 0, 0)
};
_scanDepth = scanDepth;
_isSourceBeSet = true;
return true;
}
catch (Exception e)
{
LogHelper.ErrorLog("SliceHelper, SetModelSource error," + e.Message + "," + e.StackTrace);
return false;
}
}
///
/// 解析模型
///
private bool ParseMdl(string mdlFilePath, int depth)
{
using (var stream = new FileStream(mdlFilePath, FileMode.Open))
{
var fileStreamReader = new AIStreamReader(stream);
var version = fileStreamReader.ReadString();
if (version == "V1")
{
var compressedBytes = fileStreamReader.ReadBytes();
using (var ms = new MemoryStream(compressedBytes))
{
using (GZipStream zipStream = new GZipStream(ms, CompressionMode.Decompress))
{
var zipStreamReader = new AIStreamReader(zipStream);
return FillImageArray(zipStreamReader, depth);
}
}
}
else
{
//fileStreamReader.Reset();
stream.Position = 0;
return FillImageArray(fileStreamReader, depth);
}
}
}
///
/// 数组填充6个表面图像
///
private bool FillImageArray(AIStreamReader reader, int depth)
{
var imgCount = reader.ReadInt();
if (imgCount != depth)
{
LogHelper.ErrorLog("mdl file's image count not equal with model depth.");
return false;
}
for (var i = 0; i < imgCount; ++i)
{
var readBytes = reader.ReadBytes();
byte[] decodedDataBuffer = new byte[_modelSize.OneFacePixelsNum];
if (!AIReconstructor.ImDataDecode(readBytes, readBytes.Length, decodedDataBuffer, decodedDataBuffer.Length))
{
int errorMaxLen = 256;
StringBuilder errorMsg = new StringBuilder(errorMaxLen);
AIReconstructor.EnumCppCoreErrorCode errorCode = AIReconstructor.EnumCppCoreErrorCode.None;
AIReconstructor.GetErrorCodeAndMsg(ref errorCode, errorMsg, errorMaxLen);
throw new Exception("Failed at decoding model image datas, error code: "
+ errorCode.ToString() + " , details: " + errorMsg.ToString() + " .");
}
Array.Copy(decodedDataBuffer, 0, _modelData[i], 0, _modelSize.OneFacePixelsNum);
}
return true;
}
///
/// 释放资源
///
///
public void Release()
{
_generalModelSlice.SliceImageData = null;
_resizedModelSlice.SliceImageData = null;
_modelData = null;
GC.Collect();
}
///
/// 获取模型最大的切面尺寸
///
///
private int GetMaxImageLength()
{
var lenList = new List { _modelSize.ModelLengthX, _modelSize.ModelLengthY, _modelSize.ModelLengthZ };
var maxHypotenuse1 = Math.Sqrt(lenList[0] * lenList[0] + lenList[1] * lenList[1]);
var maxHypotenuse2 = Math.Sqrt(lenList[1] * lenList[1] + lenList[2] * lenList[2]);
var maxHypotenuse3 = Math.Sqrt(lenList[0] * lenList[0] + lenList[2] * lenList[2]);
var maxLength = Math.Max(maxHypotenuse1, maxHypotenuse2);
maxLength = Math.Max(maxLength, maxHypotenuse3);
return (int)Math.Round(maxLength * maxLength);
}
///
/// 计算三维切片图像
///
/// Input data include points >= 3 and clip category
/// Save path
/// True if calculate successfully.
public bool Calculate3DSliceImage(CefInputDatas inputData, string savePath)
{
if (string.IsNullOrWhiteSpace(savePath))
{
LogHelper.ErrorLog("SliceHelper, slice image's save path is empty");
return false;
}
if (!GetModelSlice(inputData))
{
LogHelper.ErrorLog("SliceHelper, Calculate3DSliceImage GetModelSlice failed.");
return false;
}
return SaveImage(savePath);
}
///
/// 计算模型切片
///
///
///
public bool GetModelSlice(CefInputDatas inputData)
{
try
{
//判断输入数据是否合法,当前是否可以获取切片
if (!CheckBeforeGetModelSlice(inputData))
{
return false;
}
//获得基础点的三个点
if (!GetBasePoint(inputData))
{
LogHelper.ErrorLog("SliceHelper,Input point is parallel.");
return false;
}
//获得切面类型
var sliceType = MathTools3D.GetModelSliceType(_inputThreeBasic3DPoints);
//计算切面与模型的交点
_endPointList3D = MathTools3D.GetIntersectionOfPlaneAndModel(_inputThreeBasic3DPoints, _modelSize, sliceType);
//计算旋转矩阵
_coordinateTransformation3D = GetCoordinateTransformation();
//获得三维点对应的二维点
_endPointList2I = MathTools3D.GetRotatedImageEndPoints(_endPointList3D, _planeBasic3DPoints, sliceType);
//顺时针排序端点
MathTools3D.SortEndPointClockwise(_planeBasic2DPoints, _endPointList3D, _endPointList2I);
//获得切片图像大小
GetSlicePanelSize(sliceType);
//设置切面图像像素点的值
return SetModelSliceData(sliceType);
}
catch (Exception e)
{
LogHelper.ErrorLog(" SliceHelper, GetModelSlice error." + e.Message + "," + e.StackTrace);
return false;
}
}
///
/// 判断输入数据是否合法,当前是否可以获取切片
///
///
///
private bool CheckBeforeGetModelSlice(CefInputDatas inputData)
{
//模型是否已设置
if (!_isSourceBeSet)
{
LogHelper.ErrorLog("SliceHelper,Model source not be set");
return false;
}
//输入点个数是否小于3
if (inputData.PointsList.Count < 3)
{
LogHelper.ErrorLog("SliceHelper,input point count is less than 3");
return false;
}
//输入点是否在模型内
foreach (var point in inputData.PointsList)
{
//if (ModelEdgeIsInModel(point)) continue;
if (point.X > MathTools3D.NegPrecision && point.X < _xEdge &&
point.Y > MathTools3D.NegPrecision && point.Y < _yEdge &&
point.Z > MathTools3D.NegPrecision && point.Z < _zEdge) continue;
LogHelper.ErrorLog(
$"SliceHelper,Slice input point error: out of model x:{point.X}, y:{point.Y}, z:{point.Z}");
return false;
}
return true;
}
///
/// 计算旋转矩阵
///
///
///
private CoordinateTransformation3D GetCoordinateTransformation()
{
//旋转后的图像坐标系,基于的三个世界点
_planeBasic3DPoints = MathTools3D.GetOne2DPlaneBasicPoints(_endPointList3D);
//计算_plane2DBasic3DPoints对应的二维点
_planeBasic2DPoints = MathTools3D.ChangePlaneBasic3DPointTo2D(_planeBasic3DPoints);
//根据坐标系基础点的三维坐标和二维坐标计算旋转矩阵
return MathTools3D.GetCoordinateTransformationParameter(_planeBasic3DPoints, _planeBasic2DPoints);
}
///
/// 获得切片最小尺寸
///
private void GetSlicePanelSize(ModelSliceType sliceType)
{
//获得切片像素值
switch (sliceType)
{
case ModelSliceType.XEqual:
_generalModelSlice.SliceWidth = _modelSize.ModelLengthY;
_generalModelSlice.SliceHeight = _modelSize.ModelLengthZ;
break;
case ModelSliceType.YEqual:
_generalModelSlice.SliceWidth = _modelSize.ModelLengthX;
_generalModelSlice.SliceHeight = _modelSize.ModelLengthZ;
break;
case ModelSliceType.ZEqual:
_generalModelSlice.SliceWidth = _modelSize.ModelLengthX;
_generalModelSlice.SliceHeight = _modelSize.ModelLengthY;
break;
default:
_generalModelSlice.SliceWidth = _endPointList2I.Max(m => m.X);
_generalModelSlice.SliceHeight = _endPointList2I.Max(m => m.Y);
break;
}
var imageLength = _generalModelSlice.SliceWidth * _generalModelSlice.SliceHeight;
if (_sliceMaxLength < imageLength)
{
_generalModelSlice.SliceImageData = new byte[imageLength];
_resizedModelSlice.SliceImageData = new byte[imageLength];
//_modelMeasureSlice = new ModelMeasureSlice(imageLength);
_sliceMaxLength = imageLength;
}
}
///
/// 设置切面图像像素点的值
///
///
///
private bool SetModelSliceData(ModelSliceType sliceType)
{
try
{
//获得切片像素值
switch (sliceType)
{
case ModelSliceType.XEqual:
return GetModeSliceDataX((int)Math.Round(_inputThreeBasic3DPoints.PointA.X));
case ModelSliceType.YEqual:
return GetModeSliceDataY((int)Math.Round(_inputThreeBasic3DPoints.PointA.Y));
case ModelSliceType.ZEqual:
return GetModeSliceDataZ((int)Math.Round(_inputThreeBasic3DPoints.PointA.Z));
case ModelSliceType.Normal:
return GetModeSliceDataNormal();
default:
return false;
}
}
catch (Exception e)
{
LogHelper.ErrorLog("SliceHelper, SetModelSliceData error," + e.Message + "," + e.StackTrace);
return false;
}
}
///
/// 获得基础的三个点
///
///
///
private bool GetBasePoint(CefInputDatas inputData)
{
var count = inputData.PointsList.Count;
for (var i = 0; i < count; ++i)
{
for (var j = 0; j < count; ++j)
{
for (var z = 0; z < count; ++z)
{
if (i == j || j == z || i == z) continue;
//计算切面的基础点
_inputThreeBasic3DPoints.PointA = MathTools3D.ChangePrecision(inputData.PointsList[i]);
_inputThreeBasic3DPoints.PointB = MathTools3D.ChangePrecision(inputData.PointsList[j]);
_inputThreeBasic3DPoints.PointC = MathTools3D.ChangePrecision(inputData.PointsList[z]);
if (!MathTools3D.IsParallel(_inputThreeBasic3DPoints.PointA, _inputThreeBasic3DPoints.PointB, _inputThreeBasic3DPoints.PointC))
{
return true;
}
}
}
}
return false;
}
///
/// 计算最终图像的大小
///
///
private Size GetDstImageSize()
{
int dstWidth;
int dstHeight;
//宽
if (_generalModelSlice.SliceWidth < 512)
{
dstWidth = _generalModelSlice.SliceWidth >= 256 ? 256 : 128;
}
else
{
dstWidth = 512;
}
//高
if (_generalModelSlice.SliceHeight < 512)
{
dstHeight = _generalModelSlice.SliceHeight >= 256 ? 256 : 128;
}
else
{
dstHeight = 512;
}
return new Size(dstWidth, dstHeight);
}
///
/// 计算切片端点的极坐标
///
///
///
private void ChangeToPolarCoordinates(int ratioWidth, int ratioHeight)
{
try
{
_endPointList2DPolar.Clear();
var dstWidth = _sliceWidth2N / ratioWidth;
var dstHeight = _sliceHeight2N / ratioHeight;
foreach (var point in _endPointList2I)
{
var a = (int)((float)point.X / ratioWidth + 0.5);
var b = dstHeight - (int)((float)point.Y / ratioHeight + 0.5);
var a1 = Math.Abs(a / (float)dstWidth);
var b1 = Math.Abs(b / (float)dstHeight);
a1 = Math.Min(Math.Max(a1, 0), 1);
b1 = Math.Min(Math.Max(b1, 0), 1);
_endPointList2DPolar.Add(new Point2DF(a1, b1));
}
}
catch (Exception e)
{
LogHelper.ErrorLog("SliceHelper, ChangeToPolarCoordinates error:", e.Message);
}
}
///
/// x坐标相等时获得切片图像数据的函数
///
///
///
private bool GetModeSliceDataX(double xPos)
{
var x = (int)Math.Round(xPos);
x = Math.Min(_modelSize.ModelLengthX - 1, x);
x = Math.Max(0, x);
Parallel.For(0, _generalModelSlice.SliceHeight, _parallelOption, h =>
{
var dstIndex = h * _generalModelSlice.SliceWidth;
var z = _modelSize.ModelLengthZ - 1 - h;
var srcIndex = _modelSize.ModelLengthX * (_modelSize.ModelLengthY - 1) + x;
for (var w = 0; w < _generalModelSlice.SliceWidth; ++w)
{
_generalModelSlice.SliceImageData[dstIndex] = _modelData[z][srcIndex];
++dstIndex;
srcIndex -= _modelSize.ModelLengthX;
}
});
return true;
}
///
/// y坐标相等时获得切片图像数据的函数
///
///
///
private bool GetModeSliceDataY(double yPos)
{
var y = (int)Math.Round(yPos);
y = Math.Min(_modelSize.ModelLengthY - 1, y);
y = Math.Max(0, y);
var z = _modelSize.ModelLengthZ - 1;
var srcIndex = (y + 1) * _modelSize.ModelLengthX - 1;
Parallel.For(0, _generalModelSlice.SliceHeight, _parallelOption, h =>
{
var z1 = z - h;
var dstIndex = h * _generalModelSlice.SliceWidth;
for (var w = 0; w < _generalModelSlice.SliceWidth; ++w)
{
_generalModelSlice.SliceImageData[dstIndex] = _modelData[z1][srcIndex - w];
++dstIndex;
}
});
return true;
}
///
/// z坐标相等时获得切片图像数据的函数
///
///
///
private bool GetModeSliceDataZ(double zPos)
{
var z = (int)Math.Round(zPos);
z = Math.Min(_modelSize.ModelLengthZ - 1, z);
z = Math.Max(0, z);
var dstIndex = 0;
var srcIndex = _modelSize.ModelLengthX * _modelSize.ModelLengthY - 1;
var count = _generalModelSlice.SliceHeight * _generalModelSlice.SliceWidth;
for (var i = 0; i < count; ++i)
{
_generalModelSlice.SliceImageData[dstIndex] = _modelData[z][srcIndex];
++dstIndex;
--srcIndex;
}
return true;
}
///
/// XYZ坐标都不相等时获得切片图像数据的函数
///
///
///
///
///
private bool GetModeSliceDataNormal()
{
try
{
//分别计算每一行的图像像素值(多线程并行计算)
Parallel.For(0, _generalModelSlice.SliceHeight, _parallelOption, GetSliceData);
return true;
}
catch (Exception e)
{
LogHelper.ErrorLog("SliceHelper, GetModeSliceDataNormal have an error," + e.Message + "," + e.StackTrace);
return false;
}
}
///
/// 计算切面图像点像素值,每一行
///
///
///
private void GetSliceData(int start)
{
try
{
//精度要求
float Precision = 0.0001f;
//精度要求
float NegPrecision = -0.0001f;
var tran = _coordinateTransformation3D.TranslationMatrix;
var rotationMatrix = _coordinateTransformation3D.RotationMatrix;
var startIndex = start * _generalModelSlice.SliceWidth;
var maxCount = startIndex + _generalModelSlice.SliceWidth;
var modelLengthX = _modelSize.ModelLengthX;
var x = tran[0] + rotationMatrix[1] * start;
var y = tran[1] + rotationMatrix[4] * start;
var z = tran[2] + rotationMatrix[7] * start;
var negativeEdge = NegPrecision;
var xEdge = _modelSize.ModelLengthX - 1 + Precision;
var yEdge = _modelSize.ModelLengthY - 1 + Precision;
var zEdge = _modelSize.ModelLengthZ - 1 + Precision;
while (startIndex < maxCount)
{
if (x > negativeEdge && x < xEdge && y > negativeEdge && y < yEdge && z > negativeEdge && z < zEdge)
{
_generalModelSlice.SliceImageData[startIndex] = _modelData[(int)(z + 0.5)][modelLengthX * (int)(y + 0.5) + (int)(x + 0.5)];
}
else
{
_generalModelSlice.SliceImageData[startIndex] = 0;
}
x += rotationMatrix[0];
y += rotationMatrix[3];
z += rotationMatrix[6];
++startIndex;
}
}
catch (Exception e)
{
LogHelper.ErrorLog($"SliceHelper, GetSliceData error {e}");
}
}
///
/// 拷贝模型切片数据到目标byte数组
///
private static void CopyPixel(byte[] srcByte, Size srcSize, byte[] dstByte, int dstWidth)
{
for (var h = 0; h < srcSize.Height; ++h)
{
var start1 = h * srcSize.Width;
var start2 = h * dstWidth;
for (var w = 0; w < srcSize.Width; ++w)
{
dstByte[start2] = srcByte[start1];
++start1;
++start2;
}
}
}
///
/// 返回切面端点的三维坐标
///
///
public List GetModelSliceEndPoint3D()
{
return _endPointList3D;
}
///
/// 返回切面端点的二维坐标
///
///
public List GetModelSliceEndPointPolar2D()
{
return _endPointList2DPolar;
}
///
/// 保存切片图像到目标路径
///
private bool SaveImage(string savePath)
{
try
{
////计算目标图像大小
var dstSize = GetDstImageSize();
var byteDst = new byte[dstSize.Width * dstSize.Height];
_sliceWidth2N = MathTools3D.GetMinPowOfTwo(_generalModelSlice.SliceWidth);
_sliceHeight2N = MathTools3D.GetMinPowOfTwo(_generalModelSlice.SliceHeight);
//计算缩放比率
var ratioWidth = _sliceWidth2N / dstSize.Width;
var ratioHeight = _sliceHeight2N / dstSize.Height;
ratioWidth = ratioWidth > 1 ? ratioWidth : 1;
ratioHeight = ratioHeight > 1 ? ratioHeight : 1;
var generalWH = new Size(_generalModelSlice.SliceWidth, _generalModelSlice.SliceHeight);
if (ratioWidth > 1 || ratioHeight > 1)
{
var remainderW = _generalModelSlice.SliceWidth % ratioWidth;
var remainderH = _generalModelSlice.SliceHeight % ratioHeight;
_resizedModelSlice.SliceWidth = (_generalModelSlice.SliceWidth + remainderW) / ratioWidth;
_resizedModelSlice.SliceHeight = (_generalModelSlice.SliceHeight + remainderH) / ratioHeight;
var resizedWH = new Size(_resizedModelSlice.SliceWidth, _resizedModelSlice.SliceHeight);
//缩放并将数据拷贝到最终图像上
_resizedModelSlice.SliceImageData = ResizeNearestNeighbor(_generalModelSlice.SliceImageData, generalWH, resizedWH);
CopyPixel(_resizedModelSlice.SliceImageData, resizedWH, byteDst, dstSize.Width);
}
else
{
var size = new Size(_generalModelSlice.SliceWidth, _generalModelSlice.SliceHeight);
CopyPixel(_generalModelSlice.SliceImageData, size, byteDst, dstSize.Width);
}
//dstImage.Save(savePath);
ByteEncoderSave(byteDst, new Size(dstSize.Width, dstSize.Height), savePath);
//计算图像的极坐标
ChangeToPolarCoordinates(ratioWidth, ratioHeight);
return true;
}
catch (Exception e)
{
LogHelper.ErrorLog("SliceHelper, SaveImage have an error," + e.Message + "," + e.StackTrace);
return false;
}
}
///
/// 用最近邻法对图像byte数组进行resize
///
///
///
///
public static byte[] ResizeNearestNeighbor(byte[] srcByte, Size srcSize, Size dstSize)
{
int bytesPerPixel = 1;
byte[] dstDataBuffer = new byte[dstSize.Width * dstSize.Height];
int dstDataLen = dstSize.Width * dstSize.Height * bytesPerPixel;
if (dstDataBuffer.Length < dstDataLen)
{
Array.Resize(ref dstDataBuffer, dstDataLen);
}
float scale_x = (float)srcSize.Width / dstSize.Width;
float scale_y = (float)srcSize.Height / dstSize.Height;
int dstStep = dstSize.Width * bytesPerPixel;
int srcStep = srcSize.Width * bytesPerPixel;
int ny, nx, nc;
int sy, sx;
for (ny = 0; ny < dstSize.Height; ++ny)
{
sy = Convert.ToInt32(Math.Floor(ny * scale_y));
sy = Math.Min(sy, srcSize.Height - 1);
for (nx = 0; nx < dstSize.Width; ++nx)
{
sx = Convert.ToInt32(Math.Floor(nx * scale_x));
sx = Math.Min(sx, srcSize.Width - 1);
for (nc = 0; nc < bytesPerPixel; nc++)
{
dstDataBuffer[ny * dstStep + nx * bytesPerPixel + nc] =
srcByte[sy * srcStep + sx * bytesPerPixel + nc];
}
}
}
return dstDataBuffer;
}
public static bool ByteEncoderSave(byte[] rawValues, Size size, string savePath)
{
EnumColorType _colorType = EnumColorType.Gray8;
var decodedPointer = Marshal.UnsafeAddrOfPinnedArrayElement(rawValues, 0);
AIReconstructor.StructImageInfo imageInfo = new AIReconstructor.StructImageInfo(size.Width, size.Height, _colorType, decodedPointer);
AIReconstructor.StructImwriteParam[] imwriteParams = new AIReconstructor.StructImwriteParam[1];
imwriteParams[0] = new AIReconstructor.StructImwriteParam(AIReconstructor.EnumImwriteFlags.JpegQuality, 80);
if (!AIReconstructor.ImDataSave(imageInfo, AIReconstructor.EnumImwriteExtension.Jpg,
imwriteParams, 1, savePath))
{
int errorMaxLen = 256;
StringBuilder errorMsg = new StringBuilder(errorMaxLen);
AIReconstructor.EnumCppCoreErrorCode errorCode = AIReconstructor.EnumCppCoreErrorCode.None;
AIReconstructor.GetErrorCodeAndMsg(ref errorCode, errorMsg, errorMaxLen);
throw new Exception("Failed at encoding model image datas, error code: "
+ errorCode.ToString() + " , details: " + errorMsg.ToString() + " .");
}
return true;
}
///
/// 根据3个三维坐标点返回其所在的平面
///
///
public byte[] GetMeasureImage(List pointList, out int width, out int height)
{
try
{
CefInputDatas inputData = new CefInputDatas();
inputData.PointsList = pointList;
if (!GetModelSlice(inputData))
{
LogHelper.ErrorLog("Server SliceHelper, GetMeasureImage GetModelSlice failed.");
width = 0;
height = 0;
return null;
}
var decodedPointer = Marshal.UnsafeAddrOfPinnedArrayElement(_generalModelSlice.SliceImageData, 0);
EnumColorType _colorType = EnumColorType.Gray8;
AI.Reconstruction.AIReconstructor.StructImageInfo srcImageInfo = new AI.Reconstruction.AIReconstructor.StructImageInfo(_generalModelSlice.SliceWidth,
_generalModelSlice.SliceHeight,
_colorType,
decodedPointer);
int bytesize = _generalModelSlice.SliceWidth * _generalModelSlice.SliceHeight;
AI.Reconstruction.AIReconstructor.StructImageInfo dstImageInfo = new AI.Reconstruction.AIReconstructor.StructImageInfo();
Get2DMeasureImage(srcImageInfo, bytesize, ref dstImageInfo);
int imageSize = dstImageInfo.Width * dstImageInfo.Height;
byte[] byteArray = new byte[imageSize];
Marshal.Copy(dstImageInfo.DataPointer, byteArray, 0, imageSize);
width = dstImageInfo.Width;
height = dstImageInfo.Height;
//手动释放内存
if (srcImageInfo.DataPointer != IntPtr.Zero)
{
srcImageInfo.DataPointer = IntPtr.Zero;
}
if (dstImageInfo.DataPointer != IntPtr.Zero)
{
dstImageInfo.DataPointer = IntPtr.Zero;
}
return byteArray;
}
catch (Exception e)
{
LogHelper.ErrorLog("Server SliceHelper, GetMeasureImage error," + e.Message + "," + e.StackTrace);
width = 0;
height = 0;
return null;
}
}
}
}