* [WIP] Fix contour annotations RTSS saving * fix: Export image sop image reference provider * Fixes for download with filename * Updates to fix metadata issues with CS3D * Updates to save menu * Fixing some additional re-save metadata * Add support for saving with predecessor image sequence * PR comment fixes * fix: Load RTSS after save * fix segmentation save * fix load of mixed seg/rt studies * Use frame module to get information on the frame shown * Fix study browser to use instances.length when numImageFrames not present * fix: Load of display set split from multiple non-FOR referenes * Fix RT and SEG applying to wrong series because of using referenced series sequence without checkout sop instances * Fix save seg * Update to released CS3D versions * test: Add revokeObjectURL to test download blob * Add hard dependency on mode-basic to fix build order issues * fix: build * Try to fix build segmentation * PR comments * PR comment update
132 lines
4.1 KiB
TypeScript
132 lines
4.1 KiB
TypeScript
import { utils } from '@ohif/core';
|
|
|
|
const { downloadCsv } = utils;
|
|
|
|
export function generateSegmentationCSVReport(
|
|
segmentationData,
|
|
info: {
|
|
reference: {
|
|
SeriesNumber: string;
|
|
SeriesInstanceUID: string;
|
|
StudyInstanceUID: string;
|
|
SeriesDate: string;
|
|
SeriesTime: string;
|
|
SeriesDescription: string;
|
|
};
|
|
}
|
|
) {
|
|
// Initialize the rows for our CSV
|
|
const csvRows = [];
|
|
|
|
// Add segmentation-level information
|
|
csvRows.push(['Segmentation ID', segmentationData.segmentationId || '']);
|
|
csvRows.push(['Segmentation Label', segmentationData.label || '']);
|
|
|
|
csvRows.push([]);
|
|
|
|
const additionalInfo = info.reference;
|
|
// Add reference information
|
|
const referenceKeys = [
|
|
['Series Number', additionalInfo.SeriesNumber],
|
|
['Series Instance UID', additionalInfo.SeriesInstanceUID],
|
|
['Study Instance UID', additionalInfo.StudyInstanceUID],
|
|
['Series Date', additionalInfo.SeriesDate],
|
|
['Series Time', additionalInfo.SeriesTime],
|
|
['Series Description', additionalInfo.SeriesDescription],
|
|
];
|
|
|
|
referenceKeys.forEach(([key, value]) => {
|
|
if (value) {
|
|
csvRows.push([`reference ${key}`, value]);
|
|
}
|
|
});
|
|
|
|
// Add a blank row for separation
|
|
csvRows.push([]);
|
|
|
|
csvRows.push(['Segments Statistics']);
|
|
|
|
// Add segment information in columns
|
|
if (segmentationData.segments) {
|
|
// First row: Segment headers
|
|
const segmentHeaderRow = ['Label'];
|
|
for (const segmentId in segmentationData.segments) {
|
|
const segment = segmentationData.segments[segmentId];
|
|
segmentHeaderRow.push(`${segment.label || ''}`);
|
|
}
|
|
csvRows.push(segmentHeaderRow);
|
|
|
|
// Add segment properties
|
|
csvRows.push([
|
|
'Segment Index',
|
|
...Object.values(segmentationData.segments).map(s => s.segmentIndex || ''),
|
|
]);
|
|
csvRows.push([
|
|
'Locked',
|
|
...Object.values(segmentationData.segments).map(s => (s.locked ? 'Yes' : 'No')),
|
|
]);
|
|
csvRows.push([
|
|
'Active',
|
|
...Object.values(segmentationData.segments).map(s => (s.active ? 'Yes' : 'No')),
|
|
]);
|
|
|
|
// Add segment statistics
|
|
// First, collect all unique statistics across all segments
|
|
const allStats = new Set();
|
|
for (const segment of Object.values(segmentationData.segments)) {
|
|
if (segment.cachedStats && segment.cachedStats.namedStats) {
|
|
for (const statKey in segment.cachedStats.namedStats) {
|
|
const stat = segment.cachedStats.namedStats[statKey];
|
|
const statLabel = stat.label || stat.name;
|
|
const statUnit = stat.unit ? ` (${stat.unit})` : '';
|
|
allStats.add(`${statLabel}${statUnit}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Then create a row for each statistic
|
|
for (const statName of allStats) {
|
|
const statRow = [statName];
|
|
|
|
for (const segment of Object.values(segmentationData.segments)) {
|
|
let statValue = '';
|
|
|
|
if (segment.cachedStats && segment.cachedStats.namedStats) {
|
|
for (const statKey in segment.cachedStats.namedStats) {
|
|
const stat = segment.cachedStats.namedStats[statKey];
|
|
const currentStatName = `${stat.label || stat.name}${stat.unit ? ` (${stat.unit})` : ''}`;
|
|
|
|
if (currentStatName === statName) {
|
|
statValue = stat.value !== undefined ? stat.value : '';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
statRow.push(statValue);
|
|
}
|
|
|
|
csvRows.push(statRow);
|
|
}
|
|
}
|
|
|
|
// Convert to CSV string
|
|
let csvString = '';
|
|
for (const row of csvRows) {
|
|
const formattedRow = row.map(cell => {
|
|
// Handle values that need to be quoted (contain commas, quotes, or newlines)
|
|
const cellValue = cell !== undefined && cell !== null ? cell.toString() : '';
|
|
if (cellValue.includes(',') || cellValue.includes('"') || cellValue.includes('\n')) {
|
|
// Escape quotes and wrap in quotes
|
|
return '"' + cellValue.replace(/"/g, '""') + '"';
|
|
}
|
|
return cellValue;
|
|
});
|
|
csvString += formattedRow.join(',') + '\n';
|
|
}
|
|
|
|
downloadCsv(csvString, {
|
|
filename: `${segmentationData.label || 'Segmentation'}_Report_${new Date().toISOString().split('T')[0]}.csv`,
|
|
});
|
|
}
|