Tutorial 4 - Using AOIs

Files:

This tutorial will build on Tutorial 3 - Accessing cube data. We'll add an option to constrain processing to an AOI.

If you would like to run this tutorial as you follow along with the code, see Running Tutorials With Opticks. If you would like to build and experiment with this tutorial as you follow along with the code, see Building and Running Tutorial plug-ins. If you are running this tutorial in Opticks, you will need to select "Tutorial 4" from the Tutorial toolbar to execute it.

   if (isBatch())
   {
      pInArgList->addArg<AoiElement>("AOI", NULL, "The AOI to calculate statistics over");
   }
We are adding a new input argument for an AoiElement. The plug-in only provides this argument when running in batch mode.

   AoiElement* pAoi = NULL;
   if (isBatch())
   {
      pAoi = pInArgList->getPlugInArgValue<AoiElement>("AOI");
   }
This extracts the AOI argument if the plug-in is being executed in batch mode.

      Service<ModelServices> pModel;
      std::vector<DataElement*> pAois = pModel->getElements(pCube, TypeConverter::toString<AoiElement>());
This code gets a list of all the AoiElements which are children of the RasterElement. When a type string is required, TypeConverter will generate the correct string given a data type. This guarantees a compile time check for a correct type.

      if (!pAois.empty())
      {
         QStringList aoiNames("<none>");
         for (std::vector<DataElement*>::iterator it = pAois.begin(); it != pAois.end(); ++it)
         {
            aoiNames << QString::fromStdString((*it)->getName());
         }
         QString aoi = QInputDialog::getItem(Service<DesktopServices>()->getMainWidget(),
            "Select an AOI", "Select an AOI for processing", aoiNames);
         // select AOI
         if (aoi != "<none>")
         {
            std::string strAoi = aoi.toStdString();
            for (std::vector<DataElement*>::iterator it = pAois.begin(); it != pAois.end(); ++it)
            {
               if ((*it)->getName() == strAoi)
               {
                  pAoi = static_cast<AoiElement*>(*it);
                  break;
               }
            }
            if (pAoi == NULL)
            {
               std::string msg = "Invalid AOI.";
               pStep->finalize(Message::Failure, msg);
               if (pProgress != NULL)
               {
                  pProgress->updateProgress(msg, 0, ERRORS);
               }

               return false;
            }
         }
      }
   } // end if
We are creating a Qt string list of all the available AOI names including a placeholder for no AOI selection. A QInputDialog presents the user with an AOI choice. We find the chosen AOI with some validation.

   unsigned int startRow = 0;
   unsigned int startColumn = 0;
   unsigned int endRow = pDesc->getRowCount() - 1;
   unsigned int endColumn = pDesc->getColumnCount() - 1;
   const BitMask* pPoints = (pAoi == NULL) ? NULL : pAoi->getSelectedPoints();
   if (pPoints != NULL && !pPoints->isOutsideSelected())
   {
      int x1;
      int x2;
      int y1;
      int y2;
      pPoints->getMinimalBoundingBox(x1, y1, x2, y2);

      startRow = y1;
      endRow = y2;
      startColumn = x1;
      endColumn = x2;
   }
   pRequest->setRows(pDesc->getActiveRow(startRow), pDesc->getActiveRow(endRow));
   pRequest->setColumns(pDesc->getActiveColumn(startColumn), pDesc->getActiveColumn(endColumn));
If an AOI is chosen, we can be more efficient in accessing the cube data. We only need to loop over the AOI's bounding box. An AOI can be accessed as a bitmask. The bitmask can either represent selected pixels or unselected pixels. The BitMask::isOutsideSelected() method indicates if the bitmask is negated. If so, we need to loop over the entire image.

      for (unsigned int col = startColumn; col <= endColumn; ++col)
      {
         if (pPoints == NULL || pPoints->getPixel(col, row))
         {
            switchOnEncoding(pDesc->getDataType(), updateStatistics, pAcc->getColumn(), min, max, total);
            ++count;
            pAcc->nextColumn();
         }
      }
      pAcc->nextRow();
We only add the pixel to the statistics counters if it is masked by the AOI. We can ignore BitMask::isOutsideSelected() since BitMask::getPixel() already considers this.

The remainder of the file is unchanged from the previous tutorial.


Software Development Kit - Opticks 4.8.0 Build 15482