/* * 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 otbGreyLevelCooccurrenceIndexedList_hxx #define otbGreyLevelCooccurrenceIndexedList_hxx #include "otbGreyLevelCooccurrenceIndexedList.h" namespace otb { template GreyLevelCooccurrenceIndexedList::GreyLevelCooccurrenceIndexedList() : m_Size(), m_Symmetry(true), m_TotalFrequency(0), m_ClipBinsAtEnds(true), m_InputImageMinimum(0), m_InputImageMaximum(255) { } template void GreyLevelCooccurrenceIndexedList::Initialize(const unsigned int nbins, const PixelValueType min, const PixelValueType max, const bool symmetry) { PixelPairType lowerBound; PixelPairType upperBound; m_Size.Fill(nbins); m_InputImageMinimum = min; m_InputImageMaximum = max; lowerBound.Fill(min); upperBound.Fill(max + 1); m_Symmetry = symmetry; m_LookupArray = LookupArrayType(m_Size[0] * m_Size[1]); m_LookupArray.Fill(-1); m_TotalFrequency = 0; // adjust the sizes of min max value containers unsigned int dim; m_Min.resize(PixelPairSize); for (dim = 0; dim < PixelPairSize; dim++) { m_Min[dim].resize(m_Size[dim]); } m_Max.resize(PixelPairSize); for (dim = 0; dim < PixelPairSize; dim++) { m_Max[dim].resize(m_Size[dim]); } float interval; for (unsigned int i = 0; i < PixelPairSize; i++) { if (m_Size[i] > 0) { interval = static_cast(upperBound[i] - lowerBound[i]) / static_cast(m_Size[i]); // Set the min vector and max vector for (unsigned int j = 0; j < static_cast(m_Size[i] - 1); j++) { this->SetBinMin(i, j, (PixelValueType)(lowerBound[i] + ((float)j * interval))); this->SetBinMax(i, j, (PixelValueType)(lowerBound[i] + (((float)j + 1) * interval))); } this->SetBinMin(i, m_Size[i] - 1, (PixelValueType)(lowerBound[i] + (((float)m_Size[i] - 1) * interval))); this->SetBinMax(i, m_Size[i] - 1, (PixelValueType)(upperBound[i])); } } } template void GreyLevelCooccurrenceIndexedList::SetBinMin(const unsigned int dimension, const InstanceIdentifier nbin, PixelValueType min) { m_Min[dimension][nbin] = min; } template void GreyLevelCooccurrenceIndexedList::SetBinMax(const unsigned int dimension, const InstanceIdentifier nbin, PixelValueType max) { m_Max[dimension][nbin] = max; } template bool GreyLevelCooccurrenceIndexedList::GetIndex(const PixelPairType& pixelPair, IndexType& index) const { // now using something similar to binary search to find // index. unsigned int dim; int begin; int mid; int end; PixelValueType median; PixelValueType tempPixelValue; for (dim = 0; dim < PixelPairSize; dim++) { tempPixelValue = pixelPair[dim]; begin = 0; if (tempPixelValue < m_Min[dim][begin]) { // one of measurement is below the minimum // its ok if we extend the bins to infinity.. not ok if we don't if (!m_ClipBinsAtEnds) { index[dim] = (IndexValueType)0; continue; } else { // set an illegal value and return 0 index[dim] = (IndexValueType)m_Size[dim]; return false; } } end = m_Min[dim].size() - 1; if (tempPixelValue >= m_Max[dim][end]) { // one of measurement is above the maximum // its ok if we extend the bins to infinity.. not ok if we don't // Need to include the last endpoint in the last bin. if (!m_ClipBinsAtEnds || tempPixelValue == m_Max[dim][end]) { index[dim] = (IndexValueType)m_Size[dim] - 1; continue; } else { // set an illegal value and return 0 index[dim] = (IndexValueType)m_Size[dim]; return false; } } // Binary search for the bin where this measurement could be mid = (end + 1) / 2; median = m_Min[dim][mid]; while (true) { if (tempPixelValue < median) { end = mid - 1; } else if (tempPixelValue > median) { // test whether it is inside the current bin by comparing to the max of // this bin. if (tempPixelValue < m_Max[dim][mid] && tempPixelValue >= m_Min[dim][mid]) { index[dim] = mid; break; } // otherwise, continue binary search begin = mid + 1; } else { index[dim] = mid; break; } mid = begin + (end - begin) / 2; median = m_Min[dim][mid]; } // end of while } // end of for() return true; } template void GreyLevelCooccurrenceIndexedList::AddPixelPair(const PixelValueType& pixelvalue1, const PixelValueType& pixelvalue2) { if (pixelvalue1 < m_InputImageMinimum || pixelvalue1 > m_InputImageMaximum) { return; // don't put a pixel in the co-occurrence list if pixelvalue1 // is out-of-bounds. } if (pixelvalue2 < m_InputImageMinimum || pixelvalue2 > m_InputImageMaximum) { return; // don't put a pixel in the co-occurrence list if the pixelvalue2 // is out-of-bounds. } IndexType index; PixelPairType ppair(PixelPairSize); ppair[0] = pixelvalue1; ppair[1] = pixelvalue2; // Get Index of the given pixel pair; this->GetIndex(ppair, index); // Add the index and set/update the frequency of the pixel pair. if m_Symmetry // is true the index is swapped and added to vector again. this->AddPairToVector(index); if (m_Symmetry) { IndexValueType temp; temp = index[0]; index[0] = index[1]; index[1] = temp; this->AddPairToVector(index); } } template typename GreyLevelCooccurrenceIndexedList::RelativeFrequencyType GreyLevelCooccurrenceIndexedList::GetFrequency(IndexValueType i, IndexValueType j) { double frequency = 0; InstanceIdentifier instanceId = i * m_Size[0] + j; if (instanceId < m_LookupArray.size()) { int findex = m_LookupArray[instanceId]; if (findex > -1) frequency = m_Vector[findex].second / m_TotalFrequency; } return frequency; } template typename GreyLevelCooccurrenceIndexedList::RelativeFrequencyType GreyLevelCooccurrenceIndexedList::GetFrequency(IndexValueType i, IndexValueType j, const VectorType& vect) const { double frequency = 0; InstanceIdentifier instanceId = i * m_Size[0] + j; if (instanceId < m_LookupArray.size()) { int findex = m_LookupArray[instanceId]; if (findex > -1) frequency = vect[findex].second; } return frequency; } template typename GreyLevelCooccurrenceIndexedList::VectorType GreyLevelCooccurrenceIndexedList::GetVector() { return m_Vector; } template void GreyLevelCooccurrenceIndexedList::AddPairToVector(IndexType index) { InstanceIdentifier instanceId = 0; instanceId = index[1] * m_Size[0] + index[0]; int vindex = m_LookupArray[instanceId]; if (vindex < 0) { m_LookupArray[instanceId] = m_Vector.size(); CooccurrencePairType cooccur; cooccur = std::make_pair(index, 1); m_Vector.push_back(cooccur); } else { m_Vector[vindex].second++; } m_TotalFrequency = m_TotalFrequency + 1; } template void GreyLevelCooccurrenceIndexedList::PrintSelf(std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "Symmetry: " << this->m_Symmetry << std::endl; os << indent << "TotalFrequency: " << this->m_TotalFrequency << std::endl; os << indent << "Size: " << m_Size; os << indent << "CooccurrenceIndexedList: " << std::endl; typename VectorType::const_iterator it; for (it = m_Vector.begin(); it != m_Vector.end(); ++it) { std::cerr << "index=" << (*it).first << ", frequency=" << (*it).second << std::endl; } std::cerr << std::endl; } } // end namespace otb #endif