Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// The following contains classes and prototypes for most code of centerline vectorization.
Toshihiro Shimizu 890ddd
#include "tcenterlinevectP.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/tcenterlinevectorizer.h"
Toshihiro Shimizu 890ddd
#include "toonz/Naa2TlvConverter.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
#include "tcolorstyles.h"
Toshihiro Shimizu 890ddd
#include "trastercm.h"
Toshihiro Shimizu 890ddd
#include "ttoonzimage.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "tgeometry.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "tropcm.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// STD includes
Toshihiro Shimizu 890ddd
#include <vector></vector>
Toshihiro Shimizu 890ddd
#include <list></list>
Toshihiro Shimizu 890ddd
#include <queue></queue>
Toshihiro Shimizu 890ddd
#include <map></map>
Toshihiro Shimizu 890ddd
#include <functional></functional>
Toshihiro Shimizu 890ddd
#include <algorithm></algorithm>
Toshihiro Shimizu 890ddd
#include <math.h></math.h>
Toshihiro Shimizu 890ddd
#include <assert.h></assert.h>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*********************************
Toshihiro Shimizu 890ddd
//*     Further miscellaneous     *
Toshihiro Shimizu 890ddd
//*********************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Reduces strokes of image by currConfig->m_reduceThicknessRatio/100
Toshihiro Shimizu 890ddd
inline void reduceThickness(TVectorImageP image, double thicknessRatio)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	thicknessRatio *= 0.01;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
	int j;
Toshihiro Shimizu 890ddd
	for (i = 0; i < image->getStrokeCount(); ++i) {
Toshihiro Shimizu 890ddd
		for (j = 0; j < image->getStroke(i)->getControlPointCount(); ++j) {
Toshihiro Shimizu 890ddd
			TThickPoint newCP = image->getStroke(i)->getControlPoint(j);
Toshihiro Shimizu 890ddd
			newCP.thick *= thicknessRatio;
Toshihiro Shimizu 890ddd
			image->getStroke(i)->setControlPoint(j, newCP);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Delete Skeleton graphs and list
Toshihiro Shimizu 890ddd
inline void deleteSkeletonList(SkeletonList *skeleton)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < skeleton->size(); ++i)
Toshihiro Shimizu 890ddd
		delete (*skeleton)[i];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	delete skeleton;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TVectorImageP copyStrokes(std::vector<tstroke *=""> &strokes)</tstroke>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
	TVectorImageP result = new TVectorImage;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (i = 0; i < strokes.size(); ++i)
Toshihiro Shimizu 890ddd
		if (strokes[i]->getStyle() >= 0)
Toshihiro Shimizu 890ddd
			result->addStroke(strokes[i]);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline TThickPoint randomized(const TThickPoint &P)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TThickPoint Q = P;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Q.x += ((((double)rand()) / RAND_MAX) - 0.5) * 0.1;
Toshihiro Shimizu 890ddd
	Q.y += ((((double)rand()) / RAND_MAX) - 0.5) * 0.1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return Q;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Give stroke extremities a random shake. May help for region computing.
Toshihiro Shimizu 890ddd
void randomizeExtremities(TVectorImageP vi)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < vi->getStrokeCount(); ++i) {
Toshihiro Shimizu 890ddd
		TThickPoint P = vi->getStroke(i)->getControlPoint(0);
Toshihiro Shimizu 890ddd
		vi->getStroke(i)->setControlPoint(0, randomized(P));
Toshihiro Shimizu 890ddd
		int n = vi->getStroke(i)->getControlPointCount();
Toshihiro Shimizu 890ddd
		P = vi->getStroke(i)->getControlPoint(n - 1);
Toshihiro Shimizu 890ddd
		vi->getStroke(i)->setControlPoint(n - 1, randomized(P));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Looped frame
Toshihiro Shimizu 890ddd
inline void addFrameStrokes(TVectorImageP vi, TRasterP ras, TPalette *palette)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const double epsThick = 1.0;
Toshihiro Shimizu 890ddd
	TStroke *frameStroke;
Toshihiro Shimizu 890ddd
	std::vector<tthickpoint> CPs;</tthickpoint>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(0, 0, epsThick));
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(ras->getLx() / 2.0, 0, epsThick));
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(ras->getLx(), 0, epsThick));
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(ras->getLx(), 0, epsThick));
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(ras->getLx(), 0, epsThick));
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(ras->getLx(), ras->getLy() / 2.0, epsThick));
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(ras->getLx(), ras->getLy(), epsThick));
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(ras->getLx(), ras->getLy(), epsThick));
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(ras->getLx(), ras->getLy(), epsThick));
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(ras->getLx() / 2.0, ras->getLy(), epsThick));
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(0, ras->getLy(), epsThick));
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(0, ras->getLy(), epsThick));
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(0, ras->getLy(), epsThick));
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(0, ras->getLy() / 2.0, epsThick));
Toshihiro Shimizu 890ddd
	CPs.push_back(TThickPoint(0, 0, epsThick));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	frameStroke = new TStroke(CPs);
