This tutorial demonstrates an important part of most Opticks plug-ins, accessing data in a raster cube. We'll build a plug-in which calculates some basic statistics over band 1 of a data cube. We'll see how to use DataAccessor and switchOnEncoding.h.
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 3" from the Tutorial toolbar to execute it.
namespace { template<typename T> void updateStatistics(T* pData, double& min, double& max, double& total) { min = std::min(min, static_cast<double>(*pData)); max = std::max(max, static_cast<double>(*pData)); total += *pData; } };
setAbortSupported(true);
pInArgList->addArg<RasterElement>(Executable::DataElementArg(), "Generate statistics for this raster element");
bool Tutorial3::getOutputSpecification(PlugInArgList*& pOutArgList) { pOutArgList = Service<PlugInManagerServices>()->getPlugInArgList(); VERIFY(pOutArgList != NULL); pOutArgList->addArg<double>("Minimum", "The minimum value"); pOutArgList->addArg<double>("Maximum", "The maximum value"); pOutArgList->addArg<unsigned int>("Count", "The number of pixels"); pOutArgList->addArg<double>("Mean", "The average value"); return true; }
RasterDataDescriptor* pDesc = static_cast<RasterDataDescriptor*>(pCube->getDataDescriptor());
FactoryResource<DataRequest> pRequest; DataAccessor pAcc = pCube->getDataAccessor(pRequest.release());
double min = std::numeric_limits<double>::max(); double max = -min; double total = 0.0; for (unsigned int row = 0; row < pDesc->getRowCount(); ++row)
if (isAborted()) { std::string msg = getName() + " has been aborted."; pStep->finalize(Message::Abort, msg); if (pProgress != NULL) { pProgress->updateProgress(msg, 0, ABORT); } return false; }
if (!pAcc.isValid()) { std::string msg = "Unable to access the cube data."; pStep->finalize(Message::Failure, msg); if (pProgress != NULL) { pProgress->updateProgress(msg, 0, ERRORS); } return false; }
if (pProgress != NULL)
{
pProgress->updateProgress("Calculating statistics", row * 100 / pDesc->getRowCount(), NORMAL);
}
for (unsigned int col = 0; col < pDesc->getColumnCount(); ++col)
{
switchOnEncoding(pDesc->getDataType(), updateStatistics, pAcc->getColumn(), min, max, total);
pAcc->nextColumn();
}
The switchOnEncoding() function takes an EncodingType and cases the void* returned from DataAccessorImpl::getColumn() into the appropriate data type for the specified EncodingType. It then calls the updateStatistics() function with the remaining arguments. This is a common pattern for accessing data in a raster cube. Finally, DataAccessorImpl::nextColumn() moves the DataAccessor's internal pointer to the next column.
pAcc->nextRow(); } unsigned int count = pDesc->getColumnCount() * pDesc->getRowCount(); double mean = total / count;
if (pProgress != NULL) { std::string msg = "Minimum value: " + StringUtilities::toDisplayString(min) + "\n" + "Maximum value: " + StringUtilities::toDisplayString(max) + "\n" + "Number of pixels: " + StringUtilities::toDisplayString(count) + "\n" + "Average: " + StringUtilities::toDisplayString(mean); pProgress->updateProgress(msg, 100, NORMAL); } pStep->addProperty("Minimum", min); pStep->addProperty("Maximum", max); pStep->addProperty("Count", count); pStep->addProperty("Mean", mean); pOutArgList->setPlugInArgValue("Minimum", &min); pOutArgList->setPlugInArgValue("Maximum", &max); pOutArgList->setPlugInArgValue("Count", &count); pOutArgList->setPlugInArgValue("Mean", &mean); pStep->finalize(); return true;