123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851 |
- using WingServerCommon.Service;
- using WingInterfaceLibrary.Interface;
- using WingInterfaceLibrary.Request;
- using WingInterfaceLibrary.Enum;
- using WingServerCommon.Config;
- using WingServerCommon.Config.Parameters;
- using WingAIDiagnosisService.Carotid.Utilities;
- using Vinno.vCloud.Common.Vid2;
- using WingAIDiagnosisService.Manage;
- using WingAIDiagnosisService.Carotid;
- using Newtonsoft.Json;
- using AI.DiagSystem;
- using WingServerCommon.Log;
- using System.IO;
- using System;
- using System.Threading.Tasks;
- using System.Collections.Generic;
- using System.Linq;
- using AI.Common;
- using System.Threading;
- using AI.Common.Log;
- using SkiaSharp;
- using System.Net.Http;
- using System.Net;
- using WingInterfaceLibrary.Request.Storage;
- using WingInterfaceLibrary.Result.AIDiagnosis;
- using WingInterfaceLibrary.Request.AIDiagnosis;
- using WingInterfaceLibrary.DTO.Record;
- using WingInterfaceLibrary.DTO.Comment;
- using Emgu.CV;
- using Emgu.CV.CvEnum;
- using Emgu.CV.Structure;
- using System.Net.Http.Headers;
- using WingAIDiagnosisService.Common;
- namespace WingAIDiagnosisService.Service
- {
- /// <summary>
- /// AI诊断服务
- /// </summary>
- public partial class AIDiagnosisService : JsonRpcService, IAIDiagnosisService
- {
- private EnumPerformance _workerLevel = EnumPerformance.Medium;
- private int _batchImageSize = 16;
- private int _sleepTime = 400;
- private readonly string _tempFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DiagnosisTemp");
- private AIDiagSystem _diagSystem;
- private AILesionCompareUtils _lesionCompareUtil;
- private RecognizeCarotidType _recognizeCarotidType = new RecognizeCarotidType();
- //识别左右颈是否初始化成功
- private static bool _recognizeCarotidTypeCanBeUse = false;
- static HttpClient _httpClient = new HttpClient();
- private IAuthenticationService _authenticationService;
- private IStorageService _storageService;
- private readonly string _carotidName = "CarotidPlaqueDetect";
- /// <summary>
- /// Init service
- /// </summary>
- public override void Load(JsonRpcClientPool jsonRpcClientPool)
- {
- base.Load(jsonRpcClientPool);
- _authenticationService = GetProxy<IAuthenticationService>();
- _storageService = GetProxy<IStorageService>();
- _workerLevel = (EnumPerformance)ConfigurationManager.GetParammeter<IntParameter>("AI", "WorkerLevel").Value;
- _batchImageSize = ConfigurationManager.GetParammeter<IntParameter>("AI", "BatchImageSize").Value;
- _httpClient.Timeout = TimeSpan.FromMinutes(15);
- InitAISystem();
- //初始化识别左右颈
- _recognizeCarotidTypeCanBeUse = _recognizeCarotidType.Initialization();
- }
- private void InitAISystem()
- {
- var modeFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Networks");
- _diagSystem = new AIDiagSystem(_workerLevel, modeFilePath, EnumInferWorkName.Default, false, true, true);
- if (_diagSystem != null)
- {
- _diagSystem.NotifyError += AIdiagSystem_NotifyError;
- _diagSystem.NotifyLog += AIdiagSystem_NotifyLog;
- }
- _lesionCompareUtil = new AILesionCompareUtils();
- }
- /// <summary>
- /// 查询杏聆荟支持的AI模块
- /// </summary>
- /// <param name="request">查询杏聆荟支持的AI模块请求实体</param>
- /// <returns></returns>
- /// <show>false</show>
- public async Task<IList<string>> FindDiagnosisModulesAsync(TokenRequest request)
- {
- try
- {
- var moduleNames = AIDiagSystem.GetValidModuleNamesForVclound() ?? new List<EnumAIModuleNames>();
- var resultData = moduleNames.Select(x => x.ToString()).ToList();
- if (!resultData.Contains(_carotidName))
- {
- resultData.Remove("CarotidArtery");
- resultData.Add(_carotidName);
- }
- return await Task.FromResult(resultData.Distinct().ToList());
- }
- catch (Exception)
- {
- return new List<string>();
- }
- }
- /// <summary>
- /// 图像诊断
- /// </summary>
- /// <param name="request">图像诊断请求实体</param>
- /// <returns>图像诊断结果</returns>
- /// <show>false</show>
- public async Task<DiagnosisImageResult> DiagnosisImageAsync(DiagnosisImageRequest request)
- {
- try
- {
- var localFile = await DownloadAsync(request.FileToken);
- if (File.Exists(localFile))
- {
- if (_diagSystem == null)
- {
- InitAISystem();
- }
- using (var imageData = new VinnoImageData(localFile, OperationMode.Open))
- {
- if (DiagnosisHelper.IsCarotid(imageData))
- {
- if (imageData.ImageCount > DiagnosisHelper.CarotidMinImageCounts)
- {
- //颈动脉
- var result = await CarotidDiagnosis(imageData);
- var resultData = new DiagnosisImageResult()
- {
- DiagnosisOrgans = new List<DiagnosisOrganEnum>() { DiagnosisOrganEnum.CarotidArtery },
- CarotidResult = result
- };
- return resultData;
- }
- }
- else
- {
- //乳腺、肝脏
- var results = NormalDiagnosis(imageData);
- var diagnosisResults = results.Select(x => new AIDiagnosisPerImageModel(x.Key, x.Value)).ToList();
- var diagnosisResult = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AIDiagnosisPerImageDTO>>(Newtonsoft.Json.JsonConvert.SerializeObject(diagnosisResults));
- var resultData = new DiagnosisImageResult()
- {
- DiagnosisConclusion = (DiagnosisConclusionEnum)GetDiagnosisConclusion(diagnosisResults),
- DiagnosisResult = diagnosisResult,
- DiagnosisOrgans = GetDiagnosisOrgans(diagnosisResult),
- };
- return resultData;
- }
- }
- }
- }
- catch (Exception ex)
- {
- Logger.WriteLineWarn($"DiagnosisImageAsync err {ex}");
- }
- return new DiagnosisImageResult();
- }
- /// <summary>
- /// 生成AI报告
- /// </summary>
- /// <param name="request">生成AI报告请求实体</param>
- /// <returns></returns>
- /// <show>false</show>
- public async Task<DiagnosisReportResult> DiagnosisReportAsync(DiagnosisReportRequest request)
- {
- try
- {
- if (request.Organ == DiagnosisOrganEnum.CarotidArtery)
- {
- var result = await GetCarotidAIMeasureResult(request);
- return result;
- }
- else
- {
- var manager = await CreateDiagnosisManagerAsync(request);
- var reportPerImages = manager.GetReportResults();
- var diagnosisConclusion = GetDiagnosisConclusion(reportPerImages);
- var diagnosisResult = new List<DiagnosisPerImageDTO>();
- foreach (var item in reportPerImages)
- {
- var aiFileToken = await UploadFileAsync(item.AILocalImagePath, Path.GetFileName(item.AILocalImagePath));
- var perImageResult = Newtonsoft.Json.JsonConvert.DeserializeObject<DiagnosisPerImageDTO>(Newtonsoft.Json.JsonConvert.SerializeObject(item));
- perImageResult.RemedicalCode = item.RemedicalCode;
- perImageResult.DataType = (RemedicalFileDataTypeEnum)item.DataType;
- perImageResult.Pixel = item.Pixel;
- perImageResult.AIFileToken = aiFileToken;
- diagnosisResult.Add(perImageResult);
- }
- return new DiagnosisReportResult
- {
- DiagnosisConclusion = (DiagnosisConclusionEnum)diagnosisConclusion,
- DiagnosisResult = diagnosisResult,
- };
- }
- }
- catch (Exception ex)
- {
- Logger.WriteLineWarn($"AIService DiagnosisReport err, {ex}");
- }
- return new DiagnosisReportResult();
- }
- /// <summary>
- /// 获取颈动脉ai报告数据
- /// </summary>
- /// <param name="request">生成AI报告请求实体</param>
- /// <returns></returns>
- private async Task<DiagnosisReportResult> GetCarotidAIMeasureResult(DiagnosisReportRequest request)
- {
- var result = new DiagnosisReportResult()
- {
- DiagnosisConclusion = DiagnosisConclusionEnum.NoObviousLesion
- };
- var orderedExamDatas = request.RemedicalList.OrderByDescending(m => m.CarotidResult?.CarotidScanType).Where(m => m.CarotidResult?.MeasureImageFiles != null && m.CarotidResult.MeasureImageFiles.Count > 0);
- if (orderedExamDatas?.Count() > 0)
- {
- DiagnosisRemicalDTO leftData = null;
- //left
- var leftExamDatas = orderedExamDatas.Where(m => m.CarotidResult.CarotidScanType == CarotidScanTypeEnum.CarotidLeft);
- if (leftExamDatas.Any())
- {
- foreach (var leftItem in leftExamDatas)
- {
- if (string.IsNullOrEmpty(leftItem.CarotidResult.MeasureResult))
- {
- result.DiagnosisConclusion = DiagnosisConclusionEnum.Unrecognized;
- continue;
- }
- //leftItem.CarotidResult.MeasureResult = "{\"IntimaResult\":{\"IsSuccess\":true,\"AntIntima\":{\"IntimaThick\":0.0,\"IsSuccess\":false},\"PostIntima\":{\"IntimaThick\":0.75,\"IsSuccess\":true}},\"IsYImageSuccess\":false,\"PlaqueResult\":{\"PlaquePostion\":0,\"PlaqueCountType\":2,\"PlaqueType\":0,\"PlaqueWidth\":1.75,\"PlaqueHeight\":3.76,\"Stenosis\":10.37,\"IsSuccess\":true}}";
- var measureResult = JsonConvert.DeserializeObject<CarotidAIMeasureResult>(leftItem.CarotidResult.MeasureResult) ?? new CarotidAIMeasureResult();
- if (measureResult.PlaqueResult?.PlaqueCountType != Carotid.Utilities.DetectPlaque.PlaqueCountType.NoPlaque)
- {
- leftData = leftItem;
- result.DiagnosisConclusion = DiagnosisConclusionEnum.Other;
- break;
- }
- }
- if (leftData == null)
- {
- leftData = leftExamDatas.First();
- }
- }
- if (leftData != null)
- {
- result.CarotidResult.Add(leftData);
- }
- //right
- float intimaThickStandard = 1.0f;
- DiagnosisRemicalDTO rightData = null;
- var rightExamDatas = orderedExamDatas.Where(m => m.CarotidResult.CarotidScanType == CarotidScanTypeEnum.CarotidRight);
- if (rightExamDatas.Any())
- {
- foreach (var rightItem in rightExamDatas)
- {
- if (string.IsNullOrEmpty(rightItem.CarotidResult.MeasureResult))
- {
- result.DiagnosisConclusion = DiagnosisConclusionEnum.Unrecognized;
- continue;
- }
- //rightItem.CarotidResult.MeasureResult = "{\"IntimaResult\":{\"IsSuccess\":true,\"AntIntima\":{\"IntimaThick\":0.0,\"IsSuccess\":false},\"PostIntima\":{\"IntimaThick\":0.75,\"IsSuccess\":true}},\"IsYImageSuccess\":false,\"PlaqueResult\":{\"PlaquePostion\":0,\"PlaqueCountType\":2,\"PlaqueType\":0,\"PlaqueWidth\":1.75,\"PlaqueHeight\":3.76,\"Stenosis\":10.37,\"IsSuccess\":true}}";
- var measureResult = JsonConvert.DeserializeObject<CarotidAIMeasureResult>(rightItem.CarotidResult.MeasureResult) ?? new CarotidAIMeasureResult();
- if (measureResult.IntimaResult?.PostIntima?.IntimaThick > intimaThickStandard)
- {
- rightData = rightItem;
- result.DiagnosisConclusion = DiagnosisConclusionEnum.Other;
- break;
- }
- }
- if (rightData == null)
- {
- rightData = rightExamDatas.First();
- }
- }
- if (rightData != null)
- {
- result.CarotidResult.Add(rightData);
- }
- Logger.WriteLineInfo($"AIDiagnosisService package carotidAIMeasureResult finished, CarotidLeftRemedicalCode:{leftData?.RemedicalCode}, CarotidLeft:{leftData?.CarotidResult?.MeasureResult}, CarotidRightRemedicalCode:{rightData?.RemedicalCode}, CarotidRight:" + rightData?.CarotidResult?.MeasureResult);
- }
- return result;
- }
- private async Task<BaseDiagnosis> CreateDiagnosisManagerAsync(DiagnosisReportRequest request)
- {
- var recordResults = new List<DiagnosisPerImageModel>();
- foreach (var remedical in request.RemedicalList)
- {
- foreach (var perImage in remedical.DiagnosisResult)
- {
- var localFile = await DownloadAsync(remedical.FileToken);
- if (File.Exists((localFile)))
- {
- var diagnosisPerImage = new DiagnosisPerImageModel();
- diagnosisPerImage.RemedicalCode = remedical.RemedicalCode;
- diagnosisPerImage.DataType = (WingAIDiagnosisService.Manage.DataType)remedical.DataType;
- diagnosisPerImage.LocalVidPath = localFile;
- diagnosisPerImage.Index = perImage.Index;
- diagnosisPerImage.PriorityScore = perImage.PriorityScore;
- var diagnosisResults = Newtonsoft.Json.JsonConvert.DeserializeObject<List<WingAIDiagnosisService.Manage.AIDiagnosisResultPerOrgan>>(Newtonsoft.Json.JsonConvert.SerializeObject(perImage.DiagResultsForEachOrgan));
- diagnosisPerImage.DiagResultsForEachOrgan = diagnosisResults;
- recordResults.Add(diagnosisPerImage);
- }
- }
- }
- switch (request.Organ)
- {
- case DiagnosisOrganEnum.Breast:
- return new BreastDiagnosis(recordResults, request.Organ);
- case DiagnosisOrganEnum.Liver:
- return new LiverDiagnosis(recordResults, request.Organ);
- default:
- throw new Exception($"not support organ type:{request.Organ.ToString()}");
- }
- }
- private async Task<CarotidResultDTO> CarotidDiagnosis(VinnoImageData imageData)
- {
- var resampleInputData = new ResampleInputData();
- resampleInputData.SurfaceFilePath = DiagnosisHelper.GetCacheFilePath(DiagnosisHelper.SurfaceFileSuffix);
- resampleInputData.MdlFilePath = DiagnosisHelper.GetCacheFilePath(DiagnosisHelper.ModelFileSuffix);
- resampleInputData.MdlZipFilePath = DiagnosisHelper.GetCacheFilePath(DiagnosisHelper.ZipFileSuffix);
- resampleInputData.BaseAIImagePath = DiagnosisHelper.GetCacheFilePath(DiagnosisHelper.JPGFileSuffix);
- resampleInputData.PlaqueAIImagePath = DiagnosisHelper.GetCacheFilePath(DiagnosisHelper.JPGFileSuffix);
- resampleInputData.YShapeAIImagePath = DiagnosisHelper.GetCacheFilePath(DiagnosisHelper.JPGFileSuffix);
- var resampleResult = TryResample(imageData, resampleInputData);
- if (resampleResult.ResampleErrorCode == ResampleErrorCode.Success)
- {
- var carotidAIImageTokens = new List<CarotidAIImage>();
- if (resampleResult.CarotidAIMeasureResult.IsYImageSuccess)
- {
- var fileUrl = await UploadFileAsync(resampleInputData.YShapeAIImagePath, Path.GetFileName(resampleInputData.YShapeAIImagePath));
- if (!string.IsNullOrWhiteSpace(fileUrl))
- {
- carotidAIImageTokens.Add(new CarotidAIImage() { AIImageToken = fileUrl, AIImageType = CarotidAIImageType.YShape });
- }
- File.Delete(resampleInputData.YShapeAIImagePath);
- }
- if (resampleResult.CarotidAIMeasureResult.IntimaResult.IsSuccess)
- {
- var fileUrl = await UploadFileAsync(resampleInputData.BaseAIImagePath, Path.GetFileName(resampleInputData.BaseAIImagePath));
- if (!string.IsNullOrWhiteSpace(fileUrl))
- {
- carotidAIImageTokens.Add(new CarotidAIImage() { AIImageToken = fileUrl, AIImageType = CarotidAIImageType.Base });
- }
- File.Delete(resampleInputData.BaseAIImagePath);
- }
- if (resampleResult.CarotidAIMeasureResult.PlaqueResult.IsSuccess && resampleResult.CarotidAIMeasureResult.PlaqueResult.PlaqueCountType != WingAIDiagnosisService.Carotid.Utilities.DetectPlaque.PlaqueCountType.NoPlaque)
- {
- var fileUrl = await UploadFileAsync(resampleInputData.PlaqueAIImagePath, Path.GetFileName(resampleInputData.PlaqueAIImagePath));
- if (!string.IsNullOrWhiteSpace(fileUrl))
- {
- carotidAIImageTokens.Add(new CarotidAIImage() { AIImageToken = fileUrl, AIImageType = CarotidAIImageType.Plaque });
- }
- File.Delete(resampleInputData.PlaqueAIImagePath);
- }
- var surfaceImageList = new List<string>();
- long surfaceFileSize=0;
- var cdnSurfaceFile="";
- if (!string.IsNullOrWhiteSpace(resampleInputData.SurfaceFilePath) && File.Exists(resampleInputData.SurfaceFilePath))
- {
- surfaceImageList = await SurfaceFile(resampleInputData.SurfaceFilePath);
- var surfaceFileTuple = await UploadFileTupleAsync(resampleInputData.SurfaceFilePath, Path.GetFileName(resampleInputData.SurfaceFilePath));
- surfaceFileSize=surfaceFileTuple.Item2;
- File.Delete(resampleInputData.SurfaceFilePath);
- resampleInputData.SurfaceFilePath = surfaceFileTuple.Item1;
- cdnSurfaceFile= surfaceFileTuple.Item1.ToUrlToken();//ToCDN
- }
- long mdlFileFileSize=0;
- var cdnMdlFile="";
- if (!string.IsNullOrWhiteSpace(resampleInputData.MdlFilePath) && File.Exists(resampleInputData.MdlFilePath))
- {
- var mdlFileTuple = await UploadFileTupleAsync(resampleInputData.MdlFilePath, Path.GetFileName(resampleInputData.MdlFilePath));
- mdlFileFileSize=mdlFileTuple.Item2;
- File.Delete(resampleInputData.MdlFilePath);
- resampleInputData.MdlFilePath = mdlFileTuple.Item1;
- cdnMdlFile= mdlFileTuple.Item1.ToUrlToken();//ToCDN
- }
- var result = new CarotidResultDTO
- {
- CarotidScanType = (CarotidScanTypeEnum)resampleInputData.ScanType,
- CarotidScanDirection = (CarotidScanDirectionEnum)resampleInputData.CarotidScanDirection,
- SurfaceFile = resampleInputData.SurfaceFilePath,
- SurfaceFileSize=surfaceFileSize,
- CDNSurfaceFile=cdnSurfaceFile,
- MdlFileSize=mdlFileFileSize,
- MdlFile = resampleInputData.MdlFilePath,
- CDNMdlFile=cdnMdlFile,
- MeasureImageFiles = carotidAIImageTokens.Select(x => new MeasureImageFileDTO { ImageType = (CarotidAIImageTypeEnum)x.AIImageType, ImageFile = x.AIImageToken }).ToList(),
- MeasureResult = JsonConvert.SerializeObject(resampleResult.CarotidAIMeasureResult),
- SurfaceImageList = surfaceImageList,
- };
- return result;
- }
- return null;
- }
- private ResampleResult TryResample(VinnoImageData vinnoImageData, ResampleInputData resampleInputData)
- {
- float scanDistance = 7;
- ResampleResult resampleResult = new ResampleResult(ResampleErrorCode.Fail);
- var vinnoExtendedData = VinnoCarotidExtendedData.FromBytes(vinnoImageData.ExtendedData);
- CarotidScanType scanType = CarotidScanType.CarotidLeft;
- CarotidScanDirection direction = CarotidScanDirection.TopToBottom;
- if (vinnoExtendedData != null)
- {
- // Should be 6~9cm normally.
- //scanDistance = vinnoExtendedData.ScanDistance;
- scanType = vinnoExtendedData.CarotidType == CarotidType.Left ? CarotidScanType.CarotidLeft : CarotidScanType.CarotidRight;
- direction = vinnoExtendedData.CarotidDirection == CarotidDirection.BottomToTop ? CarotidScanDirection.BottomToTop
- : CarotidScanDirection.TopToBottom;
- }
- else
- {
- //This is a walkaround : vid's first frame is black image or depth coordinate is not in the right place.
- var middleCount = vinnoImageData.ImageCount / 2;
- var vinnoImage = vinnoImageData.GetImage(middleCount);
- var imageBuffer = vinnoImage.ImageData;
- if (_recognizeCarotidTypeCanBeUse)
- {
- //转成彩色图像
- using var img = new Mat();
- CvInvoke.Imdecode(imageBuffer, ImreadModes.Color, img);
- using var image = img.ToImage<Bgr, byte>();
- //识别左右颈信息
- scanType = _recognizeCarotidType.RecognizeType(image);
- }
- }
- resampleInputData.ScanDistance = scanDistance;
- resampleInputData.ScanType = scanType;
- resampleInputData.CarotidScanDirection = direction;
- resampleResult = ResampleModel.Instance.Resample(vinnoImageData, resampleInputData, _workerLevel);
- return resampleResult;
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="filePath"></param>
- private async Task<List<string>> SurfaceFile(string filePath)
- {
- var fileUrls = new List<string>();
- using (var stream = new FileStream(filePath, FileMode.Open))
- {
- var reader = new Carotid3DStreamReader(stream);
- var width = reader.ReadInt();
- var height = reader.ReadInt();
- var depth = reader.ReadInt();
- var physicalData = VinnoCarotid3DPhysicalData.FromBytes(reader.ReadBytes());
- var imageCount = reader.ReadInt();
- var fileName = $"{Guid.NewGuid():N}";
- for (var i = 0; i < imageCount; i++)
- {
- var readBytes = reader.ReadBytes();
- if (readBytes.Any())
- {
- using var img = new Mat();
- CvInvoke.Imdecode(readBytes, ImreadModes.Color, img);
- var buf = new Emgu.CV.Util.VectorOfByte();
- using var image = img.ToImage<Gray, byte>();
- CvInvoke.Imencode(".jpg", image, buf, new KeyValuePair<ImwriteFlags, int>(ImwriteFlags.JpegQuality, 80));
- var jpgByte = buf.ToArray();
- var localPath = Path.Combine(_tempFolder, $"{fileName}_{i + 1}.jpg");
- File.WriteAllBytes(localPath, jpgByte);
- var fileUrl = await UploadFileAsync(localPath, Path.GetFileName(localPath));
- fileUrls.Add(fileUrl);
- File.Delete(localPath);
- }
- }
- }
- return fileUrls;
- }
- private SKBitmap CreateBitmap(VinnoImage vinnoImage)
- {
- try
- {
- return SKBitmap.Decode(vinnoImage.ImageData);
- }
- catch (Exception ex)
- {
- Logger.WriteLineError($"Create skbitmap by VinnoImage error:{ex}");
- }
- return null;
- }
- private EnumColorType MapTo(SKColorType sKColor)
- {
- switch (sKColor)
- {
- case SKColorType.Rgba8888:
- return EnumColorType.Rgba;
- case SKColorType.Rgb888x:
- return EnumColorType.Rgba;
- case SKColorType.Bgra8888:
- return EnumColorType.Bgra;
- case SKColorType.Gray8:
- return EnumColorType.Gray8;
- }
- throw new Exception($"AIService not support color type:{sKColor}");
- }
- private void AIdiagSystem_NotifyError(object sender, ErrorEventArgs e)
- {
- Logger.WriteLineError("AIdiagSystem_NotifyError:" + e.GetException());
- }
- private void AIdiagSystem_NotifyLog(object sender, LogEventArgs e)
- {
- if (e != null && !string.IsNullOrEmpty(e.Msg))
- {
- switch (e.LogType)
- {
- case EnumLogType.InfoLog:
- Logger.WriteLineInfo($"AIdiagSystem_NotifyLog:{e.Msg}");
- break;
- case EnumLogType.ErrorLog:
- Logger.WriteLineError($"AIdiagSystem_NotifyLog:{e.Msg}");
- break;
- case EnumLogType.WarnLog:
- Logger.WriteLineWarn($"AIdiagSystem_NotifyLog:{e.Msg}");
- break;
- case EnumLogType.FatalLog:
- Logger.WriteLineError($"AIdiagSystem_NotifyLog:{e.Msg}");
- break;
- default:
- Logger.WriteLineInfo(e.Msg);
- break;
- }
- }
- }
- private DiagnosisConclusion GetDiagnosisConclusion<T>(List<T> results) where T : AIDiagnosisPerImageModel
- {
- var diagnosisConclusions = new List<DiagnosisConclusion>();
- foreach (var imageResult in results)
- {
- foreach (var diagnosisResult in imageResult.DiagResultsForEachOrgan)
- {
- var benignLabels = new List<int>();
- var malignantLabels = new List<int>();
- if (diagnosisResult.Organ == DiagnosisOrganEnum.Breast)
- {
- benignLabels = new List<int> { 1, 2, 3 };
- malignantLabels = new List<int> { 4, 5, 6, 7 };
- }
- else if (diagnosisResult.Organ == DiagnosisOrganEnum.Liver)
- {
- benignLabels = new List<int> { 1, 2, 3, 5, 6, 7, 8 };
- malignantLabels = new List<int> { 4 };
- }
- var labels = diagnosisResult.DetectedObjects.Select(x => x.Label);
- if (labels.Contains(0))
- {
- diagnosisConclusions.Add(DiagnosisConclusion.NoObviousLesion);
- }
- if (labels.Intersect(benignLabels).Any())
- {
- diagnosisConclusions.Add(DiagnosisConclusion.Benign);
- }
- if (labels.Intersect(malignantLabels).Any())
- {
- diagnosisConclusions.Add(DiagnosisConclusion.Malignant);
- }
- }
- }
- var containsBenign = diagnosisConclusions.Contains(DiagnosisConclusion.Benign);
- var containsMalignant = diagnosisConclusions.Contains(DiagnosisConclusion.Malignant);
- var containsNoObviousLesion = diagnosisConclusions.Contains(DiagnosisConclusion.NoObviousLesion);
- if (containsBenign && containsMalignant)
- {
- return DiagnosisConclusion.BenignAndMalignant;
- }
- else if (containsBenign)
- {
- return DiagnosisConclusion.Benign;
- }
- else if (containsMalignant)
- {
- return DiagnosisConclusion.Malignant;
- }
- else if (containsNoObviousLesion)
- {
- return DiagnosisConclusion.NoObviousLesion;
- }
- else
- {
- return DiagnosisConclusion.Unrecognized;
- }
- }
- private List<DiagnosisOrganEnum> GetDiagnosisOrgans(List<AIDiagnosisPerImageDTO> results)
- {
- var diagnosisOrgans = new List<DiagnosisOrganEnum>();
- foreach (var imageResult in results)
- {
- foreach (var diagnosisResult in imageResult.DiagResultsForEachOrgan)
- {
- var organName = Enum.GetName(typeof(DiagnosisOrganEnum), (int)diagnosisResult.Organ);
- if (!string.IsNullOrWhiteSpace(organName) && diagnosisResult.Organ != DiagnosisOrganEnum.Null && diagnosisResult.DetectedObjects?.Any() == true)
- {
- diagnosisOrgans.Add((DiagnosisOrganEnum)diagnosisResult.Organ);
- }
- }
- }
- return diagnosisOrgans.Distinct().ToList();
- }
- private Dictionary<int, AIDiagResultPerImg> NormalDiagnosis(VinnoImageData imageData)
- {
- var images = new List<RawImage>();
- var results = new Dictionary<int, AIDiagResultPerImg>();
- try
- {
- var totalCount = imageData.ImageCount;
- for (var i = 0; i < totalCount; i++)
- {
- var image = imageData.GetImage(i);
- var bitmap = CreateBitmap(image);
- if (bitmap != null)
- {
- images.Add(new RawImage(bitmap.Bytes, bitmap.Width, bitmap.Height, MapTo(bitmap.ColorType)));
- }
- }
- if (images.Count > 0)
- {
- var excuteCount = images.Count / _batchImageSize;
- var remainderCount = images.Count % _batchImageSize;
- var diagId = _diagSystem.StartEvalutationOfMultipleImageBatches(images.Count);
- for (var j = 0; j < excuteCount; j++)
- {
- var excuteImages = images.GetRange(j * _batchImageSize, _batchImageSize);
- _diagSystem.PushOneBatchOfImagesAsync(diagId, excuteImages);
- Thread.Sleep(_sleepTime);
- }
- if (remainderCount > 0)
- {
- var excuteImages = images.GetRange(excuteCount * _batchImageSize, remainderCount);
- _diagSystem.PushOneBatchOfImagesAsync(diagId, excuteImages);
- }
- results = _diagSystem.GetEvaluationsOfPushedMultipleImageBatches(diagId);
- }
- }
- catch (Exception ex)
- {
- Logger.WriteLineWarn($"AIService NormalDiagnosis err, {ex}");
- }
- finally
- {
- foreach (var image in images)
- {
- image?.Dispose();
- }
- }
- return results;
- }
- /// <summary>下载文件</summary>
- /// <param name="fileUrl"></param>
- /// <returns></returns>
- private async Task<string> DownloadAsync(string fileUrl)
- {
- try
- {
- if (string.IsNullOrEmpty(fileUrl))
- {
- return string.Empty;
- }
- if (!Directory.Exists(_tempFolder))
- {
- Directory.CreateDirectory(_tempFolder);
- }
- var fileName = Path.GetFileName(fileUrl);
- var tempFile = Path.Combine(_tempFolder, fileName);
- if (File.Exists(tempFile))
- {
- return tempFile;
- }
- long fileSize = 0;
- using (var request = new HttpRequestMessage())
- {
- request.RequestUri = new Uri(fileUrl);
- request.Method = HttpMethod.Get;
- var response = await _httpClient.SendAsync(request);
- if (response != null && response.StatusCode == HttpStatusCode.OK)
- {
- var contentLength = response.Content.Headers.ContentLength;
- fileSize = contentLength == null ? 0 : contentLength.Value;
- }
- }
- if (fileSize <= 0)
- {
- throw new NotSupportedException($"fileSize is {fileSize}");
- }
- byte[] bytes = await _httpClient.GetByteArrayAsync(fileUrl);
- File.WriteAllBytes(tempFile, bytes);
- return tempFile;
- }
- catch (Exception ex)
- {
- Logger.WriteLineWarn($"DiagnosisService download file err, url: {fileUrl}, {ex}");
- }
- finally
- {
- //Logger.WriteLineInfo($"download file:{fileUrl}");
- }
- return string.Empty;
- }
- /// <summary>
- /// 上传文件
- /// </summary>
- /// <param name="filePath"></param>
- /// <param name="fileName"></param>
- /// <returns></returns>
- private async Task<string> UploadFileAsync(string filePath, string fileName)
- {
- var fileToken = "";
- using (var fileStream = new FileStream(filePath, FileMode.Open))
- {
- var size = fileStream.Length;
- byte[] buffer = new byte[fileStream.Length];
- fileStream.Read(buffer, 0, buffer.Length);
- fileToken = await DoUploadFile(fileName, buffer);
- }
- return fileToken;
- }
- /// <summary>
- /// 上传文件
- /// </summary>
- /// <param name="filePath"></param>
- /// <param name="fileName"></param>
- /// <returns></returns>
- private async Task<Tuple<string, long>> UploadFileTupleAsync(string filePath, string fileName)
- {
- var fileToken = "";
- long size = 0;
- using (var fileStream = new FileStream(filePath, FileMode.Open))
- {
- size = fileStream.Length;
- byte[] buffer = new byte[fileStream.Length];
- fileStream.Read(buffer, 0, buffer.Length);
- fileToken = await DoUploadFile(fileName, buffer);
- }
- return new Tuple<string, long>(fileToken, size);
- }
- /// <summary>
- /// 上传文件
- /// </summary>
- /// <param name="fileName"></param>
- /// <param name="fileData"></param>
- /// <returns></returns>
- async Task<string> DoUploadFile(string fileName, byte[] fileData)
- {
- var requestHeads = new Dictionary<string, string>();
- var defaultToken = await _authenticationService.GetServerDefaultTokenAsync();
- var authorizationRet = await _storageService.GetAuthorizationAsync(
- new FileServiceRequest
- {
- Token = defaultToken,
- FileName = fileName,
- });
- requestHeads.Add("Authorization", authorizationRet.Authorization);
- var fileUrl = authorizationRet.StorageUrl;
- Logger.WriteLineInfo($"DoUploadFile fileUrl:{fileUrl}");
- using (var request = new HttpRequestMessage())
- {
- var fileExtension = Path.GetExtension(fileName);
- var mimeType = FileHelper.GetMimeType(fileExtension);
- var contentType = MediaTypeHeaderValue.Parse(mimeType);
- using (UploadContent content = new UploadContent(fileData, contentType))
- {
- request.RequestUri = new Uri(fileUrl);
- request.Method = HttpMethod.Put;
- request.Content = content;
- foreach (var head in requestHeads)
- {
- request.Headers.TryAddWithoutValidation(head.Key, head.Value);
- }
- var result = await ExecuteRequest(request);
- if (!result)
- {
- throw new Exception("Upload file failed!");
- }
- }
- }
- return fileUrl;
- }
- private UploadFileTypeEnum GetUploadFileType(string fileName)
- {
- if (fileName.EndsWith(".vid"))
- {
- return UploadFileTypeEnum.VID;
- }
- else if (fileName.EndsWith(".jpg"))
- {
- return UploadFileTypeEnum.JPG;
- }
- else
- {
- return UploadFileTypeEnum.MP4;
- }
- }
- /// <summary>
- /// 执行请求
- /// </summary>
- /// <param name="httpRequestMessage"></param>
- /// <typeparam name="T"></typeparam>
- /// <returns></returns>
- public async Task<bool> ExecuteRequest(HttpRequestMessage httpRequestMessage)
- {
- try
- {
- var response = await _httpClient.SendAsync(httpRequestMessage);
- if (response != null && response.StatusCode == HttpStatusCode.OK)
- {
- return true;
- }
- return false;
- }
- catch (Exception ex)
- {
- throw ex;
- }
- }
- }
- }
|