void IntensityDistributionHistogram::construct( const Billon &billon, const Interval<uint> &sliceInterval, const Interval<uint> &sectorInterval,
												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);
}
예제 #2
0
	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;
	}
예제 #3
0
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 &currentSlice = billon.slice(k);
			const Slice &previousSlice = billon.previousSlice(k);
			const iCoord2D &currentPithCoord = 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++;
			}
		}
	}
}
예제 #4
0
	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);
}
예제 #6
0
	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);
	}
예제 #8
0
	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 &currentSlice = 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;
	}
예제 #9
0
	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();
	}
예제 #10
0
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);
}