Toshihiro Shimizu 890ddd
	frameStroke->setStyle(0);
Toshihiro Shimizu 890ddd
	frameStroke->setSelfLoop(true);
Toshihiro Shimizu 890ddd
	vi->addStroke(frameStroke);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Returns if input stroke is edge boundary of an ink-filled region
Toshihiro Shimizu 890ddd
bool VectorizerCore::isInkRegionEdge(TStroke *stroke)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return stroke->getFlag(SkeletonArc::SS_OUTLINE);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Similar as above
Toshihiro Shimizu 890ddd
bool VectorizerCore::isInkRegionEdgeReversed(TStroke *stroke)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return stroke->getFlag(SkeletonArc::SS_OUTLINE_REVERSED);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void VectorizerCore::clearInkRegionFlags(TVectorImageP vi)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int flag = SkeletonArc::SS_OUTLINE | SkeletonArc::SS_OUTLINE_REVERSED;
Toshihiro Shimizu 890ddd
	for (int i = 0; i < (int)vi->getStrokeCount(); i++)
Toshihiro Shimizu 890ddd
		vi->getStroke(i)->setFlag(flag, false);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************
Toshihiro Shimizu 890ddd
//*    Vectorizer Main   *
Toshihiro Shimizu 890ddd
//************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TVectorImageP VectorizerCore::centerlineVectorize(
Toshihiro Shimizu 890ddd
	TImageP &image, const CenterlineConfiguration &configuration, TPalette *palette)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TRasterImageP ri = image;
Toshihiro Shimizu 890ddd
	TToonzImageP ti = image;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRasterP ras;
Toshihiro Shimizu 890ddd
	if (ri)
Toshihiro Shimizu 890ddd
		ras = ri->getRaster();
Toshihiro Shimizu 890ddd
	else {
Toshihiro Shimizu 890ddd
		ras = ti->getRaster()->clone();
Toshihiro Shimizu 890ddd
		TRop::expandPaint(ras);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (configuration.m_naaSource) {
Toshihiro Shimizu 890ddd
		if (TRaster32P ras32 = ras) {
Toshihiro Shimizu 890ddd
			Naa2TlvConverter converter;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			converter.process(ras32);
Toshihiro Shimizu 890ddd
			converter.setPalette(palette);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (ti = converter.makeTlv(true)) // Transparent synthetic inks
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				image = ti;
Toshihiro Shimizu 890ddd
				ras = ti->getRaster();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				TRop::expandPaint(ras);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	VectorizerCoreGlobals globals;
Toshihiro Shimizu 890ddd
	globals.currConfig = &configuration;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Contours polygons;
Toshihiro Shimizu 890ddd
	polygonize(ras, polygons, globals);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Most time-consuming part of vectorization, 'this' is passed to inform of partial progresses
Toshihiro Shimizu 890ddd
	SkeletonList *skeletons = skeletonize(polygons, this, globals);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (isCanceled()) {
Toshihiro Shimizu 890ddd
		//Clean and return 0 at cancel command
Toshihiro Shimizu 890ddd
		deleteSkeletonList(skeletons);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		return TVectorImageP();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	organizeGraphs(skeletons, globals);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//junctionRecovery(polygons);   //Da' problemi per maxThickness
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<tstroke *=""> sortibleResult;</tstroke>
Toshihiro Shimizu 890ddd
	TVectorImageP result;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	calculateSequenceColors(ras, globals); //Extract stroke colors here
Toshihiro Shimizu 890ddd
	conversionToStrokes(sortibleResult, globals);
Toshihiro Shimizu 890ddd
	applyStrokeColors(sortibleResult, ras, palette, globals); //Strokes get sorted here
Toshihiro Shimizu 890ddd
	result = copyStrokes(sortibleResult);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Further misc adjustments
Toshihiro Shimizu 890ddd
	if (globals.currConfig->m_thicknessRatio < 100)
Toshihiro Shimizu 890ddd
		reduceThickness(result, configuration.m_thicknessRatio);
Toshihiro Shimizu 890ddd
	if (globals.currConfig->m_maxThickness == 0.0)
Toshihiro Shimizu 890ddd
		for (unsigned int i = 0; i < result->getStrokeCount(); ++i)
Toshihiro Shimizu 890ddd
			result->getStroke(i)->setSelfLoop(true);
Toshihiro Shimizu 890ddd
	if (globals.currConfig->m_makeFrame)
Toshihiro Shimizu 890ddd
		addFrameStrokes(result, ras, palette);
Toshihiro Shimizu 890ddd
	//randomizeExtremities(result);   //Cuccio random - non serve...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	deleteSkeletonList(skeletons);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return result;
Toshihiro Shimizu 890ddd
}