otbPixelValue.cxx 10.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Copyright (C) 2005-2017 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.
 */
20 21 22 23 24

#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"

#include "otbMultiChannelExtractROI.h"
25
#include "otbGenericRSTransform.h"
26 27 28 29 30 31

namespace otb
{
namespace Wrapper
{

32
class PixelValue : public Application
33 34 35
{
public:
  /** Standard class typedefs. */
36
  typedef PixelValue                    Self;
37 38 39 40 41
  typedef Application                   Superclass;
  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  typedef otb::MultiChannelExtractROI<FloatVectorImageType::InternalPixelType,
42
              FloatVectorImageType::InternalPixelType> ExtractROIFilterType;
43

44
  typedef otb::GenericRSTransform<>  RSTransformType;
45 46 47
  /** Standard macro */
  itkNewMacro(Self);

48
  itkTypeMacro(PixelValue, otb::Application);
49 50

private:
51
  void DoInit() override
52 53 54 55 56
  {
    SetName("PixelValue");
    SetDescription("Get the value of a pixel.");

    // Documentation
57
    SetDocName("Pixel Value");
58
    SetDocLongDescription("This application gives the value of a selected "
Antoine Regimbeau's avatar
Antoine Regimbeau committed
59
      "pixel. There are three ways to designate a pixel, with its index, "
60 61 62
      "its physical coordinate (in the physical space attached to the image), "
      "and with geographical coordinate system. Coordinates will be "
      "interpreted differently depending on which mode is chosen.");
63 64 65 66
    SetDocLimitations("None");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso(" ");

67 68
    AddDocTag(Tags::Manip);
    AddDocTag(Tags::Coordinates);
69

70 71
    AddParameter(ParameterType_InputImage , "in", "Input Image");
    SetParameterDescription("in" , "Input image");
72

73
    AddParameter(ParameterType_Float , "coordx" , "X coordinate" );
74 75 76
    SetParameterDescription("coordx" ,
          "This will be the X coordinate interpreted depending on the "
          "chosen mode");
77
    AddParameter(ParameterType_Float , "coordy" , "Y coordinate" );
78 79 80
    SetParameterDescription("coordy" ,
          "This will be the Y coordinate interpreted depending on the "
          "chosen mode");
81

82
    AddParameter(ParameterType_Choice , "mode" ,
83
          "Coordinate system used to designate the pixel");
84
    SetParameterDescription( "mode" ,
Antoine Regimbeau's avatar
Antoine Regimbeau committed
85
          "Different modes can be selected, default mode is Index.");
86
    AddChoice( "mode.index" , "Index");
87
    SetParameterDescription( "mode.index" ,
Antoine Regimbeau's avatar
Antoine Regimbeau committed
88
          "This mode uses the given coordinates as index to locate the pixel.");
89
    AddChoice( "mode.physical" , "Image physical space");
90
    SetParameterDescription( "mode.physical" ,
Antoine Regimbeau's avatar
Antoine Regimbeau committed
91
          "This mode interprets the given coordinates in the image "
92
          "physical space.");
93
    AddChoice( "mode.epsg" , "EPSG coordinates");
94
    SetParameterDescription( "mode.epsg" ,
Antoine Regimbeau's avatar
Antoine Regimbeau committed
95
          "This mode interprets the given coordinates in the specified "
96
          "geographical coordinate system by the EPSG code.");
97

98 99
    AddParameter(ParameterType_Int , "mode.epsg.code" , "EPSG code");
    SetParameterDescription("mode.epsg.code" ,
100
          "This code is used to define a geographical coordinate system. "
Victor Poughon's avatar
Victor Poughon committed
101
          "If no system is specified, WGS84 (EPSG: 4326) is used by default.");
102
    MandatoryOff("mode.epsg.code");
103 104

    AddParameter(ParameterType_ListView,"cl","Channels");
OTB Bot's avatar
STYLE  
OTB Bot committed
105
    SetParameterDescription("cl","Displayed channels");
106 107 108 109 110 111 112 113 114 115 116
    MandatoryOff("cl");

    AddParameter(ParameterType_String,"value","Pixel Value");
    SetParameterDescription("value", "Pixel radiometric value");
    SetParameterRole("value", Role_Output);

    // Doc example parameter settings
    SetDocExampleParameterValue("in", "QB_Toulouse_Ortho_XS.tif");
    SetDocExampleParameterValue("coordx", "50");
    SetDocExampleParameterValue("coordy", "100");
    SetDocExampleParameterValue("cl", "Channel1");
117

118
    SetOfficialDocLink();
119 120
  }

121
  void DoUpdateParameters() override
122 123 124
  {
    if ( HasValue("in") )
      {
125
      ExtractROIFilterType::InputImageType * inImage = GetParameterImage("in");
126

127 128 129 130 131 132 133 134 135 136
      // Update the values of the channels to be selected
      unsigned int nbComponents = inImage->GetNumberOfComponentsPerPixel();
      ClearChoices("cl");
      for (unsigned int idx = 0; idx < nbComponents; ++idx)
        {
        std::ostringstream key, item;
        key<<"cl.channel"<<idx+1;
        item<<"Channel"<<idx+1;
        AddChoice(key.str(), item.str());
        }
137 138
      }
  }
139

140
  std::string CreateBoundaryBox( const std::string & mode )
141 142 143
  {
    FloatVectorImageType::Pointer inImage = GetParameterImage("in");
    FloatVectorImageType::IndexType min , max;
144
    min.Fill(0);
145 146
    max[0] = inImage->GetLargestPossibleRegion().GetSize()[0] - 1;
    max[1] = inImage->GetLargestPossibleRegion().GetSize()[1] - 1;
147
    std::string boundaries[4];
148
    if (mode == "index")
149 150 151 152 153 154
      {
      boundaries[0] = std::to_string(max[0]);
      boundaries[1] = std::to_string(max[1]);
      boundaries[2] = std::to_string(min[0]);
      boundaries[3] = std::to_string(min[1]);
      }
155
    else if (mode == "physical")
156
      {
157
      itk::Point< float, 2 > minP(0) , maxP(0);
158 159 160 161 162 163 164
      inImage->TransformIndexToPhysicalPoint(min,minP);
      inImage->TransformIndexToPhysicalPoint(max,maxP);
      boundaries[0] = std::to_string(std::max(minP[0],maxP[0]));
      boundaries[1] = std::to_string(std::max(minP[1],maxP[1]));
      boundaries[2] = std::to_string(std::min(minP[0],maxP[0]));
      boundaries[3] = std::to_string(std::min(minP[1],maxP[1]));
      }
165
    else if (mode == "epsg")
166 167
      {
      RSTransformType::Pointer inverse = RSTransformType::New();
168
      if ( HasUserValue("mode.epsg.code") )
169
        {
170
        std::string wktFromEpsg =
171
          otb::GeoInformationConversion::ToWKT(GetParameterInt( "mode.epsg.code" ));
172 173 174 175 176
        inverse->SetOutputProjectionRef(wktFromEpsg);
        }
      inverse->SetInputKeywordList( inImage->GetImageKeywordlist() );
      inverse->SetInputProjectionRef( inImage->GetProjectionRef() );
      inverse->InstantiateTransform();
177
      itk::Point< float, 2 > minPOut(0) , maxPOut(0) , minP(0) , maxP(0);
178 179 180 181
      inImage->TransformIndexToPhysicalPoint(min,minP);
      inImage->TransformIndexToPhysicalPoint(max,maxP);
      minPOut = inverse->TransformPoint( minP );
      maxPOut = inverse->TransformPoint( maxP );
182 183 184 185
      boundaries[0] = std::to_string(std::max(minPOut[0],maxPOut[0]));
      boundaries[1] = std::to_string(std::max(minPOut[1],maxPOut[1]));
      boundaries[2] = std::to_string(std::min(minPOut[0],maxPOut[0]));
      boundaries[3] = std::to_string(std::min(minPOut[1],maxPOut[1]));
186
      }
187 188

    for (int i = 0 ; i<4 ; i++)
189
      {
190 191
      std::size_t coma = boundaries[i].find(".");
      if ( coma != std::string::npos )
192
        {
193
        std::size_t zero = boundaries[i].find_last_not_of("0");
194
        if ( zero != std::string::npos )
195 196 197
          boundaries[i].erase(zero + 1);
        else
          boundaries[i] = "0";
198
        }
199
      }
200

201 202 203 204
    std::string box = "";
    box += "["+boundaries[2]+" , "+boundaries[0]+"] x ";
    box += "["+boundaries[3]+" , "+boundaries[1]+"]";
    return box;
205 206
  }

207
  void DoExecute() override
208
  {
209
    std::string mode = GetParameterString( "mode" );
210
    FloatVectorImageType::Pointer inImage = GetParameterImage("in");
211 212
    FloatVectorImageType::IndexType id ;
    id.Fill(0);
213 214
    bool isPixelIn( false );
    if ( mode == "index" )
215 216 217
      {
      id[0] = static_cast< int >( GetParameterFloat( "coordx" ) );
      id[1] = static_cast< int >( GetParameterFloat( "coordy" ) );
218
      if (static_cast< unsigned int >( id[0] ) >=
219
                    inImage->GetLargestPossibleRegion().GetSize()[0]
220
       || static_cast< unsigned int >( id[1] ) >=
221
                    inImage->GetLargestPossibleRegion().GetSize()[1]
222 223
       || id[0] < 0 || id[1] < 0 )
        {
224
        id.Fill(0);
225 226 227 228 229 230 231 232
        isPixelIn = false;
        }
      else
        {
        isPixelIn = true;
        }
      }

233
    else if ( mode == "physical" )
234
      {
235
      itk::Point<float, 2> pixel(0);
236 237 238 239
      pixel[ 0 ] = GetParameterFloat( "coordx" );
      pixel[ 1 ] = GetParameterFloat( "coordy" );
      isPixelIn = inImage->TransformPhysicalPointToIndex(pixel,id);
      }
240

241
    else if ( mode == "epsg" )
242 243
      {
      RSTransformType::Pointer rsTransform = RSTransformType::New();
244
      if ( HasUserValue("mode.epsg.code") )
245
        {
246
        std::string wktFromEpsg =
247
          otb::GeoInformationConversion::ToWKT( GetParameterInt( "mode.epsg.code" ) );
248
        rsTransform->SetInputProjectionRef(wktFromEpsg);
249
        }
250 251 252
      rsTransform->SetOutputKeywordList( inImage->GetImageKeywordlist() );
      rsTransform->SetOutputProjectionRef( inImage->GetProjectionRef() );
      rsTransform->InstantiateTransform();
253
      itk::Point<float, 2> pixelIn(0) , pixelOut(0);
254 255 256 257 258 259
      pixelIn[ 0 ] = GetParameterFloat( "coordx" );
      pixelIn[ 1 ] = GetParameterFloat( "coordy" );
      rsTransform->InstantiateTransform();
      pixelOut = rsTransform->TransformPoint(pixelIn);
      isPixelIn = inImage->TransformPhysicalPointToIndex(pixelOut,id);
      }
260

261 262
    if ( !isPixelIn )
      {
263 264 265 266
      std::string why = "Accessible pixels are in ";
      why += CreateBoundaryBox( GetParameterString( "mode" ) );
      why += " for the selected mode.";
      otbAppLogFATAL(<<"Specified position out of bound.\n" + why);
267 268
      }

269 270 271
    ExtractROIFilterType::Pointer extractor = ExtractROIFilterType::New();
    extractor->SetInput(inImage);

272 273 274
    // Extract the channels if needed
    if ( GetParameterByKey("cl")->GetActive() )
      {
275
      for (unsigned int idx = 0; idx < GetSelectedItems("cl").size(); ++idx)
276 277 278 279
        {
        extractor->SetChannel(GetSelectedItems("cl")[idx] + 1 );
        }
      }
280
    FloatVectorImageType::SizeType size;
281
    size.Fill(1);
282 283 284 285 286
    FloatVectorImageType::RegionType region;
    region.SetSize(size);
    region.SetIndex(id);

    extractor->SetExtractionRegion(region);
287
    extractor->Update();
288

289 290 291
    // Display the pixel value
    id.Fill(0);
    std::ostringstream oss;
292
    oss << extractor->GetOutput()->GetPixel(id);
293
    SetParameterString("value", oss.str());
294
    //Display image information in the dedicated logger
295 296 297 298 299 300 301 302
    otbAppLogINFO( << oss.str() );
  }

};

}
}

303
OTB_APPLICATION_EXPORT(otb::Wrapper::PixelValue)