This tutorial will demonstrate how to randomly access data in a raster element and how to create a new raster element while performing an edge detection algorithm. We'll create a plug-in which performs edge detection and returns a RasterElement with the edge detected data.
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 5" from the Tutorial toolbar to execute it.
This tutorial is distinct from the others and does not extend the plug-in used in those tutorials.
The Sobel edge detection algorithm can be calculated using convolution. This algorithm will only do edge detection with the first band in the data cube. The algorithm uses two kernels: one to calculate the vertical gradient, and one to calculate the horizontal gradient.
Vertical Gradient:
| -1 | 0 | +1 |
| -2 | 0 | +2 |
| -1 | 0 | +1 |
Horizontal Gradient:
| +1 | +2 | +1 |
| 0 | 0 | 0 |
| -1 | -2 | -1 |
These two results form a vector which describes the edge direction and magnitude at each point in the image. We are not concerned with edge direction so we will display only the absolute magnitude.
Now let's go over the edge detection function.
template<typename T> void edgeDetection(T* pData, DataAccessor pSrcAcc, int row, int col, int rowSize, int colSize) {
int prevCol = std::max(col - 1, 0); int prevRow = std::max(row - 1, 0); int nextCol = std::min(col + 1, colSize - 1); int nextRow = std::min(row + 1, rowSize - 1);
pSrcAcc->toPixel(prevRow, prevCol);
VERIFYNRV(pSrcAcc.isValid());
T upperLeftVal = *reinterpret_cast<T*>(pSrcAcc->getColumn());
double gx = -1.0 * upperLeftVal + -2.0 * leftVal + -1.0 * lowerLeftVal + 1.0 * upperRightVal + 2.0 * rightVal + 1.0 * lowerRightVal; double gy = -1.0 * lowerLeftVal + -2.0 * downVal + -1.0 * lowerRightVal + 1.0 * upperLeftVal + 2.0 * upVal + 1.0 * upperRightVal;
double magnitude = sqrt(gx * gx + gy * gy);
*pData = static_cast<T>(magnitude); }
bool Tutorial5::getOutputSpecification(PlugInArgList*& pOutArgList) { pOutArgList = Service<PlugInManagerServices>()->getPlugInArgList(); VERIFY(pOutArgList != NULL); pOutArgList->addArg<RasterElement>("Result", NULL); return true; }
if (pDesc->getDataType() == INT4SCOMPLEX || pDesc->getDataType() == FLT8COMPLEX) { std::string msg = "Edge detection cannot be performed on complex types."; pStep->finalize(Message::Failure, msg); if (pProgress != NULL) { pProgress->updateProgress(msg, 0, ERRORS); } return false;
ModelResource<RasterElement> pResultCube(RasterUtilities::createRasterElement(pCube->getName() + "_Edge_Detection_Result", pDesc->getRowCount(), pDesc->getColumnCount(), pDesc->getDataType()));
FactoryResource<DataRequest> pResultRequest; pResultRequest->setWritable(true); DataAccessor pDestAcc = pResultCube->getDataAccessor(pResultRequest.release());
switchOnEncoding(pDesc->getDataType(), edgeDetection, pDestAcc->getColumn(), pSrcAcc, row, col, pDesc->getRowCount(), pDesc->getColumnCount());
pDestAcc->nextColumn();
}
pDestAcc->nextRow();
if (!isBatch()) { Service<DesktopServices> pDesktop; SpatialDataWindow* pWindow = static_cast<SpatialDataWindow*>(pDesktop->createWindow(pResultCube->getName(), SPATIAL_DATA_WINDOW)); SpatialDataView* pView = (pWindow == NULL) ? NULL : pWindow->getSpatialDataView(); if (pView == NULL) { std::string msg = "Unable to create view."; pStep->finalize(Message::Failure, msg); if (pProgress != NULL) { pProgress->updateProgress(msg, 0, ERRORS); } return false; } pView->setPrimaryRasterElement(pResultCube.get()); pView->createLayer(RASTER, pResultCube.get());
pOutArgList->setPlugInArgValue("Tutorial5_Result", pResultCube.release());