Skip to content

Add DIMS imaging support and improve imaging workflow#753

Open
YukiMatsuzawa wants to merge 12 commits into
masterfrom
feature/imzml-imaging
Open

Add DIMS imaging support and improve imaging workflow#753
YukiMatsuzawa wants to merge 12 commits into
masterfrom
feature/imzml-imaging

Conversation

@YukiMatsuzawa

Copy link
Copy Markdown
Contributor

This PR adds and refines the DIMS imaging flow, including the new imaging tab/ribbon UI, async pixel intensity loading, placeholder handling, and export support. It also updates the underlying data providers, image models, and DIMS/IMMS imaging view models to align the UI and processing pipeline.

Key changes:

  • Added DIMS imaging UI entry points and tab structure
  • Improved imaging data loading with async cache/placeholder handling
  • Updated intensity/image model bindings and ROI-related logic
  • Added export support for imaging intensities
  • Refactored DIMS/IMMS imaging processing and file handling
  • Fixed save and chromatogram-related imaging behavior

YukiMatsuzawa and others added 11 commits July 22, 2026 15:52
Refactored core imaging classes to use asynchronous methods for loading and processing pixel intensity data. Replaced synchronous calls with async counterparts, updated method signatures, and added CancellationToken support. Enhanced ViewModels to observe async loading states, improving UI responsiveness and scalability for long-running operations. Console/test code updated for compatibility.
Refactored AccumulatedIntensity to remove lazy async logic from the getter and made calculation explicit via a public method. Updated XAML bindings to use .Value for correct data binding. Made SelectedRoiPeakSummary nullable and trigger intensity calculation on selection. Simplified property binding and delegated calculation in the ViewModel.
Introduce thread-safe ConcurrentLruCache and IntensityImagePlaceholderModel for intensity image caching and retrieval. Update BitmapImageModel for async, thread-safe bitmap loading. Refactor models and viewmodels to use the new placeholder mechanism, replacing direct IntensityImageModel selection. Update SaveImagesModel and XAML bindings to support async image loading and improved null handling. Improve thread-safety and property change notifications throughout.
- Allow internal updates to BitmapImageModel.Title property
- Dynamically set image titles based on m/z, mobility, and peak name
- Ensure IntensityImagePlaceholderModel updates image titles as needed
- Display current image title in ImagingMainView.xaml above the image
- Add grid row in XAML to support image title display
Introduce ExportIntensitiesAsync to export only image intensities. Add ExportIntensitiesCommand to the view model and update the UI to use the new command. Change export button bindings from OneTime to OneWay for improved responsiveness.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends MSDIAL5’s imaging capabilities by adding DIMS imaging UI entry points (Ribbon/tab) and refactoring the imaging pipeline toward async, cached/placeholder-based image/intensity loading, alongside new DIMS provider options and export/save workflow updates.

Changes:

  • Added DIMS imaging Ribbon/Tab UI and new commands (ROI save/load, intensity export) for the imaging workflow.
  • Refactored imaging image/intensity generation toward async loading with placeholder/caching models and updated bindings.
  • Added a new “Accumulate/Sum MS1 spectra by m/z” data provider option for DIMS and tightened peak conversion mass range usage.

Reviewed changes

