Основные компоненты: ImageViewerManager, LayoutManager, ReferenceLineManager, ExportManager, AnnotationManager, FilterManager, LocalizeManager
Функционал тестового приложения:
Главный компонент системы.
...
//Пример стартовой инициализация ImageViewerManager
ImageViewerManager imageViewerManager = new ImageViewerManager(this, this.layoutPanel);
imageViewerManager.onProcessDescriptionChanged += imageViewerManager_ProcessDescriptionChanged;
imageViewerManager.onSeriesLoaded += ImageViewerManager_onSeriesLoaded;
imageViewerManager.onStudyLoaded += ImageViewerManager_onStudyLoaded;
//Конец инициализации
...
//Событие загрузка серии
private void ImageViewerManager_onSeriesLoaded(DicomImageViewControl currentDicomImageViewControl)
{
//Например, генерация TreeView для переключения между папками серий
generateTreeViewNodesForStudy();
}
...
//Генерация TreeView для переключения между папками серий
private void generateTreeViewNodesForStudy()
{
treeViewDicomStudies.Nodes.Clear();
foreach (DicomImageViewControl dicomImageViewControl in imageViewerManager.LoadedDicomImageViewControls)
{
TreeNode seriesNode = new TreeNode();
seriesNode.Text = dicomImageViewControl.CurrentDicomElement.ImageSop.SeriesDescription;
seriesNode.Tag = dicomImageViewControl.FilePaths;
imageListDicomStudies.Images.Add(dicomImageViewControl.CurrentDicomElement.Bitmap);
seriesNode.ImageIndex = imageListDicomStudies.Images.Count - 1;
seriesNode.SelectedImageIndex = imageListDicomStudies.Images.Count - 1;
treeViewDicomStudies.Nodes.Add(seriesNode);
}
}
...
Размещение окон с обследованиями, изменение сетки, изменение размеров окон
...
//Пример реализации метода реакции на событие изменения размеров контейнера, в котором отображаются серии обследований
void layoutPanel_SizeChanged(object sender, System.EventArgs e)
{
imageViewerManager.LayoutManager.Resize();
}
...
//Обработка нажатия клавиши
void container_KeyDown(object sender, KeyEventArgs e)
{
imageViewerManager.LayoutManager.KeyDown(e);
e.Handled = false;
}
...
//Изменение сетки размещения
imageViewerManager.LayoutManager.Offset = this.Offset;
imageViewerManager.LayoutManager.GridX = 2;
imageViewerManager.LayoutManager.GridY = 3;
imageViewerManager.LayoutManager.ChangeLayout();
...
Отрисовка линий взаимного пересечения различных проекций
...
//Пример реализации метода переключения на следующее изображение в серии
internal void NextImage()
{
if (this.CurrentDicomElement != null)
{
if (this.number + 1 < DicomElements.Count)
{
this.number++;
this.CurrentDicomElement = DicomElements[this.number];
this.LoadImage();
}
else
{
this.number = 0;
this.CurrentDicomElement = DicomElements[0];
this.LoadImage();
}
//Вызов пересчета и перерисовки линий взаимного пересечения различных проекций во всех отображаемых на данный момент окнах
imageViewerManager.ReferenceLineManager.Refresh();
}
}
...
Экспорт DICOM-файлов в jpeg, avi
...
//Пример вызова методов для экспорта
private void bgrwExport_DoWork(object sender, DoWorkEventArgs e)
{
ArgForBgrwExport argForBgrwExport = (ArgForBgrwExport)e.Argument;
BackgroundWorker worker = sender as BackgroundWorker;
ExportManager = new ExportManager(argForBgrwExport.folder);
string type = argForBgrwExport.type;
if (type == "bitmap")
{
ExportManager.doBitmapExporting(worker);
}
if (type == "video")
{
ExportManager.doVideoExporting(worker);
}
if (worker.CancellationPending)
{
e.Cancel = true;
}
}
...
//Экспорт DICOM серии в видеофайл
public void doVideoExporting(BackgroundWorker worker)
{
int count = 0;
foreach (DirectoryInfo folder in folders.GetDirectories())
{
if (worker.CancellationPending)
{
break;
}
try
{
new VideoExporter().exportTo(folder);
}
catch (Exception e)
{
log.Error("Error while video exporting from folder: " + folder.Name);
log.Error(e.StackTrace);
}
count++;
worker.ReportProgress(count);
}
}
...
Управление аннотациями к отображаемому файлу DICOM. Стрелка, область, прямоуголник, измерение, текст.
...
//Пример добавления аннотации "Произвольная область"
if (this.freehandToolActive)
{
freehanding = true;
if (currentFreeHandAnnotation == null)
{
currentFreeHandAnnotation = new FreeHandAnnotation();
currentFreeHandAnnotation.Color = this.imageViewerManager.CurrentColor;
currentFreeHandAnnotation.Width = this.imageViewerManager.CurrentBrushSize;
AnnotationManager.AddAnnotation(currentFreeHandAnnotation);
}
}
...
//Пример добавления аннотации "Линейка"
if (this.rulerToolActive)
{
rulling = true;
if (currentRulerAnnotation == null)
{
currentRulerAnnotation = new RulerAnnotation();
currentRulerAnnotation.Color = this.imageViewerManager.CurrentColor;
currentRulerAnnotation.StartPoint = this.convertToOrigin(e.Location);
currentRulerAnnotation.EndPoint = new Point(currentRulerAnnotation.StartPoint.X, currentRulerAnnotation.StartPoint.Y - 15);
AnnotationManager.AddAnnotation(currentRulerAnnotation);
}
return;
}
...
//Пример добавления аннотации "Стрелка"
if (this.arrowToolActive)
{
arrowing = true;
if (currentArrowAnnotation == null)
{
currentArrowAnnotation = new ArrowAnnotation();
currentArrowAnnotation.Color = this.imageViewerManager.CurrentColor;
currentArrowAnnotation.Width = this.imageViewerManager.CurrentBrushSize;
currentArrowAnnotation.StartPoint = this.convertToOrigin(e.Location);
currentArrowAnnotation.EndPoint = new Point(currentArrowAnnotation.StartPoint.X, currentArrowAnnotation.StartPoint.Y - 15);
AnnotationManager.AddAnnotation(currentArrowAnnotation);
}
return;
}
...
Компонент управления накладываемыми на DICOM-изображение фильтрами.
...
//Пример реализации формы для управления фильтрами
public FormFilterManager(DicomImageViewer.Dicom.FilterManager filterManager)
{
InitializeComponent();
this.FilterManager = filterManager;
//Получаем список существующих фильтров
foreach (var item in FilterManager.FiltersNameList)
{
cbFiltersList.Items.Add(item);
}
if (cbFiltersList.Items.Count > 0)
{
cbFiltersList.SelectedIndex = 0;
}
refreshLbFilters();
}
...
private void bAddFilter_Click(object sender, EventArgs e)
{
//Добавляем фильтр и базовое значение
FilterManager.AddFilter(cbFiltersList.Text, Convert.ToDouble(tbValue.Text));
refreshLbFilters();
}
...
private void bDeleteAllFilters_Click(object sender, EventArgs e)
{
//Удалить все фильтры
FilterManager.DeleteAllFilters();
refreshLbFilters();
}
...
private void bDeleteFilter_Click(object sender, EventArgs e)
{
//Удаляем конкретный фильтр
if (lbFilters.SelectedIndex != -1)
{
FilterManager.DeleteFilter(((Filter)lbFilters.Items[lbFilters.SelectedIndex]).Id);
refreshLbFilters();
}
}
...
//Актуализация ListBox со списком фильтров
private void refreshLbFilters(int selectedIndex = -1)
{
//Получаем список примененных фильтров
int currentIndex = lbFilters.SelectedIndex;
if(selectedIndex != -1)
{
currentIndex = selectedIndex;
}
lbFilters.Items.Clear();
foreach (System.Collections.DictionaryEntry item in this.FilterManager.Filters)
{
lbFilters.Items.Add((Filter)item.Value);
}
if (currentIndex >= lbFilters.Items.Count)
{
currentIndex = lbFilters.Items.Count - 1;
}
if (currentIndex < -1)
{
currentIndex = -1;
}
if (lbFilters.Items.Count > 0)
{
lbFilters.SelectedIndex = currentIndex;
}
else
{
tbSelectedFilterName.Tag = "";
tbSelectedFilterName.Text = "";
tbSelectedFilterValue.Text = "";
}
}
...
Инструмент локализации срезов(слайсов) для передачи полученной информации исполнительному оборудованию
...
//Пример создания локализатора
if (toolName == "localize")
{
LocalizeManager.CreateLocalize(this.CurrentDicomImageViewControl);
}
...
Библитека использует компоненты популярного opensource проекта ClearCanvas.