void SummedAreaOp::modifyChannels( const Imath::Box2i &displayWindow, const Imath::Box2i &dataWindow, ChannelVector &channels ) { SumArea summer( dataWindow ); for( unsigned i=0; i<channels.size(); i++ ) { despatchTypedData<SumArea, TypeTraits::IsNumericVectorTypedData>( channels[i], summer ); } }
/*! @brief Report the connections for a given port. @param[in] flavour The format for the output. @param[in] portName The port to be inspected. @param[in] checker A function that provides for early exit from loops. @param[in] checkStuff The private data for the early exit function. */ static void reportConnections(const OutputFlavour flavour, const YarpString & portName, CheckFunction checker, void * checkStuff) { ODL_ENTER(); //#### ODL_S1s("portName = ", portName); //#### ODL_P1("checkStuff = ", checkStuff); //#### bool sawInputs = false; bool sawOutputs = false; ChannelVector inputs; ChannelVector outputs; YarpString inputsAsString; YarpString outputsAsString; Utilities::GatherPortConnections(portName, inputs, outputs, Utilities::kInputAndOutputBoth, false, checker, checkStuff); if (0 < inputs.size()) { for (ChannelVector::const_iterator walker(inputs.begin()); inputs.end() != walker; ++walker) { switch (flavour) { case kOutputFlavourTabs : if (sawInputs) { inputsAsString += ", "; } inputsAsString += SanitizeString(walker->_portName, true); switch (walker->_portMode) { case kChannelModeTCP : inputsAsString += " TCP"; break; case kChannelModeUDP : inputsAsString += " UDP"; break; case kChannelModeOther : inputsAsString += " unknown"; break; default : break; } break; case kOutputFlavourJSON : if (sawInputs) { inputsAsString += ", "; } inputsAsString += T_("{ " CHAR_DOUBLEQUOTE_ "Port" CHAR_DOUBLEQUOTE_ ": " CHAR_DOUBLEQUOTE_); inputsAsString += SanitizeString(walker->_portName); inputsAsString += T_(CHAR_DOUBLEQUOTE_ ", " CHAR_DOUBLEQUOTE_ "Mode" CHAR_DOUBLEQUOTE_ ": " CHAR_DOUBLEQUOTE_); switch (walker->_portMode) { case kChannelModeTCP : inputsAsString += "TCP"; break; case kChannelModeUDP : inputsAsString += "UDP"; break; case kChannelModeOther : inputsAsString += "unknown"; break; default : break; } inputsAsString += T_(CHAR_DOUBLEQUOTE_ " }"); break; case kOutputFlavourNormal : inputsAsString += " Input from "; inputsAsString += SanitizeString(walker->_portName, true); switch (walker->_portMode) { case kChannelModeTCP : inputsAsString += " via TCP."; break; case kChannelModeUDP : inputsAsString += " via UDP."; break; case kChannelModeOther : inputsAsString += " via non-TCP/non-UDP."; break; default : break; } inputsAsString += "\n"; break; default : break; } sawInputs = true; } } if (0 < outputs.size()) { for (ChannelVector::const_iterator walker(outputs.begin()); outputs.end() != walker; ++walker) { switch (flavour) { case kOutputFlavourTabs : if (sawOutputs) { outputsAsString += ", "; } outputsAsString += SanitizeString(walker->_portName, true); switch (walker->_portMode) { case kChannelModeTCP : outputsAsString += " TCP"; break; case kChannelModeUDP : outputsAsString += " UDP"; break; case kChannelModeOther : outputsAsString += " unknown"; break; default : break; } break; case kOutputFlavourJSON : if (sawOutputs) { outputsAsString += ", "; } outputsAsString += T_("{ " CHAR_DOUBLEQUOTE_ "Port" CHAR_DOUBLEQUOTE_ ": " CHAR_DOUBLEQUOTE_); outputsAsString += SanitizeString(walker->_portName); outputsAsString += T_(CHAR_DOUBLEQUOTE_ ", " CHAR_DOUBLEQUOTE_ "Mode" CHAR_DOUBLEQUOTE_ ": " CHAR_DOUBLEQUOTE_); switch (walker->_portMode) { case kChannelModeTCP : outputsAsString += "TCP"; break; case kChannelModeUDP : outputsAsString += "UDP"; break; case kChannelModeOther : outputsAsString += "unknown"; break; default : break; } outputsAsString += T_(CHAR_DOUBLEQUOTE_ " }"); break; case kOutputFlavourNormal : outputsAsString += " Output to "; outputsAsString += SanitizeString(walker->_portName, true); switch (walker->_portMode) { case kChannelModeTCP : outputsAsString += " via TCP."; break; case kChannelModeUDP : outputsAsString += " via UDP."; break; case kChannelModeOther : outputsAsString += " via non-TCP/non-UDP."; break; default : break; } outputsAsString += "\n"; break; default : break; } sawOutputs = true; } } switch (flavour) { case kOutputFlavourTabs : cout << inputsAsString.c_str() << "\t" << outputsAsString.c_str(); break; case kOutputFlavourJSON : cout << T_(CHAR_DOUBLEQUOTE_ "Inputs" CHAR_DOUBLEQUOTE_ ": [ ") << inputsAsString.c_str() << T_(" ], " CHAR_DOUBLEQUOTE_ "Outputs" CHAR_DOUBLEQUOTE_ ": [ ") << outputsAsString.c_str() << " ]"; break; case kOutputFlavourNormal : if (sawInputs || sawOutputs) { if (sawInputs) { cout << inputsAsString.c_str(); } if (sawOutputs) { cout << outputsAsString.c_str(); } } else { cout << " No active connections." << endl; } break; default : break; } ODL_EXIT(); //#### } // reportConnections
void HitMissTransform::modifyChannels( const Imath::Box2i &displayWindow, const Imath::Box2i &dataWindow, ChannelVector &channels ) { // process the structuring elements, including making rotated versions if requested. bool rotateElements = rotateStructuringElementsParameter()->getTypedValue(); vector<int> masks; vector<int> elements; const std::vector<M33f> &matrices = structuringElementsParameter()->getTypedValue(); for( unsigned i=0; i<matrices.size(); i++ ) { int mask = 0; int element = 0; processMatrix( matrices[i], mask, element ); masks.push_back( mask ); elements.push_back( element ); if( rotateElements ) { M33f m = matrices[i]; for( unsigned r=0; r<3; r++ ) { M33f m2( m[0][2], m[1][2], m[2][2], m[0][1], m[1][1], m[2][1], m[0][0], m[1][0], m[2][0] ); processMatrix( m2, mask, element ); masks.push_back( mask ); elements.push_back( element ); m = m2; } } } // apply the operation to each channel char value = valueParameter()->getNumericValue() > thresholdParameter()->getNumericValue() ? 1 : 0; char borderValue = borderValueParameter()->getNumericValue() > thresholdParameter()->getNumericValue() ? 1 : 0; bool applyAlternately = applyElementsAlternatelyParameter()->getTypedValue(); int numIterations = iterationsParameter()->getNumericValue(); if( applyAlternately ) { numIterations *= elements.size(); } V2i size = dataWindow.size() + V2i( 1 ); V2i paddedSize = size + V2i( 2 ); std::vector<char> pixels; std::vector<char> pixels2; for( unsigned i=0; i<channels.size(); i++ ) { // threshold the image into a temporary pixels structure Thresholder thresholder( thresholdParameter()->getNumericValue(), borderValue, size, pixels ); despatchTypedData<Thresholder, TypeTraits::IsNumericVectorTypedData>( channels[i], thresholder ); pixels2.clear(); pixels2.resize( pixels.size(), borderValue ); // do the work unsigned iterationsSinceChange = 0; for( int n=0; n<numIterations || numIterations==0; n++ ) { iterationsSinceChange++; for( int y=0; y<size.y; y++ ) { const char *r0 = &(pixels[y * paddedSize.x]) + 1; const char *r1 = r0 + paddedSize.x; const char *r2 = r1 + paddedSize.x; char *ro = &(pixels2[(y+1) * paddedSize.x]) + 1; for( int x=0; x<size.x; x++ ) { if( *r1==value ) { // no point doing the work if the existing value is the one we'd change it to anyway *ro = value; } else { int v = r0[-1] | r0[0] << 2 | r0[1] << 4 | r1[-1] << 6 | r1[0] << 8 | r1[1] << 10 | r2[-1] << 12 | r2[0] << 14 | r2[1] << 16; bool matches = false; if( applyAlternately ) { size_t e = n % elements.size(); if( (v & masks[e])==elements[e] ) { matches = true; } } else { for( size_t e=0; e<elements.size(); e++ ) { if( (v & masks[e])==elements[e] ) { matches = true; break; } } } if( matches ) { *ro = value; iterationsSinceChange = 0; } else { *ro = *r1; } } ro++; r0++; r1++; r2++; } } pixels.swap( pixels2 ); if( (applyAlternately && iterationsSinceChange==elements.size()) || ( !applyAlternately && iterationsSinceChange ) ) { break; } } // and copy back into the original structure Copyer copyer( size, pixels ); despatchTypedData<Copyer, TypeTraits::IsNumericVectorTypedData>( channels[i], copyer ); } }
void ImageThinner::modifyChannels( const Imath::Box2i &displayWindow, const Imath::Box2i &dataWindow, ChannelVector &channels ) { float threshold = thresholdParameter()->getNumericValue(); const V2i size = dataWindow.size() + V2i( 1 ); for( unsigned i=0; i<channels.size(); i++ ) { FloatVectorDataPtr floatData = runTimeCast<FloatVectorData>( channels[i] ); if( !floatData ) { throw Exception( "ImageThinner::modifyChannels : only float channels supported." ); } std::vector<float> &channel = floatData->writable(); // threshold the image first for( std::vector<float>::iterator it=channel.begin(); it!=channel.end(); it++ ) { *it = *it < threshold ? 0.0f : 1.0f; } // then apply the graphics gems magic that i don't understand in the slightest ////////////////////////////////////////////////////////////////////////////// boost::multi_array_ref<float, 2> image( &channel[0], boost::extents[size.y][size.x] ); int p, q; // Neighborhood maps of adjacent cells std::vector<unsigned char> qb; // Neighborhood maps of previous scanline qb.resize( size.x ); qb[qb.size()-1] = 0; // Used for lower-right pixel int count = 1; // Deleted pixel count while( count ) { count = 0; for( int i = 0; i < 4 ; i++ ) { int m = g_masks[i]; // Build initial previous scan buffer p = image[0][0] > 0.5f; for( int x = 0; x < size.x-1; x++ ) { qb[x] = p = ((p<<1)&0006) | (image[0][x+1] > 0.5f); } // Scan image for pixel deletion candidates for( int y = 0; y < size.y-1; y++ ) { q = qb[0]; p = ((q<<3)&0110) | (image[y+1][0] > 0.5f); for( int x = 0; x < size.x-1; x++ ) { q = qb[x]; p = ((p<<1)&0666) | ((q<<3)&0110) | (image[y+1][x+1] > 0.5f); qb[x] = p; if( ((p&m) == 0) && g_delete[p] ) { count++; image[y][x] = 0.f; } } // Process right edge pixel p = (p<<1)&0666; if( (p&m) == 0 && g_delete[p] ) { count++; image[y][size.x-1] = 0.f; } } // Process bottom scan line for( int x = 0 ; x < size.x ; x++ ) { q = qb[x]; p = ((p<<1)&0666) | ((q<<3)&0110); if( (p&m) == 0 && g_delete[p] ) { count++; image[size.y-1][x] = 0.f; } } } } } }