UNPKG

@cornerstonejs/core

Version:
103 lines (102 loc) 4.2 kB
import { vec3 } from 'gl-matrix'; import { MetadataModules } from '../enums/index.js'; import * as metaData from '../metaData.js'; import isVideoTransferSyntax from './isVideoTransferSyntax.js'; export function getVideoImageDataMetadata(imageId) { const imagePlaneModule = metaData.get(MetadataModules.IMAGE_PLANE, imageId); let rowCosines = imagePlaneModule.rowCosines; let columnCosines = imagePlaneModule.columnCosines; const usingDefaultValues = imagePlaneModule.usingDefaultValues; if (usingDefaultValues || rowCosines == null || columnCosines == null) { rowCosines = [1, 0, 0]; columnCosines = [0, 1, 0]; } const rowCosineVec = vec3.fromValues(rowCosines[0], rowCosines[1], rowCosines[2]); const colCosineVec = vec3.fromValues(columnCosines[0], columnCosines[1], columnCosines[2]); const scanAxisNormal = vec3.create(); vec3.cross(scanAxisNormal, rowCosineVec, colCosineVec); const rows = imagePlaneModule.rows; const columns = imagePlaneModule.columns; const origin = (imagePlaneModule.imagePositionPatient || [0, 0, 0]); const xSpacing = imagePlaneModule.columnPixelSpacing || 1; const ySpacing = imagePlaneModule.rowPixelSpacing || 1; const zSpacing = 1; const xVoxels = imagePlaneModule.columns; const yVoxels = imagePlaneModule.rows; const zVoxels = 1; return { bitsAllocated: 8, numberOfComponents: 3, origin, rows, columns, direction: [...rowCosineVec, ...colCosineVec, ...scanAxisNormal], dimensions: [xVoxels, yVoxels, zVoxels], spacing: [xSpacing, ySpacing, zSpacing], hasPixelSpacing: !!imagePlaneModule.columnPixelSpacing, numVoxels: xVoxels * yVoxels * zVoxels, imagePlaneModule, }; } export function loadVideoStreamMetadata(imageId) { const renderedUrl = getRenderedVideoUrl(imageId); if (!renderedUrl) { throw new Error(`Video Image ID ${imageId} does not have a rendered video view`); } const generalSeries = metaData.get(MetadataModules.GENERAL_SERIES, imageId); const cine = metaData.get(MetadataModules.CINE, imageId) || {}; const instance = metaData.get(MetadataModules.INSTANCE, imageId); const frameTime = cine.frameTime ?? cine.FrameTime; return { renderedUrl, modality: generalSeries?.Modality ?? generalSeries?.modality, metadata: getVideoImageDataMetadata(imageId), cineRate: cine.cineRate ?? cine.recommendedDisplayFrameRate ?? (frameTime ? 1000 / Number(frameTime) : undefined), numberOfFrames: cine.numberOfFrames ?? instance?.NumberOfFrames, }; } function getRenderedVideoUrl(imageId) { const imageUrlModule = metaData.get(MetadataModules.IMAGE_URL, imageId); if (imageUrlModule?.rendered) { return imageUrlModule.rendered; } const transferSyntax = metaData.get(MetadataModules.TRANSFER_SYNTAX, imageId); const isVideo = transferSyntax?.isVideo || isVideoTransferSyntax(transferSyntax?.transferSyntaxUID); if (!isVideo) { return; } const imageUrl = imageId.startsWith('wadors:') ? imageId.substring(7) : imageId; if (!imageUrl.includes('/frames/')) { return; } return imageUrl .replace('/frames/', '/rendered/') .replace(/\/rendered\/\d+($|[?#])/, '/rendered$1'); } export function normalizeVideoPlaybackInfo(args) { const durationSeconds = Math.max(args.durationSeconds || 0, 0.001); let numberOfFrames = args.numberOfFrames; let fps = args.cineRate; if (!numberOfFrames || numberOfFrames === 1) { numberOfFrames = Math.max(1, Math.round(durationSeconds * (fps || 30))); } if (!fps) { fps = Math.max(1, Math.round(numberOfFrames / durationSeconds)); } return { fps, numberOfFrames, frameRange: [1, numberOfFrames], }; } export function frameNumberToTimeSeconds(frameNumber, fps) { return Math.max(0, frameNumber - 1) / Math.max(1, fps); } export function timeSecondsToFrameNumber(timeSeconds, fps) { return 1 + Math.round(Math.max(0, timeSeconds) * Math.max(1, fps)); }