Copilot reviewed 41 out of 41 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
tests/MSDIAL5/MsdialCoreTestApp/Process/MaldiMsProcessTest.cs Updates pixel feature retrieval calls to async API in test app.
src/MSDIAL5/MsdialImmsImagingCore/Process/FileProcess.cs Switches raw pixel spectra retrieval to async method.
src/MSDIAL5/MsdialGuiApp/ViewModel/ImagingImms/WholeImageResultViewModel.cs Replaces selected intensity VM wiring with placeholder-based binding.
src/MSDIAL5/MsdialGuiApp/ViewModel/ImagingImms/ImagingImmsImageViewModel.cs Adds Save ROI command wiring.
src/MSDIAL5/MsdialGuiApp/ViewModel/ImagingDims/WholeImageResultViewModel.cs Mirrors IMMS placeholder-based binding for DIMS.
src/MSDIAL5/MsdialGuiApp/ViewModel/ImagingDims/ImagingDimsImageViewModel.cs Adds Save ROI + Export intensities commands for DIMS imaging.
src/MSDIAL5/MsdialGuiApp/ViewModel/Imaging/RoiPeakSummaryViewModel.cs Makes accumulated intensity reactive + async triggerable.
src/MSDIAL5/MsdialGuiApp/ViewModel/Imaging/ImagingRoiViewModel.cs Triggers async accumulated-intensity computation on selection.
src/MSDIAL5/MsdialGuiApp/ViewModel/Dims/DimsDataCollectionSettingViewModel.cs Adds VM binding for new accumulate-MS1 option.
src/MSDIAL5/MsdialGuiApp/ViewModel/Chart/BitmapImageViewModel.cs Exposes BitmapSource as reactive + async ensure method.
src/MSDIAL5/MsdialGuiApp/View/Setting/DatasetFileSettingView.xaml.cs Adds imzML to supported dataset file selection UI.
src/MSDIAL5/MsdialGuiApp/View/Setting/DataCollectionSettingView.xaml Adds “Sum MS1 spectra by m/z” UI option and adjusts wording.
src/MSDIAL5/MsdialGuiApp/View/ImagingImms/ImagingMainView.xaml Updates imaging view to use placeholder image binding + layout adjustments.
src/MSDIAL5/MsdialGuiApp/View/ImagingDims/ImagingTab.xaml.cs New RibbonTab code-behind for DIMS imaging tab.
src/MSDIAL5/MsdialGuiApp/View/ImagingDims/ImagingTab.xaml New DIMS imaging RibbonTab UI definition.
src/MSDIAL5/MsdialGuiApp/View/ImagingDims/ImagingMainView.xaml Updates DIMS imaging view to use placeholder image binding + layout adjustments.
src/MSDIAL5/MsdialGuiApp/View/ImagingDims/DimsImagingRibbon.xaml Adds contextual “Imaging” tab group and inserts the new DIMS imaging tab.
src/MSDIAL5/MsdialGuiApp/View/Chart/BitmapImageView.xaml Updates binding path to reactive BitmapSource.Value.
src/MSDIAL5/MsdialGuiApp/Model/Loader/MsDecSpectrumFromFileLoader.cs Adds exception handling/fallback behavior when loading MSDec results.
src/MSDIAL5/MsdialGuiApp/Model/ImagingImms/WholeImageResultModel.cs Introduces placeholder model and selection-driven async image update (IMMS).
src/MSDIAL5/MsdialGuiApp/Model/ImagingImms/ImagingImmsMethodModel.cs Saves imaging results across all image models rather than a single image.
src/MSDIAL5/MsdialGuiApp/Model/ImagingImms/ImagingImmsImageModel.cs Adds folder-select ROI save behavior and returns success status.
src/MSDIAL5/MsdialGuiApp/Model/ImagingDims/WholeImageResultModel.cs Introduces placeholder model + adds “save intensities to chosen file” workflow (DIMS).
src/MSDIAL5/MsdialGuiApp/Model/ImagingDims/ImagingDimsMethodModel.cs Updates provider factory creation and saves imaging results across all images.
src/MSDIAL5/MsdialGuiApp/Model/ImagingDims/ImagingDimsImageModel.cs Adds folder-select ROI save + explicit “Export intensities” method.
src/MSDIAL5/MsdialGuiApp/Model/Imaging/SaveImagesModel.cs Updates image export to use placeholder image and prompts for output path.
src/MSDIAL5/MsdialGuiApp/Model/Imaging/RoiPeakSummaryModel.cs Makes accumulated intensity computation async with loading state.
src/MSDIAL5/MsdialGuiApp/Model/Imaging/RoiModel.cs Converts raw pixel spectra retrieval to async API.
src/MSDIAL5/MsdialGuiApp/Model/Imaging/RoiAccess.cs Adds fast-path when ROI index mapping is identity.
src/MSDIAL5/MsdialGuiApp/Model/Imaging/RawIntensityOnPixelsLoader.cs Refactors intensity loading to async and introduces a shared RawDataAccess field.
src/MSDIAL5/MsdialGuiApp/Model/Imaging/IWholeImageResultModel.cs Switches interface from selected-intensity to placeholder image model.
src/MSDIAL5/MsdialGuiApp/Model/Imaging/IntensityImagePlaceholderModel.cs New cached/placeholder image model for async intensity image generation.
src/MSDIAL5/MsdialGuiApp/Model/Imaging/IntensityImageModel.cs Makes peak index accessible and shifts intensity load to async API usage.
src/MSDIAL5/MsdialGuiApp/Model/Imaging/ImagingRoiModel.cs Saves ROI position CSV into a user-selected directory.
src/MSDIAL5/MsdialGuiApp/Model/Dims/DimsDataCollectionSettingModel.cs Adds accumulate-MS1 option and parameter (de)serialization logic.
src/MSDIAL5/MsdialGuiApp/Model/Chart/BitmapImageModel.cs Adds async bitmap realization with a loading flag and semaphore.
src/MSDIAL5/MsdialDimsCore/ProcessFile.cs Applies mass range bounds when converting MS1 peaks.
src/MSDIAL5/MsdialDimsCore/Parameter/DimsProviderFactoryParameter.cs Adds MessagePack union/parameter type for accumulate-MS1 provider.
src/MSDIAL5/MsdialDimsCore/Algorithm/DimsDataProvider.cs Implements accumulate-MS1 provider and factory.
src/MSDIAL5/MsdialCore/Enum/SupportFormat.cs Adds imzML to supported raw data extensions enum.
src/Common/CommonStandard/DataStructure/ConcurrentLruCache.cs Adds a thread-safe wrapper around LruCache (currently with lock-mode issues).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +21 to +29
public TValue Get(TKey key) {
_locker.EnterReadLock();
try {
return _cache.Get(key);
}
finally {
_locker.ExitReadLock();
}
}
Comment on lines +51 to +64
public bool TryGet(TKey key, out TValue value) {
_locker.EnterReadLock();
try {
if (_cache.ContainsKey(key)) {
value = _cache.Get(key);
return true;
}
value = default;
return false;
}
finally {
_locker.ExitReadLock();
}
}
Comment on lines +15 to 19
private readonly RawDataAccess _rawDataAccess;

