/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkVideoStream_hxx #define itkVideoStream_hxx namespace itk { template void VideoStream::SetFrameLargestPossibleSpatialRegion(SizeValueType frameNumber, typename TFrameType::RegionType region) { m_LargestPossibleSpatialRegionCache[frameNumber] = region; // If the frame is currently buffered, set the actual frame's region SizeValueType bufStart = m_BufferedTemporalRegion.GetFrameStart(); SizeValueType bufDur = m_BufferedTemporalRegion.GetFrameDuration(); if (frameNumber >= bufStart && frameNumber < bufStart + bufDur) { FrameType * frame = this->GetFrame(frameNumber); frame->SetLargestPossibleRegion(region); } } template const typename TFrameType::RegionType & VideoStream::GetFrameLargestPossibleSpatialRegion(SizeValueType frameNumber) const { // It seems that std::map's [] operator isn't const correct, so we need to // access this member from an non-const version of ourselves return const_cast(this)->m_LargestPossibleSpatialRegionCache[frameNumber]; } template void VideoStream::SetFrameRequestedSpatialRegion(SizeValueType frameNumber, typename TFrameType::RegionType region) { m_RequestedSpatialRegionCache[frameNumber] = region; // If the frame is currently buffered, set the actual frame's region SizeValueType bufStart = m_BufferedTemporalRegion.GetFrameStart(); SizeValueType bufDur = m_BufferedTemporalRegion.GetFrameDuration(); if (frameNumber >= bufStart && frameNumber < bufStart + bufDur) { FrameType * frame = this->GetFrame(frameNumber); frame->SetRequestedRegion(region); } } template const typename TFrameType::RegionType & VideoStream::GetFrameRequestedSpatialRegion(SizeValueType frameNumber) const { // It seems that std::map's [] operator isn't const correct, so we need to // access this member from an non-const version of ourselves return const_cast(this)->m_RequestedSpatialRegionCache[frameNumber]; } template void VideoStream::SetFrameBufferedSpatialRegion(SizeValueType frameNumber, typename TFrameType::RegionType region) { m_BufferedSpatialRegionCache[frameNumber] = region; // If the frame is currently buffered, set the actual frame's region SizeValueType bufStart = m_BufferedTemporalRegion.GetFrameStart(); SizeValueType bufDur = m_BufferedTemporalRegion.GetFrameDuration(); if (frameNumber >= bufStart && frameNumber < bufStart + bufDur) { FrameType * frame = this->GetFrame(frameNumber); frame->SetBufferedRegion(region); } } template const typename TFrameType::RegionType & VideoStream::GetFrameBufferedSpatialRegion(SizeValueType frameNumber) const { // It seems that std::map's [] operator isn't const correct, so we need to // access this member from an non-const version of ourselves return const_cast(this)->m_BufferedSpatialRegionCache[frameNumber]; } template void VideoStream::SetFrameSpacing(SizeValueType frameNumber, typename TFrameType::SpacingType spacing) { // Make sure spacing is non-zero for (unsigned int i = 0; i < FrameType::ImageDimension; ++i) { if (spacing[i] == 0.0) { itkExceptionMacro("Zero spacing is not allowed for any dimension: Spacing is " << spacing); } } m_SpacingCache[frameNumber] = spacing; // If the frame is currently buffered, set the actual frame's spacing SizeValueType bufStart = m_BufferedTemporalRegion.GetFrameStart(); SizeValueType bufDur = m_BufferedTemporalRegion.GetFrameDuration(); if (frameNumber >= bufStart && frameNumber < bufStart + bufDur) { FrameType * frame = this->GetFrame(frameNumber); frame->SetSpacing(spacing); } } template const typename TFrameType::SpacingType & VideoStream::GetFrameSpacing(SizeValueType frameNumber) const { // It seems that std::map's [] operator isn't const correct, so we need to // access this member from an non-const version of ourselves return const_cast(this)->m_SpacingCache[frameNumber]; } template void VideoStream::SetFrameOrigin(SizeValueType frameNumber, typename TFrameType::PointType origin) { m_OriginCache[frameNumber] = origin; // If the frame is currently buffered, set the actual frame's spacing SizeValueType bufStart = m_BufferedTemporalRegion.GetFrameStart(); SizeValueType bufDur = m_BufferedTemporalRegion.GetFrameDuration(); if (frameNumber >= bufStart && frameNumber < bufStart + bufDur) { FrameType * frame = this->GetFrame(frameNumber); frame->SetOrigin(origin); } } template const typename TFrameType::PointType & VideoStream::GetFrameOrigin(SizeValueType frameNumber) const { // It seems that std::map's [] operator isn't const correct, so we need to // access this member from an non-const version of ourselves return const_cast(this)->m_OriginCache[frameNumber]; } template void VideoStream::SetFrameDirection(SizeValueType frameNumber, typename TFrameType::DirectionType direction) { // Determinant is non-zero if (itk::Math::abs(vnl_determinant(direction.GetVnlMatrix())) <= itk::Math::eps) { itkExceptionMacro("Bad direction, determinant is 0. Direction is " << direction); } m_DirectionCache[frameNumber] = direction; // If the frame is currently buffered, set the actual frame's spacing SizeValueType bufStart = m_BufferedTemporalRegion.GetFrameStart(); SizeValueType bufDur = m_BufferedTemporalRegion.GetFrameDuration(); if (frameNumber >= bufStart && frameNumber < bufStart + bufDur) { FrameType * frame = this->GetFrame(frameNumber); frame->SetDirection(direction); } } template const typename TFrameType::DirectionType & VideoStream::GetFrameDirection(SizeValueType frameNumber) const { // It seems that std::map's [] operator isn't const correct, so we need to // access this member from an non-const version of ourselves return const_cast(this)->m_DirectionCache[frameNumber]; } template void VideoStream::SetFrameNumberOfComponentsPerPixel(SizeValueType frameNumber, NumberOfComponentsPerPixelType n) { m_NumberOfComponentsPerPixelCache[frameNumber] = n; // If the frame is currently buffered, set the actual frame's region SizeValueType bufStart = m_BufferedTemporalRegion.GetFrameStart(); SizeValueType bufDur = m_BufferedTemporalRegion.GetFrameDuration(); if (frameNumber >= bufStart && frameNumber < bufStart + bufDur) { FrameType * frame = this->GetFrame(frameNumber); frame->SetNumberOfComponentsPerPixel(n); } } template auto VideoStream::GetFrameNumberOfComponentsPerPixel(SizeValueType frameNumber) const -> const NumberOfComponentsPerPixelType & { return const_cast(this)->m_NumberOfComponentsPerPixelCache[frameNumber]; } template void VideoStream::SetFrameBuffer(typename VideoStream::BufferType * buffer) { // We reinterpret the buffer to match TemporalDataObject's buffer type. We // assume that any tampering with the internal buffer will use our BufferType // so this will be safe. auto * castBuffer = reinterpret_cast(buffer); if (m_DataObjectBuffer != castBuffer) { m_DataObjectBuffer = castBuffer; this->Modified(); } } template void VideoStream::SetMinimumBufferSize(SizeValueType minimumNumberOfFrames) { // If we don't have enough buffer space to handle the number of requested // frames, we need to resize the ring buffer. Just resizing can cause data to // be in the wrong place. For example if the head of the buffer is at index 0 // and the buffer has 3 slots, setting frame number 3 will actually place the // data into slot 0. If we then resize the buffer to have 4 slots, the data // for frame 3 will live in slot 0 even though a request for frame 3 will // return the data from the newly created slot 3. To circumvent this problem, // we move the buffered data to the proper indices in the ring buffer after // resizing. if (m_DataObjectBuffer->GetNumberOfBuffers() < minimumNumberOfFrames) { // Save the indices of all frames in the currently buffered region const SizeValueType bufferedStart = m_BufferedTemporalRegion.GetFrameStart(); const SizeValueType bufferedDuration = m_BufferedTemporalRegion.GetFrameDuration(); std::vector frames(bufferedDuration - bufferedStart, nullptr); for (SizeValueType i = bufferedStart; i < bufferedStart + bufferedDuration; ++i) { frames[i - bufferedStart] = m_DataObjectBuffer->GetBufferContents(i); } // Resize the ring buffer m_DataObjectBuffer->SetNumberOfBuffers(minimumNumberOfFrames); // Move previously buffered data to the locations where their frame numbers now map for (SizeValueType i = bufferedStart; i < bufferedStart + bufferedDuration; ++i) { m_DataObjectBuffer->SetBufferContents(i, frames[i - bufferedStart]); } } } template void VideoStream::InitializeEmptyFrames() { // If we don't have any frames requested, just return SizeValueType numFrames = m_RequestedTemporalRegion.GetFrameDuration(); if (numFrames == 0) { return; } // Safely expand the ring buffer if necessary this->SetMinimumBufferSize(numFrames); // Go through the number of required frames and make sure none are empty SizeValueType startFrame = m_RequestedTemporalRegion.GetFrameStart(); for (SizeValueType i = startFrame; i < startFrame + numFrames; ++i) { if (!m_DataObjectBuffer->BufferIsFull(i)) { FramePointer newFrame = FrameType::New(); FrameType * newFrameRawPointer = newFrame.GetPointer(); typename BufferType::ElementPointer element = dynamic_cast(newFrameRawPointer); m_DataObjectBuffer->SetBufferContents(i, element); } // Check to see if any cached meta data exists and if it does, assign it if (m_LargestPossibleSpatialRegionCache.find(i) != m_LargestPossibleSpatialRegionCache.end()) { this->GetFrame(i)->SetLargestPossibleRegion(m_LargestPossibleSpatialRegionCache[i]); } if (m_RequestedSpatialRegionCache.find(i) != m_RequestedSpatialRegionCache.end()) { this->GetFrame(i)->SetRequestedRegion(m_RequestedSpatialRegionCache[i]); } if (m_BufferedSpatialRegionCache.find(i) != m_BufferedSpatialRegionCache.end()) { this->GetFrame(i)->SetBufferedRegion(m_BufferedSpatialRegionCache[i]); } if (m_SpacingCache.find(i) != m_SpacingCache.end()) { this->GetFrame(i)->SetSpacing(m_SpacingCache[i]); } if (m_OriginCache.find(i) != m_OriginCache.end()) { this->GetFrame(i)->SetOrigin(m_OriginCache[i]); } if (m_DirectionCache.find(i) != m_DirectionCache.end()) { this->GetFrame(i)->SetDirection(m_DirectionCache[i]); } if (m_NumberOfComponentsPerPixelCache.find(i) != m_NumberOfComponentsPerPixelCache.end()) { this->GetFrame(i)->SetNumberOfComponentsPerPixel(m_NumberOfComponentsPerPixelCache[i]); } } } template void VideoStream::SetFrame(SizeValueType frameNumber, FramePointer frame) { auto * dataObjectRawPointer = dynamic_cast(frame.GetPointer()); typename BufferType::ElementPointer dataObject = dataObjectRawPointer; m_DataObjectBuffer->SetBufferContents(frameNumber, dataObject); // Cache the meta data m_LargestPossibleSpatialRegionCache[frameNumber] = frame->GetLargestPossibleRegion(); m_RequestedSpatialRegionCache[frameNumber] = frame->GetRequestedRegion(); m_BufferedSpatialRegionCache[frameNumber] = frame->GetBufferedRegion(); m_SpacingCache[frameNumber] = frame->GetSpacing(); m_OriginCache[frameNumber] = frame->GetOrigin(); m_DirectionCache[frameNumber] = frame->GetDirection(); } template auto VideoStream::GetFrame(SizeValueType frameNumber) -> FrameType * { // Fetch the frame typename BufferType::ElementPointer element = m_DataObjectBuffer->GetBufferContents(frameNumber); FramePointer frame = dynamic_cast(element.GetPointer()); return frame; } template auto VideoStream::GetFrame(SizeValueType frameNumber) const -> const FrameType * { typename BufferType::ElementPointer element = m_DataObjectBuffer->GetBufferContents(frameNumber); FrameConstPointer frame = dynamic_cast(element.GetPointer()); return frame; } template void VideoStream::Graft(const DataObject * data) { // Call TemporalDataObject's Graft implementation Superclass::Graft(data); if (data) { // Attempt to cast to a VideoStream const auto * videoData = dynamic_cast(data); if (!videoData) { itkExceptionMacro("itk::VideoStream::Graft() cannot cast " << typeid(data).name() << " to " << typeid(const Self *).name()); } // Copy the meta data caches this->SetLargestPossibleSpatialRegionCache(videoData->GetLargestPossibleSpatialRegionCache()); this->SetRequestedSpatialRegionCache(videoData->GetRequestedSpatialRegionCache()); this->SetBufferedSpatialRegionCache(videoData->GetBufferedSpatialRegionCache()); this->SetSpacingCache(videoData->GetSpacingCache()); this->SetOriginCache(videoData->GetOriginCache()); this->SetDirectionCache(videoData->GetDirectionCache()); // Copy the frame buffer this->SetFrameBuffer(const_cast(videoData->GetFrameBuffer())); } } template void VideoStream::SetAllLargestPossibleSpatialRegions(typename TFrameType::RegionType region) { SizeValueType numFrames = m_LargestPossibleTemporalRegion.GetFrameDuration(); SizeValueType startFrame = m_LargestPossibleTemporalRegion.GetFrameStart(); // If the largest region is infinite, use the largest of the requested or // buffered region if (numFrames == ITK_INFINITE_FRAME_DURATION) { SizeValueType bufEnd = m_BufferedTemporalRegion.GetFrameStart() + m_BufferedTemporalRegion.GetFrameDuration(); SizeValueType reqEnd = m_RequestedTemporalRegion.GetFrameStart() + m_RequestedTemporalRegion.GetFrameDuration(); (bufEnd > reqEnd) ? (numFrames = bufEnd) : (numFrames = reqEnd); } // Go through the number of required frames, making sure none are empty and // setting the region for (SizeValueType i = startFrame; i < startFrame + numFrames; ++i) { this->SetFrameLargestPossibleSpatialRegion(i, region); } } template void VideoStream::SetAllRequestedSpatialRegions(typename TFrameType::RegionType region) { SizeValueType numFrames = m_LargestPossibleTemporalRegion.GetFrameDuration(); SizeValueType startFrame = m_LargestPossibleTemporalRegion.GetFrameStart(); // If the largest region is infinite, use the largest of the requested or // buffered region if (numFrames == ITK_INFINITE_FRAME_DURATION) { SizeValueType bufEnd = m_BufferedTemporalRegion.GetFrameStart() + m_BufferedTemporalRegion.GetFrameDuration(); SizeValueType reqEnd = m_RequestedTemporalRegion.GetFrameStart() + m_RequestedTemporalRegion.GetFrameDuration(); (bufEnd > reqEnd) ? (numFrames = bufEnd) : (numFrames = reqEnd); } // Go through the number of required frames, making sure none are empty and // setting the region for (SizeValueType i = startFrame; i < startFrame + numFrames; ++i) { this->SetFrameRequestedSpatialRegion(i, region); } } template void VideoStream::SetAllBufferedSpatialRegions(typename TFrameType::RegionType region) { SizeValueType numFrames = m_LargestPossibleTemporalRegion.GetFrameDuration(); SizeValueType startFrame = m_LargestPossibleTemporalRegion.GetFrameStart(); // If the largest region is infinite, use the largest of the requested or // buffered region if (numFrames == ITK_INFINITE_FRAME_DURATION) { SizeValueType bufEnd = m_BufferedTemporalRegion.GetFrameStart() + m_BufferedTemporalRegion.GetFrameDuration(); SizeValueType reqEnd = m_RequestedTemporalRegion.GetFrameStart() + m_RequestedTemporalRegion.GetFrameDuration(); (bufEnd > reqEnd) ? (numFrames = bufEnd) : (numFrames = reqEnd); } // Go through the number of required frames, making sure none are empty and // setting the region for (SizeValueType i = startFrame; i < startFrame + numFrames; ++i) { this->SetFrameBufferedSpatialRegion(i, region); } } template void VideoStream::SetAllFramesSpacing(typename TFrameType::SpacingType spacing) { SizeValueType numFrames = m_LargestPossibleTemporalRegion.GetFrameDuration(); SizeValueType startFrame = m_LargestPossibleTemporalRegion.GetFrameStart(); // If the largest region is infinite, use the largest of the requested or // buffered region if (numFrames == ITK_INFINITE_FRAME_DURATION) { SizeValueType bufEnd = m_BufferedTemporalRegion.GetFrameStart() + m_BufferedTemporalRegion.GetFrameDuration(); SizeValueType reqEnd = m_RequestedTemporalRegion.GetFrameStart() + m_RequestedTemporalRegion.GetFrameDuration(); (bufEnd > reqEnd) ? (numFrames = bufEnd) : (numFrames = reqEnd); } // Go through the number of required frames, making sure none are empty and // setting the region for (SizeValueType i = startFrame; i < startFrame + numFrames; ++i) { this->SetFrameSpacing(i, spacing); } } template void VideoStream::SetAllFramesOrigin(typename TFrameType::PointType origin) { SizeValueType numFrames = m_LargestPossibleTemporalRegion.GetFrameDuration(); SizeValueType startFrame = m_LargestPossibleTemporalRegion.GetFrameStart(); // If the largest region is infinite, use the largest of the requested or // buffered region if (numFrames == ITK_INFINITE_FRAME_DURATION) { SizeValueType bufEnd = m_BufferedTemporalRegion.GetFrameStart() + m_BufferedTemporalRegion.GetFrameDuration(); SizeValueType reqEnd = m_RequestedTemporalRegion.GetFrameStart() + m_RequestedTemporalRegion.GetFrameDuration(); (bufEnd > reqEnd) ? (numFrames = bufEnd) : (numFrames = reqEnd); } // Go through the number of required frames, making sure none are empty and // setting the region for (SizeValueType i = startFrame; i < startFrame + numFrames; ++i) { this->SetFrameOrigin(i, origin); } } template void VideoStream::SetAllFramesDirection(typename TFrameType::DirectionType direction) { SizeValueType numFrames = m_LargestPossibleTemporalRegion.GetFrameDuration(); SizeValueType startFrame = m_LargestPossibleTemporalRegion.GetFrameStart(); // If the largest region is infinite, use the largest of the requested or // buffered region if (numFrames == ITK_INFINITE_FRAME_DURATION) { SizeValueType bufEnd = m_BufferedTemporalRegion.GetFrameStart() + m_BufferedTemporalRegion.GetFrameDuration(); SizeValueType reqEnd = m_RequestedTemporalRegion.GetFrameStart() + m_RequestedTemporalRegion.GetFrameDuration(); (bufEnd > reqEnd) ? (numFrames = bufEnd) : (numFrames = reqEnd); } // Go through the number of required frames, making sure none are empty and // setting the region for (SizeValueType i = startFrame; i < startFrame + numFrames; ++i) { this->SetFrameDirection(i, direction); } } template void VideoStream::SetAllFramesNumberOfComponentsPerPixel(NumberOfComponentsPerPixelType n) { SizeValueType numFrames = m_LargestPossibleTemporalRegion.GetFrameDuration(); SizeValueType startFrame = m_LargestPossibleTemporalRegion.GetFrameStart(); // If the largest region is infinite, use the largest of the requested or // buffered region if (numFrames == ITK_INFINITE_FRAME_DURATION) { SizeValueType bufEnd = m_BufferedTemporalRegion.GetFrameStart() + m_BufferedTemporalRegion.GetFrameDuration(); SizeValueType reqEnd = m_RequestedTemporalRegion.GetFrameStart() + m_RequestedTemporalRegion.GetFrameDuration(); (bufEnd > reqEnd) ? (numFrames = bufEnd) : (numFrames = reqEnd); } // Go through the number of required frames, making sure none are empty and // setting the region for (SizeValueType i = startFrame; i < startFrame + numFrames; ++i) { this->SetFrameNumberOfComponentsPerPixel(i, n); } } template void VideoStream::Allocate() { SizeValueType numFrames = m_BufferedTemporalRegion.GetFrameDuration(); if (m_DataObjectBuffer->GetNumberOfBuffers() < numFrames) { itkExceptionMacro("itk::VideoStream::SetAllLargestPossibleSpatialRegions " "not enough frame buffers available. Call InitializeEmptyFrames " "to prepare the frame buffer correctly."); } // Go through the number of required frames, making sure none are empty and // allocating them. We start at 1 and move forwards because frames will be // added using AppendFrame which first moves the Head forward, then adds the // frame for (SizeValueType i = 1; i <= numFrames; ++i) { if (!m_DataObjectBuffer->BufferIsFull(i)) { itkExceptionMacro("itk::VideoStream::SetAllLargestPossibleSpatialRegions " "empty frame buffer found at offset " << i << ". Call " "InitializeEmptyFrames to prepare the frame buffer correctly."); } FrameType * frame = dynamic_cast(m_DataObjectBuffer->GetBufferContents(i).GetPointer()); if (!frame) { itkExceptionMacro("itk::VideoStream::SetAllLargestPossibleSpatialRegions " "could not cast frame " << i << " to the correct type."); } frame->Allocate(); } } } // end namespace itk #endif