/* * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES) * Copyright (C) 2007-2012 Institut Mines Telecom / Telecom Bretagne * * 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 otbSOM_hxx #define otbSOM_hxx #include "otbSOM.h" #include "itkImageRegionIteratorWithIndex.h" #include "itkFixedArray.h" #include "otbMacro.h" #include "itkImageRegionIterator.h" #include "itkMersenneTwisterRandomVariateGenerator.h" namespace otb { /** * Constructor */ template SOM::SOM() { this->SetNumberOfRequiredInputs(0); this->SetNumberOfRequiredOutputs(1); m_MapSize.Fill(10); m_NumberOfIterations = 10; m_BetaInit = 1.0; m_BetaEnd = 0.2; m_NeighborhoodSizeInit.Fill(3); m_MinWeight = static_cast(0.0); m_MaxWeight = static_cast(128.0); m_RandomInit = false; m_Seed = 123574651; } /** * Destructor */ template SOM::~SOM() { } /** * Update the output map with a new sample. * \param sample The new sample to learn, * \param beta The learning coefficient, * \param radius The radius of the nieghbourhood. */ template void SOM::UpdateMap(const NeuronType& sample, double beta, SizeType& radius) { // output map pointer MapPointerType map = this->GetOutput(0); // typedefs typedef itk::ImageRegionIteratorWithIndex IteratorType; typedef itk::FixedArray FixedArrayIndexType; typedef itk::Statistics::EuclideanDistanceMetric DistanceType; typename DistanceType::Pointer distance = DistanceType::New(); // winner index in the map IndexType position = map->GetWinner(sample); NeuronType winner = map->GetPixel(position); // Local neighborhood definition RegionType localRegion; IndexType localIndex = position - radius; SizeType localSize; for (unsigned int i = 0; i < MapType::ImageDimension; ++i) { localSize[i] = 2 * radius[i] + 1; } localRegion.SetIndex(localIndex); localRegion.SetSize(localSize); localRegion.Crop(map->GetLargestPossibleRegion()); IteratorType it(map, localRegion); // Walk through the map, and evolve each neuron depending on its // distance to the winner. for (it.GoToBegin(); !it.IsAtEnd(); ++it) { NeuronType tempNeuron = it.Get(); NeuronType newNeuron(tempNeuron.Size()); FixedArrayIndexType positionFA, indexFA; positionFA[0] = position[0]; positionFA[1] = position[1]; indexFA[0] = it.GetIndex()[0]; indexFA[1] = it.GetIndex()[1]; double tempBeta = beta / (1 + distance->Evaluate(positionFA, indexFA)); for (unsigned int i = 0; i < newNeuron.Size(); ++i) { newNeuron[i] = tempNeuron[i] + static_cast((sample[i] - tempNeuron[i]) * tempBeta); } it.Set(newNeuron); } } /** * Step one iteration. */ template void SOM::Step(unsigned int currentIteration) { // Compute the new learning coefficient double newBeta = m_BetaFunctor(currentIteration, m_NumberOfIterations, m_BetaInit, m_BetaEnd); // Compute the new neighborhood size SizeType newSize = m_NeighborhoodSizeFunctor(currentIteration, m_NumberOfIterations, m_NeighborhoodSizeInit); // update the neurons map with each example of the training set. otbMsgDebugMacro(<< "Beta: " << newBeta << ", radius: " << newSize); for (typename ListSampleType::Iterator it = m_ListSample->Begin(); it != m_ListSample->End(); ++it) { UpdateMap(it.GetMeasurementVector(), newBeta, newSize); } } /** * Output information redefinition */ template void SOM::GenerateOutputInformation() { Superclass::GenerateOutputInformation(); this->GetOutput()->SetNumberOfComponentsPerPixel(m_ListSample->GetMeasurementVectorSize()); IndexType index; index.Fill(0); RegionType region; region.SetIndex(index); region.SetSize(this->GetMapSize()); this->GetOutput()->SetRegions(region); } /** * Output redefinition */ template void SOM::AllocateOutputs() { if (this->GetNumberOfOutputs() != 1) itkExceptionMacro(<< "Number of output image should be 1"); // output neuron map fill MapPointerType map = this->GetOutput(0); map->Allocate(); } /** * Main computation method */ template void SOM::GenerateData(void) { this->AllocateOutputs(); this->BeforeThreadedGenerateData(); MapPointerType map = this->GetOutput(0); if (m_RandomInit) { typedef itk::Statistics::MersenneTwisterRandomVariateGenerator GeneratorType; typedef itk::ImageRegionIterator IteratorType; GeneratorType::Pointer generator = GeneratorType::New(); generator->Initialize(m_Seed); NeuronType neuronInit(m_ListSample->GetMeasurementVectorSize()); IteratorType it(map, map->GetLargestPossibleRegion()); for (it.GoToBegin(); !it.IsAtEnd(); ++it) { for (unsigned int i = 0; i < neuronInit.Size(); ++i) { neuronInit[i] = static_cast(generator->GetUniformVariate(static_cast(m_MinWeight), static_cast(m_MaxWeight))); } it.Set(neuronInit); } } else { NeuronType neuronInit(m_ListSample->GetMeasurementVectorSize()); neuronInit.Fill(m_MaxWeight); map->FillBuffer(neuronInit); } // Step through the iterations for (unsigned int i = 0; i < m_NumberOfIterations; ++i) { // otbMsgDebugMacro(<<"Step "<AfterThreadedGenerateData(); } /** *PrintSelf method */ template void SOM::PrintSelf(std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); } } // end namespace otb #endif