/* * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES) * * This file is part of Orfeo Toolbox * * https://www.orfeo-toolbox.org/ * * 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 otbMultiChannelExtractROI_hxx #define otbMultiChannelExtractROI_hxx #include "otbMultiChannelExtractROI.h" #include "itkImageRegionIterator.h" #include "itkObjectFactory.h" #include "itkExtractImageFilterRegionCopier.h" #include "itkProgressReporter.h" namespace otb { /** * */ template MultiChannelExtractROI::MultiChannelExtractROI() : ExtractROIBase, VectorImage>(), m_FirstChannel(0), m_LastChannel(0), m_ChannelsKind(0) { ClearChannels(); } /** * */ template void MultiChannelExtractROI::SetChannel(unsigned int channel) { if (m_ChannelsKind == 1) { itkExceptionMacro(<< "m_Channels already set using channels interval."); } m_Channels.push_back(channel); if (m_ChannelsKind == 0) { m_ChannelsKind = 2; } this->Modified(); } template void MultiChannelExtractROI::SetFirstChannel(unsigned int id) { if (m_ChannelsKind == 2) { itkExceptionMacro(<< "m_Channels already set using SetChannels method."); } m_FirstChannel = id; if (m_ChannelsKind == 0) { m_ChannelsKind = 1; } this->Modified(); } template void MultiChannelExtractROI::SetLastChannel(unsigned int id) { if (m_ChannelsKind == 2) { itkExceptionMacro(<< "m_Channels already set using SetChannels method."); } m_LastChannel = id; if (m_ChannelsKind == 0) { m_ChannelsKind = 1; } this->Modified(); } /** * */ template void MultiChannelExtractROI::ClearChannels(void) { m_FirstChannel = 0; m_LastChannel = 0; m_Channels.clear(); m_ChannelsKind = 0; m_ChannelsWorks.clear(); } /** * */ template void MultiChannelExtractROI::PrintSelf(std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); } template void MultiChannelExtractROI::ChannelsReInitialization() { // The following conditions can be gathered but we'd loose in comprehension m_ChannelsWorks.clear(); // First passage in the method: if (m_Channels.empty() == true) { // - User SetFirst/LastChannel() if (m_ChannelsKind == 1) { this->SetChannelsWorkWithLimits(); } else { // - User called SetChannels() if (m_Channels.empty() == true && m_ChannelsKind == 2) { m_ChannelsWorks = m_Channels; } } } // Second passage in the method: Update already donne else { // - User SetFirst/LastChannel() if (m_ChannelsKind == 1) { m_Channels.clear(); this->SetChannelsWorkWithLimits(); } else { // - User called SetChannels() if (m_ChannelsKind == 2) { m_ChannelsWorks = m_Channels; } } } } template void MultiChannelExtractROI::SetChannelsWorkWithLimits() { if ((m_FirstChannel == 0) || (m_LastChannel == 0)) { itkExceptionMacro(<< "otb::ExtractImageFilter::GenerateOutputInformation " << "Channels must reside into [1...] " << typeid(itk::ImageBase*).name()); } if (m_FirstChannel > m_LastChannel) { itkExceptionMacro(<< "otb::ExtractImageFilter::GenerateOutputInformation " << "FirstChannel is greater than LastChannel" << typeid(itk::ImageBase*).name()); } for (unsigned int channel = m_FirstChannel; channel <= m_LastChannel; channel++) { m_ChannelsWorks.push_back(channel); } m_Channels = m_ChannelsWorks; } /** * ExtractImageFilter can produce an image which is a different resolution * than its input image. As such, ExtractImageFilter needs to provide an * implementation for GenerateOutputInformation() in order to inform * the pipeline execution model. The original documentation of this * method is below. * * \sa ProcessObject::GenerateOutputInformaton() */ template void MultiChannelExtractROI::GenerateOutputInformation() { // Call to the superclass implementation Superclass::GenerateOutputInformation(); this->ChannelsReInitialization(); typename Superclass::InputImageConstPointer inputPtr = this->GetInput(); typename Superclass::OutputImagePointer outputPtr = this->GetOutput(); unsigned int nbComponentsPerPixel = inputPtr->GetNumberOfComponentsPerPixel(); if (m_ChannelsKind != 0) { // Test if the asked channels index exists in the input image ChannelsType m_BadChannels; m_BadChannels.clear(); for (unsigned int i = 0; i < m_ChannelsWorks.size(); ++i) { if ((m_ChannelsWorks[i] < 1) || (m_ChannelsWorks[i] > nbComponentsPerPixel)) { bool isInsideBadChannels = false; for (unsigned int j = 0; j < m_BadChannels.size(); ++j) { if (m_BadChannels[j] == m_ChannelsWorks[i]) isInsideBadChannels = true; } if (!isInsideBadChannels) m_BadChannels.push_back(m_ChannelsWorks[i]); } } if (m_BadChannels.empty() == false) { std::ostringstream oss; oss << "otb::ExtractImageFilter::GenerateOutputInformation : "; oss << "Channel(s) [ "; for (unsigned int i = 0; i < m_BadChannels.size(); ++i) { oss << m_BadChannels[i] << " "; } oss << "] not authorized."; oss << " Each channel index has to be in [1," << nbComponentsPerPixel << "]."; itkExceptionMacro(<< oss.str().c_str()); } nbComponentsPerPixel = m_ChannelsWorks.size(); } // initialize the number of channels of the output image outputPtr->SetNumberOfComponentsPerPixel(nbComponentsPerPixel); } template void MultiChannelExtractROI::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId) { itkDebugMacro(<< "Actually executing"); // Get the input and output pointers typename Superclass::InputImageConstPointer inputPtr = this->GetInput(); typename Superclass::OutputImagePointer outputPtr = this->GetOutput(); // support progress methods/callbacks itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); // Define the portion of the input to walk for this thread InputImageRegionType inputRegionForThread; this->CallCopyOutputRegionToInputRegion(inputRegionForThread, outputRegionForThread); // Define the iterators. typedef itk::ImageRegionIterator OutputIterator; typedef itk::ImageRegionConstIterator InputIterator; OutputIterator outIt(outputPtr, outputRegionForThread); InputIterator inIt(inputPtr, inputRegionForThread); outIt.GoToBegin(); inIt.GoToBegin(); // if default behaviour if (m_ChannelsKind == 0) { // walk the output region, and sample the input image while (!outIt.IsAtEnd()) { outIt.Set(inIt.Get()); ++outIt; ++inIt; progress.CompletedPixel(); } } // Specific behaviour else { // for each channel to process unsigned int channelIn(0); unsigned int channelOut(0); unsigned int nbChannels(0); InputImagePixelType pixelInput; while (!outIt.IsAtEnd()) { OutputImagePixelType pixelOutput; pixelOutput.Reserve(outputPtr->GetVectorLength()); pixelInput = inIt.Get(); channelOut = 0; for (nbChannels = 0; nbChannels < m_ChannelsWorks.size(); ++nbChannels) { channelIn = m_ChannelsWorks[nbChannels] - 1; pixelOutput[channelOut] = static_cast(pixelInput[channelIn]); channelOut++; } outIt.Set(pixelOutput); ++outIt; ++inIt; progress.CompletedPixel(); } } } } // end namespace otb #endif