多帧合并然后遮盖
parent
3179fca112
commit
d38ce06f90
|
|
@ -1073,6 +1073,13 @@ public class OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options,
|
||||||
{
|
{
|
||||||
BackBatchGetToken();
|
BackBatchGetToken();
|
||||||
|
|
||||||
|
// 确保目标目录存在
|
||||||
|
string directory = Path.GetDirectoryName(localFilePath);
|
||||||
|
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(directory);
|
||||||
|
}
|
||||||
|
|
||||||
ossRelativePath = ossRelativePath.TrimStart('/');
|
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -15367,7 +15367,7 @@
|
||||||
<param name="_userInfo"></param>
|
<param name="_userInfo"></param>
|
||||||
<param name="_localizer"></param>
|
<param name="_localizer"></param>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Core.Application.Service.SegmentationService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Segmentation},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SegmentBinding},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTask},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableAnswerRowInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Segment},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionTrial},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer)">
|
<member name="M:IRaCIS.Core.Application.Service.SegmentationService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Segmentation},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SegmentBinding},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTask},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableAnswerRowInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Segment},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SegmentationVersion},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer)">
|
||||||
<summary>
|
<summary>
|
||||||
分割
|
分割
|
||||||
</summary>
|
</summary>
|
||||||
|
|
@ -15390,6 +15390,27 @@
|
||||||
<param name="addOrEditSegmentation"></param>
|
<param name="addOrEditSegmentation"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.Application.Service.SegmentationService.SaveSegmentationVersionAsync(System.Guid)">
|
||||||
|
<summary>
|
||||||
|
添加新版本
|
||||||
|
</summary>
|
||||||
|
<param name="segmentationId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.Application.Service.SegmentationService.GetSegmentationVersionList(IRaCIS.Core.Application.ViewModel.SegmentationVersionQuery)">
|
||||||
|
<summary>
|
||||||
|
获取分割组历史版本
|
||||||
|
</summary>
|
||||||
|
<param name="inQuery"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.Application.Service.SegmentationService.RestoreSegmentationVersion(IRaCIS.Core.Application.ViewModel.RestoreSegmentationVersionInDto)">
|
||||||
|
<summary>
|
||||||
|
恢复分割组历史版本
|
||||||
|
</summary>
|
||||||
|
<param name="inDto"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
<member name="M:IRaCIS.Core.Application.Service.SegmentationService.DeleteSegmentation(System.Guid)">
|
<member name="M:IRaCIS.Core.Application.Service.SegmentationService.DeleteSegmentation(System.Guid)">
|
||||||
<summary>
|
<summary>
|
||||||
删除分割组
|
删除分割组
|
||||||
|
|
@ -18103,6 +18124,11 @@
|
||||||
是否保存
|
是否保存
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="P:IRaCIS.Core.Application.ViewModel.SegmentationAddOrEdit.FileSize">
|
||||||
|
<summary>
|
||||||
|
文件大小,单位字节
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="P:IRaCIS.Core.Application.ViewModel.SegmentBindingView.IsLock">
|
<member name="P:IRaCIS.Core.Application.ViewModel.SegmentBindingView.IsLock">
|
||||||
<summary>
|
<summary>
|
||||||
是否锁定
|
是否锁定
|
||||||
|
|
|
||||||
|
|
@ -118,9 +118,9 @@ namespace IRaCIS.Core.Application.Service
|
||||||
{
|
{
|
||||||
var downloadJobs = new List<Func<Task>>();
|
var downloadJobs = new List<Func<Task>>();
|
||||||
|
|
||||||
var rootFolder = @"E:\DownloadImage";
|
//var rootFolder = @"E:\DownloadImage";
|
||||||
|
|
||||||
//var rootFolder = FileStoreHelper.GetDonwnloadImageFolder(_hostEnvironment);
|
var rootFolder = FileStoreHelper.GetDonwnloadImageFolder(_hostEnvironment);
|
||||||
|
|
||||||
// 获取无效字符(系统定义的)
|
// 获取无效字符(系统定义的)
|
||||||
string invalidChars = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
|
string invalidChars = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
|
||||||
|
|
|
||||||
|
|
@ -741,6 +741,7 @@ namespace IRaCIS.Core.Application.Contracts
|
||||||
|
|
||||||
public class DownloadDicomInstanceDto
|
public class DownloadDicomInstanceDto
|
||||||
{
|
{
|
||||||
|
public int NumberOfFrames { get; set; }
|
||||||
public bool IsEncapsulated { get; set; }
|
public bool IsEncapsulated { get; set; }
|
||||||
public Guid InstanceId { get; set; }
|
public Guid InstanceId { get; set; }
|
||||||
public string FileName { get; set; }
|
public string FileName { get; set; }
|
||||||
|
|
@ -1171,4 +1172,6 @@ namespace IRaCIS.Core.Application.Contracts
|
||||||
|
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,21 @@
|
||||||
using IRaCIS.Core.Application.Contracts;
|
using FellowOakDicom;
|
||||||
|
using FellowOakDicom.Imaging;
|
||||||
|
using FellowOakDicom.IO.Buffer;
|
||||||
|
using IRaCIS.Core.Application.Contracts;
|
||||||
using IRaCIS.Core.Application.Filter;
|
using IRaCIS.Core.Application.Filter;
|
||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
using IRaCIS.Core.Application.Service.ImageAndDoc.DTO;
|
using IRaCIS.Core.Application.Service.ImageAndDoc.DTO;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using IRaCIS.Core.Infrastructure;
|
using IRaCIS.Core.Infrastructure;
|
||||||
|
using MathNet.Numerics;
|
||||||
using Medallion.Threading;
|
using Medallion.Threading;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
using NetTopologySuite.Algorithm;
|
using NetTopologySuite.Algorithm;
|
||||||
|
using SharpCompress.Common;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using ZiggyCreatures.Caching.Fusion;
|
using ZiggyCreatures.Caching.Fusion;
|
||||||
|
|
@ -29,7 +37,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||||
IRepository<SystemAnonymization> _systemAnonymizationRepository,
|
IRepository<SystemAnonymization> _systemAnonymizationRepository,
|
||||||
IRepository<NoneDicomStudy> _noneDicomStudyRepository,
|
IRepository<NoneDicomStudy> _noneDicomStudyRepository,
|
||||||
IDistributedLockProvider _distributedLockProvider, IOSSService _oSSService,
|
IDistributedLockProvider _distributedLockProvider, IOSSService _oSSService,
|
||||||
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, IStudyService
|
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache, IWebHostEnvironment _hostEnvironment) : BaseService, IStudyService
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -69,6 +77,54 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static async Task<bool> TryWriteMergedDicomAsync(
|
||||||
|
Func<Task<Stream>> sourceFactory,
|
||||||
|
Stream output)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await using var source = await sourceFactory();
|
||||||
|
// 如果你是从 stream 打开
|
||||||
|
var dicomFile = await DicomFile.OpenAsync(source);
|
||||||
|
|
||||||
|
//获取像素是否为封装形式
|
||||||
|
var syntax = dicomFile.Dataset.InternalTransferSyntax;
|
||||||
|
|
||||||
|
//对于封装像素的文件做转换
|
||||||
|
if (syntax.IsEncapsulated)
|
||||||
|
{
|
||||||
|
// 获取 Pixel Data 标签
|
||||||
|
var pixelData = DicomPixelData.Create(dicomFile.Dataset);
|
||||||
|
|
||||||
|
// 创建一个新的片段序列
|
||||||
|
var newFragments = new DicomOtherByteFragment(DicomTag.PixelData);
|
||||||
|
// 获取每帧数据并封装为单独的片段
|
||||||
|
for (int n = 0; n < pixelData.NumberOfFrames; n++)
|
||||||
|
{
|
||||||
|
var frameData = pixelData.GetFrame(n);
|
||||||
|
newFragments.Fragments.Add(new MemoryByteBuffer(frameData.Data));
|
||||||
|
}
|
||||||
|
|
||||||
|
var frag = dicomFile.Dataset.GetDicomItem<DicomOtherByteFragment>(DicomTag.PixelData);
|
||||||
|
|
||||||
|
var originOffsetTable = frag?.OffsetTable;
|
||||||
|
|
||||||
|
newFragments.OffsetTable.AddRange(originOffsetTable?.ToArray());
|
||||||
|
// 替换原有的片段序列
|
||||||
|
dicomFile.Dataset.AddOrUpdate(newFragments);
|
||||||
|
}
|
||||||
|
|
||||||
|
await dicomFile.SaveAsync(output);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// 只记录,不传播
|
||||||
|
Log.Logger.Warning($"TryWriteMergedDicomAsync failed: {ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标注遮盖影像 路径后面加了.MaskImage 就是遮盖的新路径
|
/// 标注遮盖影像 路径后面加了.MaskImage 就是遮盖的新路径
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -81,16 +137,16 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var idPathList = new List<InstanceIdPath>();
|
var idPathList = new List<DownloadDicomInstanceDto>();
|
||||||
|
|
||||||
if (inCommand.SeriesId == null && inCommand.InstanceIdList != null)
|
if (inCommand.SeriesId == null && inCommand.InstanceIdList != null)
|
||||||
{
|
{
|
||||||
idPathList = await _dicomInstanceRepository.Where(t => inCommand.InstanceIdList.Contains(t.Id)).Select(t => new InstanceIdPath { Id = t.Id, Path = t.Path }).ToListAsync();
|
idPathList = await _dicomInstanceRepository.Where(t => inCommand.InstanceIdList.Contains(t.Id)).ProjectTo<DownloadDicomInstanceDto>(_mapper.ConfigurationProvider).ToListAsync();
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
idPathList = await _dicomInstanceRepository.Where(t => t.SeriesId == inCommand.SeriesId).Select(t => new InstanceIdPath { Id = t.Id, Path = t.Path }).ToListAsync();
|
idPathList = await _dicomInstanceRepository.Where(t => t.SeriesId == inCommand.SeriesId).ProjectTo<DownloadDicomInstanceDto>(_mapper.ConfigurationProvider).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
var errorList = new List<InstanceIdPath>();
|
var errorList = new List<InstanceIdPath>();
|
||||||
|
|
@ -105,7 +161,53 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var inputStream = await _oSSService.GetStreamFromOSSAsync(path);
|
|
||||||
|
await using var inputStream = new MemoryStream();
|
||||||
|
|
||||||
|
if (item.IsEncapsulated /*&& item.NumberOfFrames > 1*/)
|
||||||
|
{
|
||||||
|
|
||||||
|
var ok = await TryWriteMergedDicomAsync(() => _oSSService.GetStreamFromOSSAsync(path), inputStream);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await (await _oSSService.GetStreamFromOSSAsync(path)).CopyToAsync(inputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//await using var ms = new MemoryStream();
|
||||||
|
|
||||||
|
//await inputStream.CopyToAsync(ms);
|
||||||
|
|
||||||
|
//ms.Position = 0;
|
||||||
|
|
||||||
|
|
||||||
|
#region 测试废弃
|
||||||
|
//var localPath = Path.Combine(FileStoreHelper.GetDonwnloadImageFolder(_hostEnvironment), Path.GetFileName(path));
|
||||||
|
|
||||||
|
//await _oSSService.DownLoadFromOSSAsync(path, localPath);
|
||||||
|
|
||||||
|
//await using var input = File.OpenRead(localPath);
|
||||||
|
|
||||||
|
//var outputPath = Path.Combine(FileStoreHelper.GetDonwnloadImageFolder(_hostEnvironment), "After", Path.GetFileName(path));
|
||||||
|
|
||||||
|
//var outputFolder = Path.GetDirectoryName(outputPath);
|
||||||
|
//if (!string.IsNullOrEmpty(outputFolder))
|
||||||
|
//{
|
||||||
|
// Directory.CreateDirectory(outputFolder);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//await using var output = File.Create(outputPath);
|
||||||
|
|
||||||
|
//await DicomPixelMasker.MaskAsync(inputStream, output,inCommand.MaskRegionList);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var outPutStream = await DicomPixelMasker.MaskAsync(inputStream, inCommand.MaskRegionList);
|
var outPutStream = await DicomPixelMasker.MaskAsync(inputStream, inCommand.MaskRegionList);
|
||||||
|
|
||||||
|
|
@ -120,7 +222,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||||
await _oSSService.DeleteFromPrefix(path, true); //清理缓存的里面的遮盖图,多次遮盖同一张图时,清除缓存很重要
|
await _oSSService.DeleteFromPrefix(path, true); //清理缓存的里面的遮盖图,多次遮盖同一张图时,清除缓存很重要
|
||||||
|
|
||||||
//本身就是遮盖的图,那么就要要替换guid
|
//本身就是遮盖的图,那么就要要替换guid
|
||||||
var length = Guid.Empty.ToString().Length + ".MaskDicom_".Length ;
|
var length = Guid.Empty.ToString().Length + ".MaskDicom_".Length;
|
||||||
|
|
||||||
var restorePath = item.Path[..^length];
|
var restorePath = item.Path[..^length];
|
||||||
|
|
||||||
|
|
@ -136,14 +238,14 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||||
|
|
||||||
var newPath = $"/{prefix}/{maskFileName}";
|
var newPath = $"/{prefix}/{maskFileName}";
|
||||||
|
|
||||||
okList.Add(new InstanceIdPath() { Id = item.Id, Path = newPath });
|
okList.Add(new InstanceIdPath() { Id = item.InstanceId, Path = newPath });
|
||||||
|
|
||||||
await _dicomInstanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Id, u => new DicomInstance() { Path = newPath, IsMasked = true });
|
await _dicomInstanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.InstanceId, u => new DicomInstance() { Path = newPath, IsMasked = true });
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
||||||
errorList.Add(new InstanceIdPath() { Id = item.Id, Path = path });
|
errorList.Add(new InstanceIdPath() { Id = item.InstanceId, Path = path });
|
||||||
|
|
||||||
Log.Logger.Error(ex, $"StudyMaskImage Error for InstanceIdList Path:{path} {ex.Message}");
|
Log.Logger.Error(ex, $"StudyMaskImage Error for InstanceIdList Path:{path} {ex.Message}");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,9 @@ namespace IRaCIS.Core.Application.Service
|
||||||
|
|
||||||
CreateMap<ImageMarkNoneDicomStudyBasicInfo, NoneDicomStudyBasicInfo>();
|
CreateMap<ImageMarkNoneDicomStudyBasicInfo, NoneDicomStudyBasicInfo>();
|
||||||
|
|
||||||
|
CreateMap<DicomInstance, DownloadDicomInstanceDto>()
|
||||||
|
.ForMember(d => d.InstanceId, u => u.MapFrom(s => s.Id));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -129,8 +129,8 @@ namespace IRaCIS.Core.Application.Service
|
||||||
public async Task<IResponseOutput> MaskImage()
|
public async Task<IResponseOutput> MaskImage()
|
||||||
{
|
{
|
||||||
|
|
||||||
var sourceDir = @"D:\images\11\像素匿名\隐私信息2&测量值\08\08017\基线(V1)\ST01371_1970-01-01_US\IMAGE";
|
var sourceDir = @"C:\work\gitea\irc-netcore-api\DownloadImage";
|
||||||
var targetDir = @"D:\images\11\像素匿名\隐私信息2&测量值\08\08017\基线(V1)\ST01371_1970-01-01_US\IMAGE\after";
|
var targetDir = @"C:\work\gitea\irc-netcore-api\DownloadImage\after";
|
||||||
|
|
||||||
Directory.CreateDirectory(targetDir);
|
Directory.CreateDirectory(targetDir);
|
||||||
var regions = new[]
|
var regions = new[]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue