void IntensityDistributionHistogram::construct( const Billon &billon, const Interval<uint> &sliceInterval, const Interval<uint> §orInterval, const iCoord2D &pithCoord, const uint &maxDistance, const Interval<int> &intensityInterval, const uint &smoothingRadius ) { const uint &width = billon.n_cols; const uint &height = billon.n_rows; const int &minVal = intensityInterval.min(); uint i, j, k; clear(); resize(intensityInterval.size()+1); for ( j=0 ; j<height ; ++j ) { for ( i=0 ; i<width ; ++i ) { if ( sectorInterval.containsClosed(PieChartSingleton::getInstance()->sectorIndexOfAngle(pithCoord.angle(iCoord2D(i,j)))) && pithCoord.euclideanDistance(iCoord2D(i,j)) < maxDistance ) { for ( k=sliceInterval.min() ; k<=sliceInterval.max() ; ++k ) { if ( intensityInterval.containsClosed(billon.slice(k).at(j,i)) ) ++((*this)[billon.slice(k).at(j,i)-minVal]); } } } } meansSmoothing(smoothingRadius,false); }
QVector<rCoord2D> restrictedAreaVertex( const Billon &billon, const Interval<uint> & sliceInterval, const uint & nbPolygonVertex, const int & intensityThreshold ) { Q_ASSERT_X( nbPolygonVertex>0 , "BillonTpl<T>::getRestrictedAreaVertex", "nbPolygonVertex arguments equals to 0 => division by zero" ); QVector<rCoord2D> vectAllVertex; if ( billon.hasPith() ) { const int width = billon.n_cols; const int height = billon.n_rows; const qreal angleIncrement = TWO_PI/static_cast<qreal>(nbPolygonVertex); rCoord2D edge, center; rVec2D direction; qreal orientation; for ( uint indexSlice = sliceInterval.min() ; indexSlice<=sliceInterval.max() ; ++indexSlice ) { const Slice & currentSlice = billon.slice(indexSlice); center.x = billon.pithCoord(indexSlice).x; center.y = billon.pithCoord(indexSlice).y; orientation = 0.; while (orientation < TWO_PI) { orientation += angleIncrement; direction = rVec2D(qCos(orientation),qSin(orientation)); edge = center + direction*30; while ( edge.x>0. && edge.y>0. && edge.x<width && edge.y<height && currentSlice(edge.y,edge.x) >= intensityThreshold ) { edge += direction; } vectAllVertex.push_back(edge); } } } return vectAllVertex; }
void SectorHistogram::construct( const Billon &billon, const Interval<uint> &sliceInterval, const Interval<int> &intensity, const uint &zMotionMin, const int &radiusAroundPith ) { clear(); if ( billon.hasPith() && sliceInterval.isValid() && sliceInterval.width() > 0 ) { const int &width = billon.n_cols; const int &height = billon.n_rows; const qreal squareRadius = qPow(radiusAroundPith,2); fill(0.,PieChartSingleton::getInstance()->nbSectors()); QVector<int> circleLines; circleLines.reserve(2*radiusAroundPith+1); for ( int lineIndex=-radiusAroundPith ; lineIndex<=radiusAroundPith ; ++lineIndex ) { circleLines.append(qSqrt(squareRadius-qPow(lineIndex,2))); } QVector<int>::ConstIterator circlesLinesIterator; int iRadius; uint diff; iCoord2D currentPos; // Calcul du diagramme en parcourant les tranches du billon comprises dans l'intervalle for ( uint k=sliceInterval.min() ; k<=sliceInterval.max() ; ++k ) { const Slice ¤tSlice = billon.slice(k); const Slice &previousSlice = billon.previousSlice(k); const iCoord2D ¤tPithCoord = billon.pithCoord(k); currentPos.y = currentPithCoord.y-radiusAroundPith; for ( circlesLinesIterator = circleLines.constBegin() ; circlesLinesIterator != circleLines.constEnd() ; ++circlesLinesIterator ) { iRadius = *circlesLinesIterator; currentPos.x = currentPithCoord.x-iRadius; iRadius += currentPithCoord.x; while ( currentPos.x <= iRadius ) { if ( currentPos.x < width && currentPos.y < height && intensity.containsOpen(currentSlice.at(currentPos.y,currentPos.x)) && intensity.containsOpen(previousSlice.at(currentPos.y,currentPos.x)) ) { diff = billon.zMotion(currentPos.x,currentPos.y,k); //if ( motionInterval.containsClosed(diff) ) if ( diff >= zMotionMin ) { (*this)[PieChartSingleton::getInstance()->sectorIndexOfAngle( currentPithCoord.angle(currentPos) )] += diff-zMotionMin; } } currentPos.x++; } currentPos.y++; } } } }
void appendComponent( QXmlStreamWriter &stream, const Billon &billon, const uint &firstSlicePos, const int &index ) { const uint &width = billon.n_cols; const uint &height = billon.n_rows; const uint &depth = billon.n_slices; uint i, j, k; stream.writeStartElement("component"); stream.writeAttribute("id",QString::number(index)); stream.writeAttribute("valmax",QString::number(billon.maxValue())); stream.writeAttribute("valmin",QString::number(billon.minValue())); //coord minimum stream.writeStartElement("coord"); stream.writeAttribute("name","minimum"); stream.writeTextElement("x",QString::number(0)); stream.writeTextElement("y",QString::number(0)); stream.writeTextElement("z",QString::number(firstSlicePos)); stream.writeEndElement(); //coord maximum stream.writeStartElement("coord"); stream.writeAttribute("name","maximum"); stream.writeTextElement("x",QString::number(width-1)); stream.writeTextElement("y",QString::number(height-1)); stream.writeTextElement("z",QString::number(firstSlicePos+billon.n_slices-1)); stream.writeEndElement(); //binarydata stream.writeStartElement("binarydata"); stream.writeAttribute("encoding","16"); stream.writeCharacters(""); QDataStream voxelStream(stream.device()); for ( k=0; k<depth; ++k ) { const Slice &slice = billon.slice(k); for ( j=0; j<height; ++j ) { for ( i=0; i<width; ++i ) { voxelStream << (qint16)(slice.at(j,i)); } } } stream.writeEndElement(); stream.writeEndElement(); }
void IntensityDistributionHistogram::construct( const Billon &billon, const Interval<uint> &sliceInterval, const Interval<int> &intensityInterval, const uint &smoothingRadius ) { const uint &width = billon.n_cols; const uint &height = billon.n_rows; const int &minVal = intensityInterval.min(); uint i, j, k; clear(); resize(intensityInterval.size()+1); for ( k=sliceInterval.min() ; k<=sliceInterval.max() ; ++k ) { const Slice &slice = billon.slice(k); for ( j=0 ; j<height ; ++j ) { for ( i=0 ; i<width ; ++i ) { if ( intensityInterval.containsClosed(slice.at(j,i)) ) ++((*this)[slice.at(j,i)-minVal]); } } } meansSmoothing(smoothingRadius,false); }
void appendPith( QXmlStreamWriter &stream, const Billon &billon, const uint &firstSlicePos ) { if ( !billon.pith().isEmpty() ) { const Pith &pith = billon.pith(); stream.writeStartElement("pith"); for ( int k=0 ; k<pith.size() ; ++k ) { stream.writeStartElement("coord"); stream.writeTextElement("x",QString::number(pith[k].x)); stream.writeTextElement("y",QString::number(pith[k].y)); stream.writeTextElement("z",QString::number(k+firstSlicePos)); stream.writeEndElement(); } stream.writeEndElement(); } }
void extractConnexComponents( Billon &resultBillon, const Billon & billon, const int & minimumSize, const int & threshold ) { const uint width = billon.n_cols; const uint height = billon.n_rows; const uint depth = billon.n_slices; int nbLabel = 0; QMap<int, QList<iCoord3D> > connexComponentList; Slice* labels = new Slice(height, width); Slice* oldSlice = new Slice(height, width); oldSlice->fill(0); Slice* tmp; //On parcours les tranches 1 par 1 for ( unsigned int k=0 ; k<depth ; ++k ) { nbLabel = twoPassAlgorithm((*oldSlice),billon.slice(k),(*labels),connexComponentList,k,nbLabel,threshold); tmp = oldSlice; oldSlice = labels; labels = tmp; tmp = 0; } delete labels; delete oldSlice; QMap<int, QList<iCoord3D> >::ConstIterator iterComponents; QList<iCoord3D>::ConstIterator iterCoords; int counter = 1; resultBillon.fill(0); for ( iterComponents = connexComponentList.constBegin() ; iterComponents != connexComponentList.constEnd() ; ++iterComponents ) { if ( iterComponents.value().size() > minimumSize ) { for ( iterCoords = iterComponents.value().constBegin() ; iterCoords != iterComponents.value().constEnd() ; ++iterCoords ) { resultBillon.at((*iterCoords).y,(*iterCoords).x,(*iterCoords).z) = counter; } ++counter; } } qDebug() << QObject::tr("Nombre de composantes = %1").arg(counter-1); resultBillon.setMinValue(0); resultBillon.setMaxValue(counter-1); }
qreal restrictedAreaMeansRadius(const Billon &billon, const uint &nbDirections, const int &intensityThreshold, const uint &minimumRadius, const uint &nbSlicesToIgnore ) { Q_ASSERT_X( nbDirections>0 , "BillonTpl<T>::getRestrictedAreaMeansRadius", "nbPolygonPoints arguments equals to 0 => division by zero" ); if ( !billon.hasPith() ) return 1; const int &width = billon.n_cols; const int &height = billon.n_rows; const int depth = billon.n_slices-nbSlicesToIgnore; const qreal angleIncrement = TWO_PI/static_cast<qreal>(nbDirections); rCoord2D center, edge; rVec2D direction; qreal orientation, currentNorm; qreal radius = width; for ( int k=nbSlicesToIgnore ; k<depth ; ++k ) { const Slice ¤tSlice = billon.slice(k); center.x = billon.pithCoord(k).x; center.y = billon.pithCoord(k).y; orientation = angleIncrement; while (orientation < TWO_PI) { orientation += angleIncrement; direction = rVec2D(qCos(orientation),qSin(orientation)); edge = center + direction*minimumRadius; while ( edge.x>0 && edge.y>0 && edge.x<width && edge.y<height && currentSlice(edge.y,edge.x) > intensityThreshold ) { edge += direction; } currentNorm = rVec2D(edge-center).norm(); if ( currentNorm < radius ) radius = currentNorm; } } qDebug() << "Rayon de la boite englobante (en pixels) : " << radius; return radius; }
void appendTags( QXmlStreamWriter &stream, const Billon &billon ) { stream.writeStartElement("tags"); writeTag(stream,"width",QString::number(billon.n_cols)); writeTag(stream,"height",QString::number(billon.n_rows)); writeTag(stream,"depth",QString::number(billon.n_slices)); writeTag(stream,"xspacing",QString::number(billon.voxelWidth())); writeTag(stream,"yspacing",QString::number(billon.voxelHeight())); writeTag(stream,"zspacing",QString::number(billon.voxelDepth())); writeTag(stream,"voxelwidth",QString::number(billon.voxelWidth())); writeTag(stream,"voxelheight",QString::number(billon.voxelHeight())); writeTag(stream,"voxeldepth",QString::number(billon.voxelDepth())); stream.writeEndElement(); }
void PithExtractor::process( Billon &billon ) const { billon._pith.clear(); const int width = billon.n_cols; const int height = billon.n_rows; const int depth = billon.n_slices; uiCoord2D coordPrec, coordCurrent; float maxStandList[depth]; float *maxStandList2 = 0; float shift,houghStandThreshold; int max,x,y, nbContourPoints; max = x = y = 0; //extraction de la moelle de la premiere coupe sur la totalité de la coupe //nous permet d'avoir un coordonnée a laquelle appliqué la fenetre transHough( billon.slice(0), width, height, &x, &y, &max, &nbContourPoints ); //calcul la coordonnée d'origine de la fenetre x = x - (_windowWidth/2); x = x < 0 ? 0 : (x > (width - _windowWidth) ? width - _windowWidth : x); y = y - (_windowHeight/2); y = y < 0 ? 0 : (y > (height - _windowHeight) ? height - _windowHeight : y); //extraction de la moelle de la premiere coupe sur la coupe redimensionnée coordCurrent = transHough( billon.slice(0), _windowWidth, _windowHeight, &x, &y, &max, &nbContourPoints ); billon._pith.append(coordCurrent); maxStandList[0] = ((float)max)/nbContourPoints; //extraction des coupes suivantes std::cerr << "extractMoelle : "; for(int i=1; i<depth; i++) { //~ if(!listeCoupe->contains(i)){ std::cerr << " " << i; coordPrec = billon._pith.last(); x = x - (_windowWidth/2); x = x < 0 ? 0 : (x > (width - _windowWidth) ? width - _windowWidth : x); y = y - (_windowHeight/2); y = y < 0 ? 0 : (y > (height - _windowHeight) ? height - _windowHeight : y); //extraction de la moelle de la coupe i coordCurrent = transHough( billon.slice(i), _windowWidth, _windowHeight, &x, &y, &max, &nbContourPoints ); billon._pith.append(coordCurrent); shift = sqrt(pow((double) ((int)(billon._pith.last().x) - (int)(coordPrec.x)),(double) 2.0) + pow( (double)((int)(billon._pith.last().y) - (int)(coordPrec.y)), (double)2.0) ); //si le resultat obtenu a un decalage trop important avec la coupe precedente alors on recommence l'extraction sur l'ensemble de la coupe if(shift > _pithLag && width > _windowWidth && height > _windowHeight){ std::cerr << "*"; // std::cerr << " :> decalage=" << decalage << ">" << _pithLag << "\n"; billon._pith.pop_back(); x = y = 0; transHough(billon.slice(i), width, height, &x, &y, &max, &nbContourPoints ); x = x - (_windowWidth/2); x = x < 0 ? 0 : (x > (width - _windowWidth) ? width - _windowWidth : x); y = y - (_windowHeight/2); y = y < 0 ? 0 : (y > (height - _windowHeight) ? height - _windowHeight : y); coordCurrent = transHough( billon.slice(i), _windowWidth, _windowHeight, &x, &y, &max, &nbContourPoints ); billon._pith.append(coordCurrent); } maxStandList[i] = ((float)max)/nbContourPoints; if (!(i % 20)) { std::cerr << std::endl; } //~ }else{ //~ listMoelle->append(listMoelle->last()); //~ listMaxStand[i] = 0; //~ } } std::cerr << "\nnbCoupes=" << depth << " listMoelle.size()=" << billon._pith.size() << "\n"; //calcul du seuil a partir du quel les coupes sont considerées comme erronées maxStandList2 = new float[depth]; memcpy(maxStandList2, maxStandList, depth*sizeof(float)); qsort(maxStandList2, depth, sizeof(float), &floatCompare); int nfc = (_falseCutPercent*depth)/100; houghStandThreshold = nfc > 0 ? (maxStandList2[nfc]+maxStandList2[nfc-1])/2 : maxStandList2[nfc]; delete [] maxStandList2; // applique la coorection a la moelle correctPith(billon._pith, maxStandList, houghStandThreshold); }