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; } } } }