|
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 |
}
|