public RawIntensityOnPixelsLoader(List<Raw2DElement> targets, AnalysisFileBeanModel file, MaldiFrames frames)
{
_targets = targets;
Comment on lines +42 to +60
public async Task EnsureBitmapSourceAsync() {
if (_bitmapSource is not null || LoadingBitmap) {
return;
}

await _semaphoreSlim.WaitAsync().ConfigureAwait(false);

try {
if (_bitmapSource is not null || LoadingBitmap) {
return;
}
LoadingBitmap = true;
BitmapSource = await Task.Run(() => _bitmapSourceFactory!.Invoke()).ConfigureAwait(false);
LoadingBitmap = false;
}
finally {
_semaphoreSlim.Release();
}
}
Comment on lines 113 to +131
using var sem = new SemaphoreSlim(8, 8);
var tasks = new List<Task>(Intensities.Count);
foreach (var ints in Intensities) {
tasks.Add(Task.Run(async () => {
await sem.WaitAsync().ConfigureAwait(false);
try {
await ints.SaveAsync(writer, skipUnknownPeaks: false, token: token);
}
finally {
sem.Release();
}
}, token));
}
await Task.WhenAll(tasks).ConfigureAwait(false);
var task = Task.CompletedTask;
await task;
task.Wait();

return true;
Comment on lines +104 to +110
case DimsAccumulateDataProviderFactoryParameter accumulateParameter:
UseMs1WithHighestTic = false;
UseAccumulateMs1 = true;
TimeBegin = accumulateParameter.TimeBegin;
TimeEnd = accumulateParameter.TimeEnd;
MassTolerance = accumulateParameter.MassTolerance;
break;
Comment on lines 204 to 206
<Rectangle.ToolTip>
<TextBlock Text="{Binding SelectedRoiPeakSummary.Value.AccumulatedIntensity, StringFormat=Average intensity: {0:F0}}"/>
<TextBlock Text="{Binding SelectedRoiPeakSummary.Value.AccumulatedIntensity.Value, StringFormat=Average intensity: {0:F0}}"/>
</Rectangle.ToolTip>
Comment on lines 194 to 196
<Rectangle.ToolTip>
<TextBlock Text="{Binding SelectedRoiPeakSummary.Value.AccumulatedIntensity, StringFormat=Average intensity: {0:F0}}"/>
<TextBlock Text="{Binding SelectedRoiPeakSummary.Value.AccumulatedIntensity.Value, StringFormat=Average intensity: {0:F0}}"/>
</Rectangle.ToolTip>
Comment on lines 210 to 213
Console.WriteLine("Reading data...");
using (var access = new RawDataAccess(filepath, 0, false, true, false)) {
pixelData = access.GetRawPixelFeatures(featureElements, null);
pixelData = access.GetRawPixelFeaturesAsync(featureElements, null).Result;
}
Comment on lines 304 to 308
var featureElements = features.Select(n => new Raw2DElement() { Mz = n.PeakFeature.Mass }).ToList();
Console.WriteLine("Reading data...");
using (var access = new RawDataAccess(filepath, 0, false, true, false)) {
pixelData = access.GetRawPixelFeatures(featureElements, null);
pixelData = access.GetRawPixelFeaturesAsync(featureElements, null).Result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants