123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005 |
- 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
- {
- /// <summary>
- /// 模型尺寸
- /// </summary>
- public struct ModelSize
- {
- public int ModelLengthX;
- public int ModelLengthY;
- public int ModelLengthZ;
- public int OneFacePixelsNum;
- }
- /// <summary>
- /// 模型切片类型
- /// </summary>
- public enum ModelSliceType
- {
- XEqual = 0,
- YEqual,
- ZEqual,
- Normal
- }
- /// <summary>
- /// 模型切面
- /// </summary>
- public struct ModelSlice
- {
- //切片像素点数据
- public byte[] SliceImageData;
- //图像的宽
- public int SliceWidth;
- //图像的高
- public int SliceHeight;
- }
- /// <summary>
- /// cefsharp的输入数据
- /// </summary>
- public struct CefInputDatas
- {
- // Point list
- public IList<Point3DF> PointsList;
- // Clip image name
- public string ClipImageName;
- }
- /// <summary>
- /// 共面的三个点
- /// </summary>
- public struct CoplanarPoints
- {
- private Point3DF _p1;
- private Point3DF _p2;
- private Point3DF _p3;
- /// <summary>
- /// 第一个点
- /// </summary>
- public Point3DF Point1 { get => _p1; set => _p1 = value; }
- /// <summary>
- /// 第二个点
- /// </summary>
- public Point3DF Point2 { get => _p2; set => _p2 = value; }
- /// <summary>
- /// 第三个点
- /// </summary>
- public Point3DF Point3 { get => _p3; set => _p3 = value; }
- /// <summary>
- /// 构造函数
- /// </summary>
- /// <param name="point1"></param>
- /// <param name="point2"></param>
- /// <param name="point3"></param>
- public CoplanarPoints(Point3DF point1, Point3DF point2, Point3DF point3)
- {
- _p1 = point1;
- _p2 = point2;
- _p3 = point3;
- }
- /// <summary>
- /// 空的CoplanarPoints
- /// </summary>
- public static readonly CoplanarPoints Empty = new CoplanarPoints(Point3DF.Empty, Point3DF.Empty, Point3DF.Empty);
- /// <summary>
- /// 判断是否相等
- /// </summary>
- /// <param name="one"></param>
- /// <param name="other"></param>
- /// <returns></returns>
- public static bool Equals(CoplanarPoints one, CoplanarPoints other)
- {
- return one.Point1 == other.Point1 && one.Point2 == other.Point2 && one.Point3 == other.Point3;
- }
- /// <summary>
- /// 判断是否相等
- /// </summary>
- /// <param name="left"></param>
- /// <param name="right"></param>
- /// <returns></returns>
- public static bool operator ==(CoplanarPoints left, CoplanarPoints right)
- {
- return Equals(left, right);
- }
- /// <summary>
- /// 判断是否相等
- /// </summary>
- /// <param name="left"></param>
- /// <param name="right"></param>
- /// <returns></returns>
- public static bool operator !=(CoplanarPoints left, CoplanarPoints right)
- {
- return !Equals(left, right);
- }
- }
- /// <summary>
- /// 获得切片图像的类
- /// </summary>
- 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<Point3DF> _endPointList3D;
- //切片的端点list,图像点坐标
- private List<Point2D> _endPointList2I;
- //切片的端点list,图像端点极坐标点坐标
- private readonly List<Point2DF> _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<Point3DF>();
- _endPointList2I = new List<Point2D>();
- _endPointList2DPolar = new List<Point2DF>();
- }
- public ModelSize GetModelSize()
- {
- return _modelSize;
- }
- public byte[][] GetModelData()
- {
- return _modelData;
- }
- /// <summary>
- /// 设置模型来源
- /// </summary>
- /// <param name="mdlFilePath">mdl file</param>
- /// <param name="width">model's width distance</param>
- /// <param name="height">model's height distance</param>
- /// <param name="depth">model's depth distance</param>
- /// <param name="scanDepth">scan depth</param>
- /// <returns>Whether set model source successfully</returns>
- 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;
- }
- }
- /// <summary>
- /// 解析模型
- /// </summary>
- 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);
- }
- }
- }
- /// <summary>
- /// 数组填充6个表面图像
- /// </summary>
- 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;
- }
- /// <summary>
- /// 释放资源
- /// </summary>
- /// <returns></returns>
- public void Release()
- {
- _generalModelSlice.SliceImageData = null;
- _resizedModelSlice.SliceImageData = null;
- _modelData = null;
- GC.Collect();
- }
- /// <summary>
- /// 获取模型最大的切面尺寸
- /// </summary>
- /// <returns></returns>
- private int GetMaxImageLength()
- {
- var lenList = new List<int> { _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);
- }
- /// <summary>
- /// 计算三维切片图像
- /// </summary>
- /// <param name="inputData">Input data include points >= 3 and clip category</param>
- /// <param name="savePath">Save path</param>
- /// <returns>True if calculate successfully.</returns>
- 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);
- }
- /// <summary>
- /// 计算模型切片
- /// </summary>
- /// <param name="inputData"></param>
- /// <returns></returns>
- 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;
- }
- }
- /// <summary>
- /// 判断输入数据是否合法,当前是否可以获取切片
- /// </summary>
- /// <param name="inputData"></param>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// 计算旋转矩阵
- /// </summary>
- /// <param name="endPointList3D"></param>
- /// <returns></returns>
- private CoordinateTransformation3D GetCoordinateTransformation()
- {
- //旋转后的图像坐标系,基于的三个世界点
- _planeBasic3DPoints = MathTools3D.GetOne2DPlaneBasicPoints(_endPointList3D);
- //计算_plane2DBasic3DPoints对应的二维点
- _planeBasic2DPoints = MathTools3D.ChangePlaneBasic3DPointTo2D(_planeBasic3DPoints);
- //根据坐标系基础点的三维坐标和二维坐标计算旋转矩阵
- return MathTools3D.GetCoordinateTransformationParameter(_planeBasic3DPoints, _planeBasic2DPoints);
- }
- /// <summary>
- /// 获得切片最小尺寸
- /// </summary>
- 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;
- }
- }
- /// <summary>
- /// 设置切面图像像素点的值
- /// </summary>
- /// <param name="sliceType"></param>
- /// <returns></returns>
- 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;
- }
- }
- /// <summary>
- /// 获得基础的三个点
- /// </summary>
- /// <param name="inputData"></param>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// 计算最终图像的大小
- /// </summary>
- /// <returns></returns>
- 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);
- }
- /// <summary>
- /// 计算切片端点的极坐标
- /// </summary>
- /// <param name="ratioWidth"></param>
- /// <param name="ratioHeight"></param>
- 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);
- }
- }
- /// <summary>
- /// x坐标相等时获得切片图像数据的函数
- /// </summary>
- /// <param name="point1"></param>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// y坐标相等时获得切片图像数据的函数
- /// </summary>
- /// <param name="yPos"></param>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// z坐标相等时获得切片图像数据的函数
- /// </summary>
- /// <param name="zPos"></param>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// XYZ坐标都不相等时获得切片图像数据的函数
- /// </summary>
- /// <param name="point1"></param>
- /// <param name="point2"></param>
- /// <param name="point3"></param>
- /// <returns></returns>
- 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;
- }
- }
- /// <summary>
- /// 计算切面图像点像素值,每一行
- /// </summary>
- /// <param name="start"></param>
- /// <param name="end"></param>
- 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}");
- }
- }
- /// <summary>
- /// 拷贝模型切片数据到目标byte数组
- /// </summary>
- 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;
- }
- }
- }
- /// <summary>
- /// 返回切面端点的三维坐标
- /// </summary>
- /// <returns></returns>
- public List<Point3DF> GetModelSliceEndPoint3D()
- {
- return _endPointList3D;
- }
- /// <summary>
- /// 返回切面端点的二维坐标
- /// </summary>
- /// <returns></returns>
- public List<Point2DF> GetModelSliceEndPointPolar2D()
- {
- return _endPointList2DPolar;
- }
- /// <summary>
- /// 保存切片图像到目标路径
- /// </summary>
- 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;
- }
- }
- /// <summary>
- /// 用最近邻法对图像byte数组进行resize
- /// </summary>
- /// <param name="dstWidth"></param>
- /// <param name="dstHeight"></param>
- /// <param name="dstDataBuffer"></param>
- 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;
- }
- /// <summary>
- /// 根据3个三维坐标点返回其所在的平面
- /// </summary>
- /// <param name="pointList"></param>
- public byte[] GetMeasureImage(List<Point3DF> 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;
- }
- }
- }
- }
|