bool FIPAdaptiveThreshold::init() { bool rValue=ImageProcessor::init(); //Note: SharedImageBuffer of downstream producer is initialised with storage in ImageProcessor::init. size_t maxScratchDataSize=0; size_t maxScratchDataValues=0; for (uint32_t i=0; i<ImagesPerSlot_; i++) { const ImageFormat imFormat=getUpstreamFormat(i); const size_t width=imFormat.getWidth(); const size_t height=imFormat.getHeight(); const size_t bytesPerPixel=imFormat.getBytesPerPixel(); const size_t componentsPerPixel=imFormat.getComponentsPerPixel(); const size_t scratchDataSize = width * height * bytesPerPixel; const size_t scratchDataValues = width * height * componentsPerPixel; if (scratchDataSize>maxScratchDataSize) { maxScratchDataSize=scratchDataSize; } if (scratchDataValues>maxScratchDataValues) { maxScratchDataValues=scratchDataValues; } } //Allocate a buffer big enough for any of the image slots. _noiseFilteredInputData=new uint8_t[maxScratchDataSize]; _scratchData=new uint8_t[maxScratchDataSize]; memset(_noiseFilteredInputData, 0, maxScratchDataSize); memset(_scratchData, 0, maxScratchDataSize); _integralImageScratchData=new double[maxScratchDataValues]; memset(_integralImageScratchData, 0, maxScratchDataValues*sizeof(double)); return rValue; }
bool FIPDPT::trigger() { if ((getNumReadSlotsAvailable())&&(getNumWriteSlotsAvailable())) {//There are images to consume and the downstream producer has space to produce. std::vector<Image**> imvRead=reserveReadSlot(); std::vector<Image**> imvWrite=reserveWriteSlot(); //Start stats measurement event. ProcessorStats_->tick(); for (size_t imgNum=0; imgNum<1; ++imgNum)//For now, only process one image in each slot. { Image const * const imRead = *(imvRead[imgNum]); Image * const imWrite = *(imvWrite[imgNum]); uint8_t const * const dataRead=imRead->data(); uint8_t * const dataWrite=imWrite->data(); const ImageFormat imFormat=getDownstreamFormat(imgNum); const size_t width=imFormat.getWidth(); const size_t height=imFormat.getHeight(); memset(dataWrite, 0, width*height);//Clear the downstream image. //=== Setup the initial nodes ===// for (size_t y=0; y<height; ++y) { const size_t lineOffset=y * width; for (size_t x=0; x<width; ++x) { const auto writeValue=dataRead[lineOffset + x]; Node &node=nodeVect_[lineOffset + x]; node.index_=lineOffset + x; node.value_=writeValue; node.size_=1; #ifdef RUN_ARCS node.arcIndices_.clear(); #else node.neighbourIndices_.clear(); #endif node.pixelIndices_.clear(); node.pixelIndices_.push_back(lineOffset + x); } } //=== ==// //=== Setup the initial arcs or node neighbours ===// { #ifdef RUN_ARCS size_t arcIndex=0; #endif for (size_t y=0; y<height; ++y) { const size_t lineOffset=y * width; for (size_t x=1; x<width; ++x) { #ifdef RUN_ARCS Arc &arc=arcVect_[arcIndex]; arc.index_=arcIndex; arc.active_=true; arc.nodeIndices_[0]=lineOffset+x-1; arc.nodeIndices_[1]=lineOffset+x; nodeVect_[arc.nodeIndices_[0]].arcIndices_.push_back(arcIndex); nodeVect_[arc.nodeIndices_[1]].arcIndices_.push_back(arcIndex); arcIndex++; #else nodeVect_[lineOffset+x-1].neighbourIndices_.push_back(lineOffset+x); nodeVect_[lineOffset+x].neighbourIndices_.push_back(lineOffset+x-1); #endif } if (y<(height-1)) { for (size_t x=0; x<width; ++x) { #ifdef RUN_ARCS Arc &arc=arcVect_[arcIndex]; arc.index_=arcIndex; arc.active_=true; arc.nodeIndices_[0]=lineOffset+x; arc.nodeIndices_[1]=lineOffset+x+width; nodeVect_[arc.nodeIndices_[0]].arcIndices_.push_back(arcIndex); nodeVect_[arc.nodeIndices_[1]].arcIndices_.push_back(arcIndex); arcIndex++; #else nodeVect_[lineOffset+x].neighbourIndices_.push_back(lineOffset+x+width); nodeVect_[lineOffset+x+width].neighbourIndices_.push_back(lineOffset+x); #endif } } } } //=== === size_t policyCounter=0; size_t numBumpsRemoved=0; size_t numPitsRemoved=0; size_t numPulsesMerged=mergeFromAll();//Initial merge. updatePotentiallyActiveNodeIndexVect(); std::vector<int32_t> nodeIndicesToMerge; size_t loopCounter = 0; int32_t previousSmallestPulse = 0; while ((previousSmallestPulse<filterPulseSize_)&&(potentiallyActiveNodeIndexVect_.size()>1)) { nodeIndicesToMerge.clear(); //=== Find smallest pulse ===// int32_t smallestPulse=0; for (const auto & potentiallyActiveNodeIndex : potentiallyActiveNodeIndexVect_) { Node &node=nodeVect_[potentiallyActiveNodeIndex]; if (node.size_>0) { if ((smallestPulse==0)||(node.size_<smallestPulse)) { //if (isBump(node.index_)||isPit(node.index_)) //if (node.size_>previousSmallestPulse) { smallestPulse=node.size_; } } } } //std::cout << "Smallest pulse is " << smallestPulse << ".\n"; //std::cout.flush(); //=== ===// //=== Implement DPT pit/bump policy ===// if (previousSmallestPulse!=smallestPulse) { policyCounter=0; } //=== ===// //=== Remove pits and bumps according to policy ===// for (const auto & potentiallyActiveNodeIndex : potentiallyActiveNodeIndexVect_) { Node &node=nodeVect_[potentiallyActiveNodeIndex]; if ((node.size_>0)&&(node.size_<=smallestPulse)) { if ((policyCounter%2)==0) { //if (isPit(node.index_)) { //=== Remove pits ===// flattenToNearestNeighbour(node.index_); //flattenToFirstNeighbour(node.index_); nodeIndicesToMerge.push_back(node.index_); ++numPitsRemoved; } } else { //if (isBump(node.index_)) { //=== Remove bumps ===// flattenToNearestNeighbour(node.index_); //flattenToFirstNeighbour(node.index_); nodeIndicesToMerge.push_back(node.index_); ++numBumpsRemoved; } } } } //=== ===// //std::cout << "Pulses merged = " << numPulsesMerged << ".\n"; //std::cout << "Pits removed = " << numPitsRemoved << ".\n"; //std::cout << "Bumps removed = " << numBumpsRemoved << ".\n"; //std::cout << "\n"; //std::cout.flush(); //=== Merge over arcs of removed nodes ===// numPulsesMerged=mergeFromList(nodeIndicesToMerge); //=== ===// ++policyCounter; previousSmallestPulse=smallestPulse; if ((loopCounter&15)==0) updatePotentiallyActiveNodeIndexVect(); ++loopCounter; } //=============================================// //=============================================// //=============================================// { //=== Find smallest pulse == int32_t smallestPulse=0; for (const auto & node : nodeVect_) { if (node.size_>0) { if ((smallestPulse==0)||(node.size_<smallestPulse)) { //if (isBump(node.index_)||isPit(node.index_)) { smallestPulse=node.size_; } } } } //=== === //std::cout << "Drawing pulses of size " << smallestPulse << "+.\n"; //std::cout.flush(); //=== Draw the pulses on the sceen == for (const auto & node : nodeVect_) { if (node.size_>0) { //if (node.size_==smallestPulse) { for (const auto pixelIndex : node.pixelIndices_) { dataWrite[pixelIndex]=node.value_; } } } } //std::cout << "\n"; //std::cout.flush(); //=== === } } //Stop stats measurement event. ProcessorStats_->tock(); releaseWriteSlot(); releaseReadSlot(); return true; } return false; }
bool FIPAdaptiveThreshold::trigger() { if ((getNumReadSlotsAvailable())&&(getNumWriteSlotsAvailable())) { std::vector<Image**> imvRead=reserveReadSlot(); std::vector<Image**> imvWrite=reserveWriteSlot(); //Start stats measurement event. ProcessorStats_->tick(); for (size_t imgNum=0; imgNum<ImagesPerSlot_; ++imgNum) { Image const * const imReadUS = *(imvRead[imgNum]); Image * const imWriteDS = *(imvWrite[imgNum]); const ImageFormat imFormat=getDownstreamFormat(imgNum);//down stream and up stream formats are the same. if (!_enabled) { uint8_t const * const dataReadUS=(uint8_t const * const)imReadUS->data(); uint8_t * const dataWriteDS=(uint8_t * const)imWriteDS->data(); const size_t bytesPerImage=imFormat.getBytesPerImage(); memcpy(dataWriteDS, dataReadUS, bytesPerImage); } else { const size_t width=imFormat.getWidth(); const size_t height=imFormat.getHeight(); const size_t numElements=width * height * imFormat.getComponentsPerPixel(); if (imFormat.getPixelFormat()==ImageFormat::FLITR_PIX_FMT_Y_F32) { float const * const dataReadUS=(float const * const)imReadUS->data(); float * const dataWriteDS=(float * const)imWriteDS->data(); //Small kernel noise filter. _noiseFilter.filter((float *)_noiseFilteredInputData, dataReadUS, width, height, _integralImageScratchData, true); for (short i=1; i<_numIntegralImageLevels; ++i) { memcpy(_scratchData, _noiseFilteredInputData, width*height*sizeof(uint8_t)); _noiseFilter.filter((float *)_noiseFilteredInputData, (float *)_scratchData, width, height, _integralImageScratchData, true); } for (size_t i=0; i<numElements; ++i) { dataWriteDS[i]=1.0; } //Large kernel adaptive reference. _boxFilter.filter(dataWriteDS, dataReadUS, width, height, _integralImageScratchData, true); for (short i=1; i<_numIntegralImageLevels; ++i) { memcpy(_scratchData, dataWriteDS, width*height*sizeof(float)); _boxFilter.filter(dataWriteDS, (float *)_scratchData, width, height, _integralImageScratchData, true); } const float tovF32=_thresholdOffset * 1.0f; size_t tpc=0; for (size_t i=0; i<numElements; ++i) { if (( ((float *)_noiseFilteredInputData)[i] - tovF32) > dataWriteDS[i]) { dataWriteDS[i]=1.0; ++tpc; } else { dataWriteDS[i]=0.0; } } _thresholdAvrg=tpc;// / double(width*height); } else if (imFormat.getPixelFormat()==ImageFormat::FLITR_PIX_FMT_Y_8) { uint8_t const * const dataReadUS=(uint8_t const * const)imReadUS->data(); uint8_t * const dataWriteDS=(uint8_t * const)imWriteDS->data(); //Small kernel noise filter. _noiseFilter.filter((uint8_t *)_noiseFilteredInputData, dataReadUS, width, height, _integralImageScratchData, true); for (short i=1; i<_numIntegralImageLevels; ++i) { memcpy(_scratchData, _noiseFilteredInputData, width*height*sizeof(uint8_t)); _noiseFilter.filter((uint8_t *)_noiseFilteredInputData, (uint8_t *)_scratchData, width, height, _integralImageScratchData, true); } for (size_t i=0; i<numElements; ++i) { dataWriteDS[i]=255; } //Large kernel adaptive reference. _boxFilter.filter(dataWriteDS, dataReadUS, width, height, _integralImageScratchData, true); for (short i=1; i<_numIntegralImageLevels; ++i) { memcpy(_scratchData, dataWriteDS, width*height*sizeof(uint8_t)); _boxFilter.filter(dataWriteDS, (uint8_t *)_scratchData, width, height, _integralImageScratchData, true); } const uint8_t tovUInt8=_thresholdOffset * 255.5; size_t tpc=0; for (size_t i=0; i<numElements; ++i) { if (( ((uint8_t *)_noiseFilteredInputData)[i] - tovUInt8) > dataWriteDS[i]) { dataWriteDS[i]=255; ++tpc; } else { dataWriteDS[i]=0; } } _thresholdAvrg=tpc / double(width*height); } } } //Stop stats measurement event. ProcessorStats_->tock(); releaseWriteSlot(); releaseReadSlot(); return true; } return false; }