|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "tcenterlinevectP.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// tcg includes
|
|
Toshihiro Shimizu |
890ddd |
#include "tcg/tcg_numeric_ops.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Boost includes
|
|
Toshihiro Shimizu |
890ddd |
#include <boost container="" flat_map.hpp=""></boost>
|
|
Toshihiro Shimizu |
890ddd |
#include <boost algorithm="" minmax_element.hpp=""></boost>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
namespace boost_c = boost::container;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//==========================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//*************************
|
|
Toshihiro Shimizu |
890ddd |
//* Colors handling *
|
|
Toshihiro Shimizu |
890ddd |
//*************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Riassunto: Nel caso di normali raster, i tratti di penna sono colorati con
|
|
Shinya Kitaoka |
120a6e |
// l'elemento della palette data maggiormente tendente al nero.
|
|
Shinya Kitaoka |
120a6e |
// Per le Toonz colormap abilitiamo una gestione piu' complessa, che tiene
|
|
Shinya Kitaoka |
120a6e |
// conto del colore dell'inchiostro specificato direttamente nell'immagine.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Nello specifico:
|
|
Toshihiro Shimizu |
890ddd |
// a) I tratti di penna vengono rilevati in base al valore del campo *tone*
|
|
Toshihiro Shimizu |
890ddd |
// di un TPixleCM32, non in base alla luminosita' del colore.
|
|
Toshihiro Shimizu |
890ddd |
// (vv. Poligonizzazione)
|
|
Toshihiro Shimizu |
890ddd |
// b) Sulle centerline grezze viene costruito un insieme di 'punti di assaggio'
|
|
Toshihiro Shimizu |
890ddd |
// dell'immagine; gli id di inchiostro rilevati vengono assegnati
|
|
Toshihiro Shimizu |
890ddd |
// direttamente alla stroke: se si verifica un cambio nell'id del colore,
|
|
Toshihiro Shimizu |
890ddd |
// il punto di cambio del colore viene identificato e la centerline viene
|
|
Toshihiro Shimizu |
890ddd |
// spezzata li'.
|
|
Toshihiro Shimizu |
890ddd |
// c) Una volta identificati i colori delle stroke, le si ordina *prima*
|
|
Shinya Kitaoka |
120a6e |
// di inserirle nella vector image di output, in base al colore
|
|
Shinya Kitaoka |
120a6e |
// dell'immagine
|
|
Toshihiro Shimizu |
890ddd |
// ai loro estremi (attualmente ordinamento solo parziale).
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Campbell Barton |
b3bd84 |
static TPixelCM32 pixel(const TRasterCM32 &ras, int x, int y) {
|
|
Shinya Kitaoka |
120a6e |
// Seems that raster access was not very much double-checked at the time
|
|
Shinya Kitaoka |
120a6e |
// I wrote this. Too bad. Enforcing it now.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
return ras.pixels(tcrop(y, 0, ras.getLy() - 1))[tcrop(x, 0, ras.getLx() - 1)];
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Campbell Barton |
b3bd84 |
static T3DPointD firstInkChangePosition(const TRasterCM32P &ras,
|
|
shun-iwasawa |
27b0cf |
const T3DPointD &start,
|
|
shun-iwasawa |
27b0cf |
const T3DPointD &end, int threshold) {
|
|
Shinya Kitaoka |
120a6e |
double dist = norm(end - start);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int sampleMax = tceil(dist), sampleCount = sampleMax + 1;
|
|
Shinya Kitaoka |
120a6e |
double sampleMaxD = double(sampleMax);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Get first ink color
|
|
Shinya Kitaoka |
120a6e |
int s, color = -1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
for (s = 0; s != sampleCount; ++s) {
|
|
Shinya Kitaoka |
120a6e |
T3DPointD p = tcg::numeric_ops::lerp(start, end, s / sampleMaxD);
|
|
Shinya Kitaoka |
120a6e |
const TPixelCM32 &pix = pixel(*ras, p.x, p.y);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (pix.getTone() < threshold) {
|
|
Shinya Kitaoka |
120a6e |
color = pix.getInk();
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Get second color
|
|
Shinya Kitaoka |
120a6e |
for (; s != sampleCount; ++s) {
|
|
Shinya Kitaoka |
120a6e |
T3DPointD p = tcg::numeric_ops::lerp(start, end, s / sampleMaxD);
|
|
Shinya Kitaoka |
120a6e |
const TPixelCM32 &pix = pixel(*ras, p.x, p.y);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (pix.getTone() < threshold && pix.getInk() != color) break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Return middle position between s-1 and s
|
|
Shinya Kitaoka |
120a6e |
if (s < sampleCount)
|
|
Shinya Kitaoka |
120a6e |
return tcg::numeric_ops::lerp(start, end, (s - 0.5) / sampleMaxD);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
return TConsts::nap3d;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Find color of input sequence. Will be copied to its equivalent stroke.
|
|
Shinya Kitaoka |
120a6e |
// Currently in use only on colormaps
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Riassunto: Per saggiare il colore da assegnare alle strokes e' meglio
|
|
Shinya Kitaoka |
120a6e |
// controllare
|
|
Shinya Kitaoka |
120a6e |
// le sequenze *prima* di convertirle in TStroke (visto che si perde parte
|
|
Shinya Kitaoka |
120a6e |
// dell'aderenza originale
|
|
Shinya Kitaoka |
120a6e |
// al tratto). Si specifica un numero di 'punti di assaggio' della spezzata
|
|
Shinya Kitaoka |
120a6e |
// equidistanti tra loro,
|
|
Shinya Kitaoka |
120a6e |
// su cui viene prelevato il valore dell'ink del pixel corrispondente. Se si
|
|
Shinya Kitaoka |
120a6e |
// identifica un cambio
|
|
Shinya Kitaoka |
120a6e |
// di colore, viene lanciata la procedura di spezzamento della sequenza: si
|
|
Shinya Kitaoka |
120a6e |
// identifica il punto
|
|
Shinya Kitaoka |
120a6e |
// di spezzamento, e la sequenza s viene bloccata li'; si costruisce una nuova
|
|
Shinya Kitaoka |
120a6e |
// sequenza newSeq e
|
|
Shinya Kitaoka |
120a6e |
// viene rilanciata sampleColor(ras,newSeq,sOpposite). Le sequenze tra due punti
|
|
Shinya Kitaoka |
120a6e |
// di spezzamento
|
|
Shinya Kitaoka |
120a6e |
// vengono inserite nel vector 'globals->singleSequences'.
|
|
Shinya Kitaoka |
120a6e |
// Nel caso di sequenze circolari c'e' una piccola modifica: il primo punto di
|
|
Shinya Kitaoka |
120a6e |
// spezzamento
|
|
Toshihiro Shimizu |
890ddd |
//*ridefinisce solo* il nodo-raccordo di s, senza introdurre nuove sequenze.
|
|
Shinya Kitaoka |
120a6e |
// La sequenza sOpposite, 'inversa' di s, rimane e diventa 'forward-oriented'
|
|
Shinya Kitaoka |
120a6e |
// previo aggiornamento
|
|
Shinya Kitaoka |
120a6e |
// della coda.
|
|
Shinya Kitaoka |
120a6e |
// Osservare che i nodi di spezzamento vengono inseriti con la signature
|
|
Shinya Kitaoka |
120a6e |
// 'SAMPLECOLOR_SIGN'.
|
|
Shinya Kitaoka |
120a6e |
// NOTA: La struttura a grafo J-S 'superiore' non viene alterata qui dentro.
|
|
Shinya Kitaoka |
120a6e |
// Eventualm. da fare fuori.
|
|
Shinya Kitaoka |
120a6e |
|
|
Campbell Barton |
b3bd84 |
static void sampleColor(const TRasterCM32P &ras, int threshold, Sequence &seq,
|
|
Campbell Barton |
b3bd84 |
Sequence &seqOpposite, SequenceList &singleSequences) {
|
|
Shinya Kitaoka |
120a6e |
SkeletonGraph *currGraph = seq.m_graphHolder;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Calculate sequence parametrization
|
|
Shinya Kitaoka |
120a6e |
std::vector<unsigned int=""> nodes;</unsigned>
|
|
Shinya Kitaoka |
120a6e |
std::vector<double> params;</double>
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Meanwhile, ensure each point belong to ras. Otherwise, typically an error
|
|
luzpaz |
27707d |
// occurred in the thinning process and it's better avoid sampling procedure.
|
|
luzpaz |
27707d |
// Only exception, when a point has
|
|
luzpaz |
27707d |
// x==ras->getLx() || y==ras->getLy(); that is accepted.
|
|
Shinya Kitaoka |
120a6e |
{
|
|
Shinya Kitaoka |
120a6e |
const T3DPointD &headPos = *currGraph->getNode(seq.m_head);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!ras->getBounds().contains(TPoint(headPos.x, headPos.y))) {
|
|
Shinya Kitaoka |
120a6e |
if (headPos.x < 0 || ras->getLx() < headPos.x || headPos.y < 0 ||
|
|
Shinya Kitaoka |
120a6e |
ras->getLy() < headPos.y)
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
unsigned int curr, currLink, next;
|
|
Shinya Kitaoka |
120a6e |
double meanThickness = currGraph->getNode(seq.m_head)->z;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
params.push_back(0);
|
|
Shinya Kitaoka |
120a6e |
nodes.push_back(seq.m_head);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (curr = seq.m_head, currLink = seq.m_headLink;
|
|
Shinya Kitaoka |
120a6e |
curr != seq.m_tail || params.size() == 1; seq.next(curr, currLink)) {
|
|
Shinya Kitaoka |
120a6e |
next = currGraph->getNode(curr).getLink(currLink).getNext();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
const T3DPointD &nextPos = *currGraph->getNode(next);
|
|
Shinya Kitaoka |
120a6e |
if (!ras->getBounds().contains(TPoint(nextPos.x, nextPos.y))) {
|
|
Shinya Kitaoka |
120a6e |
if (nextPos.x < 0 || ras->getLx() < nextPos.x || nextPos.y < 0 ||
|
|
Shinya Kitaoka |
120a6e |
ras->getLy() < nextPos.y)
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
4f9e2c |
double distance =
|
|
shun-iwasawa |
4f9e2c |
tdistance(*currGraph->getNode(next), *currGraph->getNode(curr));
|
|
shun-iwasawa |
4f9e2c |
if (distance == 0.0) continue;
|
|
shun-iwasawa |
4f9e2c |
|
|
shun-iwasawa |
4f9e2c |
params.push_back(params.back() + distance);
|
|
Shinya Kitaoka |
120a6e |
nodes.push_back(next);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
meanThickness += currGraph->getNode(next)->z;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
meanThickness /= params.size();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Exclude 0-length sequences
|
|
Shinya Kitaoka |
120a6e |
if (params.back() < 0.01) {
|
|
Shinya Kitaoka |
120a6e |
seq.m_color = pixel(*ras, currGraph->getNode(seq.m_head)->x,
|
|
Shinya Kitaoka |
120a6e |
currGraph->getNode(seq.m_head)->y)
|
|
Shinya Kitaoka |
120a6e |
.getInk();
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Prepare sampling procedure
|
|
Shinya Kitaoka |
120a6e |
int paramCount = params.size(), paramMax = paramCount - 1;
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
4f9e2c |
int sampleMax = std::max(params.back() / std::max(meanThickness, 1.0),
|
|
shun-iwasawa |
4f9e2c |
3.0), // Number of color samples depends on
|
|
Shinya Kitaoka |
120a6e |
sampleCount = sampleMax + 1; // the ratio params.back() / meanThickness
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
std::vector<double> sampleParams(sampleCount); // Sampling lengths</double>
|
|
Shinya Kitaoka |
120a6e |
std::vector<tpoint> samplePoints(</tpoint>
|
|
Shinya Kitaoka |
120a6e |
sampleCount); // Image points for color sampling
|
|
Shinya Kitaoka |
120a6e |
std::vector<int> sampleSegments(</int>
|
|
Shinya Kitaoka |
120a6e |
sampleCount); // Sequence segment index for the above
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Sample colors
|
|
Shinya Kitaoka |
120a6e |
for (int s = 0, j = 0; s != sampleCount; ++s) {
|
|
Shinya Kitaoka |
120a6e |
double samplePar = params.back() * (s / double(sampleMax));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
while (j != paramMax &&
|
|
Shinya Kitaoka |
120a6e |
params[j + 1] < samplePar) // params[j] < samplePar <= params[j+1]
|
|
Shinya Kitaoka |
120a6e |
++j;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double t = (samplePar - params[j]) / (params[j + 1] - params[j]);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
T3DPointD samplePoint(*currGraph->getNode(nodes[j]) * (1 - t) +
|
|
Shinya Kitaoka |
120a6e |
*currGraph->getNode(nodes[j + 1]) * t);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
sampleParams[s] = samplePar;
|
|
Shinya Kitaoka |
120a6e |
samplePoints[s] = TPoint(
|
|
Shinya Kitaoka |
120a6e |
std::min(samplePoint.x,
|
|
Shinya Kitaoka |
120a6e |
double(ras->getLx() - 1)), // This deals with sample points at
|
|
Shinya Kitaoka |
120a6e |
std::min(samplePoint.y,
|
|
Shinya Kitaoka |
120a6e |
double(ras->getLy() - 1))); // the top/right raster border
|
|
Shinya Kitaoka |
120a6e |
sampleSegments[s] = j;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// NOTE: Extremities of a sequence are considered unreliable: they typically
|
|
luzpaz |
27707d |
// happen to be junction points shared between possibly different-colored
|
|
luzpaz |
27707d |
// strokes.
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Find first and last extremity-free sampled points
|
|
Shinya Kitaoka |
120a6e |
T3DPointD first(*currGraph->getNode(seq.m_head));
|
|
Shinya Kitaoka |
120a6e |
T3DPointD last(*currGraph->getNode(seq.m_tail));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int i, k;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (i = 1;
|
|
Shinya Kitaoka |
120a6e |
params.back() * i / double(sampleMax) <= first.z && i < sampleCount; ++i)
|
|
Shinya Kitaoka |
120a6e |
;
|
|
Shinya Kitaoka |
120a6e |
for (k = sampleMax - 1;
|
|
Shinya Kitaoka |
120a6e |
params.back() * (sampleMax - k) / double(sampleMax) <= last.z && k >= 0;
|
|
Shinya Kitaoka |
120a6e |
--k)
|
|
Shinya Kitaoka |
120a6e |
;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Give s the first sampled ink color found
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Initialize with a last-resort reasonable color - not just 0
|
|
Shinya Kitaoka |
120a6e |
seq.m_color = seqOpposite.m_color =
|
|
Shinya Kitaoka |
120a6e |
ras->pixels(samplePoints[0].y)[samplePoints[0].x].getInk();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int l;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (l = i - 1; l >= 0; --l) {
|
|
Shinya Kitaoka |
120a6e |
if (ras->pixels(samplePoints[l].y)[samplePoints[l].x].getTone() <
|
|
Shinya Kitaoka |
120a6e |
threshold) {
|
|
Shinya Kitaoka |
120a6e |
seq.m_color = seqOpposite.m_color =
|
|
Shinya Kitaoka |
120a6e |
ras->pixels(samplePoints[l].y)[samplePoints[l].x].getInk();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Then, look for the first reliable ink
|
|
Shinya Kitaoka |
120a6e |
for (l = i; l <= k; ++l) {
|
|
Shinya Kitaoka |
120a6e |
if (ras->pixels(samplePoints[l].y)[samplePoints[l].x].getTone() <
|
|
Shinya Kitaoka |
120a6e |
threshold) {
|
|
Shinya Kitaoka |
120a6e |
seq.m_color = seqOpposite.m_color =
|
|
Shinya Kitaoka |
120a6e |
ras->pixels(samplePoints[l].y)[samplePoints[l].x].getInk();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
4f9e2c |
if (i >= k)
|
|
shun-iwasawa |
4f9e2c |
goto _getOut; // No admissible segment found for splitting
|
|
shun-iwasawa |
4f9e2c |
// check.
|
|
Shinya Kitaoka |
120a6e |
// Find color changes between sampled colors
|
|
Shinya Kitaoka |
120a6e |
for (l = i; l < k; ++l) {
|
|
Shinya Kitaoka |
120a6e |
const TPixelCM32
|
|
Shinya Kitaoka |
120a6e |
&nextSample = ras->pixels(samplePoints[l + 1].y)[samplePoints[l + 1].x],
|
|
Shinya Kitaoka |
120a6e |
&nextSample2 = ras->pixels(
|
|
Shinya Kitaoka |
120a6e |
samplePoints[l + 2]
|
|
Shinya Kitaoka |
120a6e |
.y)[samplePoints[l + 2].x]; // l < k < sampleMax - so +2 is ok
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (nextSample.getTone() < threshold &&
|
|
Shinya Kitaoka |
120a6e |
nextSample.getInk() != seq.m_color &&
|
|
Shinya Kitaoka |
120a6e |
nextSample2.getTone() < threshold &&
|
|
Shinya Kitaoka |
120a6e |
nextSample2.getInk() ==
|
|
Shinya Kitaoka |
120a6e |
nextSample.getInk()) // Ignore single-sample color changes
|
|
Shinya Kitaoka |
120a6e |
{
|
|
Shinya Kitaoka |
120a6e |
// Found a color change - apply splitting procedure
|
|
Shinya Kitaoka |
120a6e |
// NOTE: The function RETURNS BEFORE THE FOR IS CONTINUED!
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int nextColor = nextSample.getInk();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Identify split segment
|
|
Shinya Kitaoka |
120a6e |
int u;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (u = sampleSegments[l]; u < sampleSegments[l + 1]; ++u) {
|
|
Shinya Kitaoka |
120a6e |
const TPixelCM32 &pix = pixel(*ras, currGraph->getNode(nodes[u + 1])->x,
|
|
Shinya Kitaoka |
120a6e |
currGraph->getNode(nodes[u + 1])->y);
|
|
Shinya Kitaoka |
120a6e |
if (pix.getTone() < threshold && pix.getInk() != seq.m_color) break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Now u indicates the splitting segment. Search for splitting point by
|
|
Shinya Kitaoka |
120a6e |
// binary subdivision.
|
|
Shinya Kitaoka |
120a6e |
const T3DPointD &nodeStartPos = *currGraph->getNode(nodes[u]),
|
|
Shinya Kitaoka |
120a6e |
&nodeEndPos = *currGraph->getNode(nodes[u + 1]);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
T3DPointD splitPoint =
|
|
Shinya Kitaoka |
120a6e |
firstInkChangePosition(ras, nodeStartPos, nodeEndPos, threshold);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (splitPoint == TConsts::nap3d)
|
|
Shinya Kitaoka |
120a6e |
splitPoint = 0.5 * (nodeStartPos +
|
|
Shinya Kitaoka |
120a6e |
nodeEndPos); // A color change was found, but could
|
|
Shinya Kitaoka |
120a6e |
// not be precisely located. Just take
|
|
Shinya Kitaoka |
120a6e |
// a reasonable representant.
|
|
Shinya Kitaoka |
120a6e |
// Insert a corresponding new node in basic graph structure.
|
|
Shinya Kitaoka |
120a6e |
unsigned int splitNode = currGraph->newNode(splitPoint);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
unsigned int nodesLink =
|
|
Shinya Kitaoka |
120a6e |
currGraph->getNode(nodes[u]).linkOfNode(nodes[u + 1]);
|
|
Shinya Kitaoka |
120a6e |
currGraph->insert(splitNode, nodes[u], nodesLink);
|
|
Shinya Kitaoka |
120a6e |
*currGraph->node(splitNode).link(0) =
|
|
Shinya Kitaoka |
120a6e |
*currGraph->getNode(nodes[u]).getLink(nodesLink);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
nodesLink = currGraph->getNode(nodes[u + 1]).linkOfNode(nodes[u]);
|
|
Shinya Kitaoka |
120a6e |
currGraph->insert(splitNode, nodes[u + 1], nodesLink);
|
|
Shinya Kitaoka |
120a6e |
*currGraph->node(splitNode).link(1) =
|
|
Shinya Kitaoka |
120a6e |
*currGraph->getNode(nodes[u + 1]).getLink(nodesLink);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
currGraph->node(splitNode).setAttribute(
|
|
Shinya Kitaoka |
120a6e |
SAMPLECOLOR_SIGN); // Sign all split-inserted nodes
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (seq.m_head == seq.m_tail &&
|
|
Shinya Kitaoka |
120a6e |
currGraph->getNode(seq.m_head).getLinksCount() == 2 &&
|
|
Shinya Kitaoka |
120a6e |
!currGraph->getNode(seq.m_head).hasAttribute(SAMPLECOLOR_SIGN)) {
|
|
Shinya Kitaoka |
120a6e |
// Circular case: we update s to splitNode and relaunch this very
|
|
Shinya Kitaoka |
120a6e |
// procedure on it.
|
|
Shinya Kitaoka |
120a6e |
seq.m_head = seq.m_tail = splitNode;
|
|
Shinya Kitaoka |
120a6e |
sampleColor(ras, threshold, seq, seqOpposite, singleSequences);
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
// Update upper (Joint-Sequence) graph data
|
|
Shinya Kitaoka |
120a6e |
Sequence newSeq;
|
|
Shinya Kitaoka |
120a6e |
newSeq.m_graphHolder = currGraph;
|
|
Shinya Kitaoka |
120a6e |
newSeq.m_head = splitNode;
|
|
Shinya Kitaoka |
120a6e |
newSeq.m_headLink = 0;
|
|
Shinya Kitaoka |
120a6e |
newSeq.m_tail = seq.m_tail;
|
|
Shinya Kitaoka |
120a6e |
newSeq.m_tailLink = seq.m_tailLink;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
seq.m_tail = splitNode;
|
|
Shinya Kitaoka |
120a6e |
seq.m_tailLink = 1; // (link from splitNode to nodes[u] inserted for
|
|
Shinya Kitaoka |
120a6e |
// second by 'insert')
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
seqOpposite.m_graphHolder =
|
|
Shinya Kitaoka |
120a6e |
seq.m_graphHolder; // Inform that a split was found
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// NOTE: access on s terminates at newSeq's push_back, due to possible
|
|
Shinya Kitaoka |
120a6e |
// reallocation of globals->singleSequences
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if ((!(seq.m_head == newSeq.m_tail &&
|
|
Shinya Kitaoka |
120a6e |
currGraph->getNode(seq.m_head).getLinksCount() == 2)) &&
|
|
Shinya Kitaoka |
120a6e |
currGraph->getNode(seq.m_head).hasAttribute(SAMPLECOLOR_SIGN))
|
|
Shinya Kitaoka |
120a6e |
singleSequences.push_back(seq);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
sampleColor(ras, threshold, newSeq, seqOpposite, singleSequences);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
_getOut:
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Color changes not found (and therefore no newSeq got pushed back); if a
|
|
Shinya Kitaoka |
120a6e |
// split happened, update sOpposite.
|
|
Shinya Kitaoka |
120a6e |
if (currGraph->getNode(seq.m_head).hasAttribute(SAMPLECOLOR_SIGN)) {
|
|
Shinya Kitaoka |
120a6e |
seqOpposite.m_color = seq.m_color;
|
|
Shinya Kitaoka |
120a6e |
seqOpposite.m_head = seq.m_tail;
|
|
Shinya Kitaoka |
120a6e |
seqOpposite.m_headLink = seq.m_tailLink;
|
|
Shinya Kitaoka |
120a6e |
seqOpposite.m_tail = seq.m_head;
|
|
Shinya Kitaoka |
120a6e |
seqOpposite.m_tailLink = seq.m_headLink;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Take samples of image colors to associate each sequence to its corresponding
|
|
Shinya Kitaoka |
120a6e |
// palette color. Currently working on colormaps.
|
|
Shinya Kitaoka |
120a6e |
// void calculateSequenceColors(const TRasterP &ras)
|
|
Shinya Kitaoka |
120a6e |
void calculateSequenceColors(const TRasterP &ras, VectorizerCoreGlobals &g) {
|
|
Shinya Kitaoka |
120a6e |
int threshold = g.currConfig->m_threshold;
|
|
Shinya Kitaoka |
120a6e |
SequenceList &singleSequences = g.singleSequences;
|
|
Shinya Kitaoka |
120a6e |
JointSequenceGraphList &organizedGraphs = g.organizedGraphs;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TRasterCM32P cm = ras;
|
|
Shinya Kitaoka |
120a6e |
unsigned int i, j, k;
|
|
Shinya Kitaoka |
120a6e |
int l;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (cm && g.currConfig->m_maxThickness > 0.0) {
|
|
Shinya Kitaoka |
120a6e |
// singleSequence is traversed back-to-front because new, possibly splitted
|
|
luzpaz |
27707d |
// sequences are inserted at back - and don't have to be re-sampled.
|
|
Shinya Kitaoka |
120a6e |
for (l = singleSequences.size() - 1; l >= 0; --l) {
|
|
Shinya Kitaoka |
120a6e |
Sequence rear;
|
|
Shinya Kitaoka |
120a6e |
sampleColor(ras, threshold, singleSequences[l], rear, singleSequences);
|
|
Shinya Kitaoka |
120a6e |
// If rear is built, a split occurred and the rear of this
|
|
Shinya Kitaoka |
120a6e |
// single sequence has to be pushed back.
|
|
Shinya Kitaoka |
120a6e |
if (rear.m_graphHolder) singleSequences.push_back(rear);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < organizedGraphs.size(); ++i)
|
|
Shinya Kitaoka |
120a6e |
for (j = 0; j < organizedGraphs[i].getNodesCount(); ++j)
|
|
Shinya Kitaoka |
120a6e |
if (!organizedGraphs[i].getNode(j).hasAttribute(
|
|
Shinya Kitaoka |
120a6e |
JointSequenceGraph::ELIMINATED)) // due to junction recovery
|
|
Shinya Kitaoka |
120a6e |
for (k = 0; k < organizedGraphs[i].getNode(j).getLinksCount(); ++k) {
|
|
Shinya Kitaoka |
120a6e |
Sequence &s = *organizedGraphs[i].node(j).link(k);
|
|
Shinya Kitaoka |
120a6e |
if (s.isForward() &&
|
|
Shinya Kitaoka |
120a6e |
!s.m_graphHolder->getNode(s.m_tail).hasAttribute(
|
|
Shinya Kitaoka |
120a6e |
SAMPLECOLOR_SIGN)) {
|
|
Shinya Kitaoka |
120a6e |
unsigned int next = organizedGraphs[i].node(j).link(k).getNext();
|
|
Shinya Kitaoka |
120a6e |
unsigned int nextLink = organizedGraphs[i].tailLinkOf(j, k);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
Sequence &sOpposite =
|
|
Shinya Kitaoka |
120a6e |
*organizedGraphs[i].node(next).link(nextLink);
|
|
Shinya Kitaoka |
120a6e |
sampleColor(cm, threshold, s, sOpposite, singleSequences);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//==========================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
inline void applyStrokeIndices(VectorizerCoreGlobals *globals) {
|
|
Shinya Kitaoka |
120a6e |
unsigned int i, j, k, n;
|
|
Shinya Kitaoka |
120a6e |
unsigned int next, nextLink;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < globals->singleSequences.size(); ++i)
|
|
Shinya Kitaoka |
120a6e |
globals->singleSequences[i].m_strokeIndex = i;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
n = i;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < globals->organizedGraphs.size(); ++i) {
|
|
Shinya Kitaoka |
120a6e |
JointSequenceGraph *currJSGraph = &globals->organizedGraphs[i];
|
|
Shinya Kitaoka |
120a6e |
for (j = 0; j < currJSGraph->getNodesCount(); ++j)
|
|
Shinya Kitaoka |
120a6e |
if (!currJSGraph->getNode(j).hasAttribute(JointSequenceGraph::ELIMINATED))
|
|
Shinya Kitaoka |
120a6e |
for (k = 0; k < currJSGraph->getNode(j).getLinksCount(); ++k) {
|
|
Shinya Kitaoka |
120a6e |
Sequence &s = *currJSGraph->node(j).link(k);
|
|
Shinya Kitaoka |
120a6e |
if (s.isForward()) {
|
|
Shinya Kitaoka |
120a6e |
s.m_strokeIndex = n;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!s.m_graphHolder->getNode(s.m_tail).hasAttribute(
|
|
Shinya Kitaoka |
120a6e |
SAMPLECOLOR_SIGN)) {
|
|
Shinya Kitaoka |
120a6e |
next = currJSGraph->getNode(j).getLink(k).getNext();
|
|
Shinya Kitaoka |
120a6e |
nextLink = currJSGraph->tailLinkOf(j, k);
|
|
Shinya Kitaoka |
120a6e |
currJSGraph->node(next).link(nextLink)->m_strokeIndex = n;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
++n;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//==========================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Riassunto: Dato un grafo superiore, possiamo associare ad ogni nodo il colore
|
|
Shinya Kitaoka |
120a6e |
// del pixel associato a quel punto; se una sequenza e' nascosta, ha entrambi
|
|
Toshihiro Shimizu |
890ddd |
// i nodi agli estremi di colore diverso, viceversa per sequenze esposte.
|
|
Shinya Kitaoka |
120a6e |
// Data una sequenza, a partire dai nodi superiori adiacenti possiamo stabilire
|
|
Shinya Kitaoka |
120a6e |
// un
|
|
Shinya Kitaoka |
120a6e |
// insieme di sequenze che gli stanno sotto, ed uno di seq. che gli stanno
|
|
Shinya Kitaoka |
120a6e |
// sopra.
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// NOTA: Questo problema e' un caso particolare di 'graph labeling', di cui non
|
|
Shinya Kitaoka |
120a6e |
// ho ancora trovato soluzione. In rete qualcosa si trova...
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// La seguente funzione fa qualcosa di piu' debole: ad ogni joint ed ogni
|
|
Shinya Kitaoka |
120a6e |
// Sequence
|
|
Shinya Kitaoka |
120a6e |
// viene assegnata una altezza (intero). Dato un Joint, le sequenze che lo hanno
|
|
Shinya Kitaoka |
120a6e |
// per estremo e che hanno lo stesso colore dell'immagine in quella posizione
|
|
Shinya Kitaoka |
120a6e |
// hanno
|
|
Shinya Kitaoka |
120a6e |
// un'altezza +1 rispetto al giunto, e viceversa altezza -1. Partendo da
|
|
Shinya Kitaoka |
120a6e |
// un giunto iniziale, quest'informazione viene propagata sul grafo; il problema
|
|
Shinya Kitaoka |
120a6e |
// sta ritornando ai giunti gia' percorsi...
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Find predominant ink color in a circle of given radius and center
|
|
shun-iwasawa |
27b0cf |
static int getInkPredominance(const TRasterCM32P &ras, TPalette *palette, int x,
|
|
shun-iwasawa |
27b0cf |
int y, int radius, int threshold) {
|
|
Shinya Kitaoka |
120a6e |
int i, j;
|
|
Shinya Kitaoka |
120a6e |
int mx, my, Mx, My;
|
|
Shinya Kitaoka |
120a6e |
std::vector<int> inksFound(palette->getStyleCount());</int>
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
radius = std::min(
|
|
Shinya Kitaoka |
120a6e |
radius, 7); // Restrict radius for a minimum significative neighbour
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
mx = std::max(x - radius, 0);
|
|
Shinya Kitaoka |
120a6e |
my = std::max(y - radius, 0);
|
|
Shinya Kitaoka |
120a6e |
Mx = std::min(x + radius, ras->getLx() - 1);
|
|
Shinya Kitaoka |
120a6e |
My = std::min(y + radius, ras->getLy() - 1);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Check square grid around (x,y)
|
|
Shinya Kitaoka |
120a6e |
for (i = mx; i <= Mx; ++i)
|
|
Shinya Kitaoka |
120a6e |
for (j = my; j <= My; ++j)
|
|
Shinya Kitaoka |
120a6e |
if (sq(i) + sq(j) <= sq(radius) &&
|
|
Shinya Kitaoka |
120a6e |
ras->pixels(j)[i].getTone() < threshold) {
|
|
Shinya Kitaoka |
120a6e |
// Update color table
|
|
Shinya Kitaoka |
120a6e |
inksFound[ras->pixels(j)[i].getInk()] +=
|
|
Shinya Kitaoka |
120a6e |
255 - ras->pixels(j)[i].getTone();
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// return the most found ink
|
|
Shinya Kitaoka |
120a6e |
int maxCount = 0, mostFound = 0;
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < (int)inksFound.size(); ++i)
|
|
Shinya Kitaoka |
120a6e |
if (inksFound[i] > maxCount) {
|
|
Shinya Kitaoka |
120a6e |
maxCount = inksFound[i];
|
|
Shinya Kitaoka |
120a6e |
mostFound = i;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
return mostFound;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*!
|
|
Toshihiro Shimizu |
890ddd |
\brief Find the predominant color in sequences adjacent to the
|
|
Toshihiro Shimizu |
890ddd |
input graph node.
|
|
Toshihiro Shimizu |
890ddd |
\return The predominant branch color if found, \p -1 otherwise.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Campbell Barton |
b3bd84 |
static int getBranchPredominance(const TRasterCM32P &ras, TPalette *palette,
|
|
Campbell Barton |
b3bd84 |
JointSequenceGraph::Node &node) {
|
|
Shinya Kitaoka |
120a6e |
struct locals {
|
|
Shinya Kitaoka |
120a6e |
static inline bool valueLess(const std::pair<int, int=""> &a,</int,>
|
|
Shinya Kitaoka |
120a6e |
const std::pair<int, int=""> &b) {</int,>
|
|
Shinya Kitaoka |
120a6e |
return (a.second < b.second);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
boost_c::flat_map<int, int=""> branchInksHistogram;</int,>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
UINT l, lCount = node.getLinksCount();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
for (l = 0; l != lCount; ++l) {
|
|
Shinya Kitaoka |
120a6e |
int color = node.getLink(l)->m_color;
|
|
Shinya Kitaoka |
120a6e |
if (color >= 0 && color <= palette->getStyleCount())
|
|
Shinya Kitaoka |
120a6e |
++branchInksHistogram[color];
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Return the most found ink, or -1 if a predominance color could not be found
|
|
Shinya Kitaoka |
120a6e |
if (branchInksHistogram.empty()) return -1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
typedef boost_c::flat_map<int, int="">::iterator histo_it;</int,>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
const std::pair<histo_it, histo_it=""> &histoRange =</histo_it,>
|
|
Shinya Kitaoka |
120a6e |
boost::minmax_element(branchInksHistogram.begin(),
|
|
Shinya Kitaoka |
120a6e |
branchInksHistogram.end(), locals::valueLess);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
return (histoRange.first->second == histoRange.second->second)
|
|
Shinya Kitaoka |
120a6e |
? -1
|
|
Shinya Kitaoka |
120a6e |
: histoRange.second->first;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// NOTA: Da implementare una versione in grado di ordinare *pienamente* la
|
|
Shinya Kitaoka |
120a6e |
// vector image.
|
|
Campbell Barton |
b3bd84 |
static void sortJS(JointSequenceGraph *js,
|
|
Campbell Barton |
b3bd84 |
std::vector<std::pair<int, *="" tstroke="">> &toOrder,</std::pair<int,>
|
|
Campbell Barton |
b3bd84 |
const TRasterCM32P &ras, TPalette *palette) {
|
|
Shinya Kitaoka |
120a6e |
enum { SORTED = 0x10 };
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
std::vector<std::pair<unsigned int="" int,="">> nodesToDo;</std::pair<unsigned>
|
|
Shinya Kitaoka |
120a6e |
unsigned int currNodeIdx, nextNodeIdx;
|
|
Shinya Kitaoka |
120a6e |
int currColor, currHeight, nextColor, nextHeight;
|
|
Shinya Kitaoka |
120a6e |
T3DPointD pD;
|
|
Shinya Kitaoka |
120a6e |
TPoint p;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
SkeletonGraph *currGraph = js->getNode(0).getLink(0)->m_graphHolder;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
unsigned int n, nCount = js->getNodesCount();
|
|
Shinya Kitaoka |
120a6e |
for (n = 0; n != nCount; ++n) {
|
|
Shinya Kitaoka |
120a6e |
// Get the first non-ELIMINATED and non-already treated JS node
|
|
Shinya Kitaoka |
120a6e |
if (!js->getNode(n).hasAttribute(JointSequenceGraph::ELIMINATED | SORTED)) {
|
|
Shinya Kitaoka |
120a6e |
nodesToDo.push_back(std::make_pair(n, 0));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
while (!nodesToDo.empty()) {
|
|
Shinya Kitaoka |
120a6e |
currNodeIdx = nodesToDo.back().first;
|
|
Shinya Kitaoka |
120a6e |
currHeight = nodesToDo.back().second;
|
|
Shinya Kitaoka |
120a6e |
nodesToDo.pop_back();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
JointSequenceGraph::Node &currNode = js->node(currNodeIdx);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Sign current node
|
|
Shinya Kitaoka |
120a6e |
currNode.setAttribute(SORTED);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Initialize this node infos
|
|
Shinya Kitaoka |
120a6e |
pD = *currGraph->getNode(currNode.getLink(0)->m_head);
|
|
Shinya Kitaoka |
120a6e |
p = TPoint(pD.x, pD.y);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!ras->getBounds().contains(p)) continue;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// currColor = getInkPredominance(ras, palette, p.x, p.y, (int) pD.z);
|
|
Shinya Kitaoka |
120a6e |
// //ras->pixels(p.y)[p.x].getInk();
|
|
Shinya Kitaoka |
120a6e |
currColor = getBranchPredominance(ras, palette, currNode);
|
|
Shinya Kitaoka |
120a6e |
if (currColor < 0) currColor = ras->pixels(p.y)[p.x].getInk();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int l, lCount = currNode.getLinksCount();
|
|
Shinya Kitaoka |
120a6e |
for (l = 0; l != lCount; ++l) {
|
|
Shinya Kitaoka |
120a6e |
nextNodeIdx = currNode.getLink(l).getNext();
|
|
Shinya Kitaoka |
120a6e |
Sequence &s = *currNode.link(l);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Check if outgoing sequence has current color (front) or not (back)
|
|
Shinya Kitaoka |
120a6e |
toOrder[s.m_strokeIndex].first =
|
|
Shinya Kitaoka |
120a6e |
(s.m_color == currColor) ? currHeight : currHeight - 1;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!(currNode.getLink(l).getAccess() == SORTED)) {
|
|
Shinya Kitaoka |
120a6e |
// Deal with this unchecked branch
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// If sequence was not split (due to color change)
|
|
Shinya Kitaoka |
120a6e |
if (!currGraph->getNode(s.m_tail).hasAttribute(SAMPLECOLOR_SIGN)) {
|
|
Shinya Kitaoka |
120a6e |
JointSequenceGraph::Node &nextNode = js->node(nextNodeIdx);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Then check nextNode
|
|
Shinya Kitaoka |
120a6e |
pD = *currGraph->getNode(nextNode.getLink(0)->m_head);
|
|
Shinya Kitaoka |
120a6e |
p = TPoint(pD.x, pD.y);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!ras->getBounds().contains(p)) continue;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// If nextNode was not already inserted in ToDo vector, do it now.
|
|
Shinya Kitaoka |
120a6e |
if (!nextNode.hasAttribute(SORTED)) {
|
|
Shinya Kitaoka |
120a6e |
// nextColor = getInkPredominance(ras, palette, p.x, p.y, (int)
|
|
Shinya Kitaoka |
120a6e |
// pD.z);
|
|
Shinya Kitaoka |
120a6e |
nextColor = getBranchPredominance(ras, palette, nextNode);
|
|
Shinya Kitaoka |
120a6e |
if (nextColor < 0) nextColor = ras->pixels(p.y)[p.x].getInk();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
nextHeight = (s.m_color == nextColor)
|
|
Shinya Kitaoka |
120a6e |
? toOrder[s.m_strokeIndex].first
|
|
Shinya Kitaoka |
120a6e |
: toOrder[s.m_strokeIndex].first + 1;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
nodesToDo.push_back(std::make_pair(nextNodeIdx, nextHeight));
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Deny access to its inverse (already processed now)
|
|
Shinya Kitaoka |
120a6e |
nextNode.link(js->tailLinkOf(currNodeIdx, l)).setAccess(SORTED);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
inline void orderColoredStrokes(JointSequenceGraphList &organizedGraphs,
|
|
Shinya Kitaoka |
120a6e |
std::vector<tstroke *=""> &strokes,</tstroke>
|
|
Shinya Kitaoka |
120a6e |
const TRasterCM32P &ras, TPalette *palette) {
|
|
Shinya Kitaoka |
120a6e |
// Initialize ordering
|
|
Shinya Kitaoka |
120a6e |
std::vector<std::pair<int, *="" tstroke="">> strokesByHeight(</std::pair<int,>
|
|
Shinya Kitaoka |
120a6e |
strokes.size(),
|
|
Shinya Kitaoka |
120a6e |
std::make_pair(-(std::numeric_limits<int>::max)(), (TStroke *)0));</int>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
size_t s, sCount = strokes.size();
|
|
Shinya Kitaoka |
120a6e |
for (s = 0; s != sCount; ++s) strokesByHeight[s].second = strokes[s];
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
size_t og, ogCount = organizedGraphs.size();
|
|
Shinya Kitaoka |
120a6e |
for (og = 0; og != ogCount; ++og)
|
|
Shinya Kitaoka |
120a6e |
sortJS(&organizedGraphs[og], strokesByHeight, ras, palette);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Now, we have the order vector filled, apply sorting algorithm.
|
|
Shinya Kitaoka |
120a6e |
std::sort(strokesByHeight.begin(), strokesByHeight.end());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
for (s = 0; s != sCount; ++s) strokes[s] = strokesByHeight[s].second;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//==========================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Take samples of image colors to associate each stroke to its corresponding
|
|
Shinya Kitaoka |
120a6e |
// palette color. Currently working on colormaps, closest-to-black strokes
|
|
Shinya Kitaoka |
120a6e |
// otherwise.
|
|
Shinya Kitaoka |
120a6e |
void applyStrokeColors(std::vector<tstroke *=""> &strokes, const TRasterP &ras,</tstroke>
|
|
Shinya Kitaoka |
120a6e |
TPalette *palette, VectorizerCoreGlobals &g) {
|
|
Shinya Kitaoka |
120a6e |
JointSequenceGraphList &organizedGraphs = g.organizedGraphs;
|
|
Shinya Kitaoka |
120a6e |
SequenceList &singleSequences = g.singleSequences;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TRasterCM32P cm = ras;
|
|
Shinya Kitaoka |
120a6e |
unsigned int i, j, k, n;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (cm && g.currConfig->m_maxThickness > 0.0) {
|
|
Shinya Kitaoka |
120a6e |
applyStrokeIndices(&g);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Treat single sequences before, like conversionToStrokes(..)
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < singleSequences.size(); ++i)
|
|
Shinya Kitaoka |
120a6e |
strokes[i]->setStyle(singleSequences[i].m_color);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Then, treat remaining graph-strokes
|
|
Shinya Kitaoka |
120a6e |
n = i;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < organizedGraphs.size(); ++i)
|
|
Shinya Kitaoka |
120a6e |
for (j = 0; j < organizedGraphs[i].getNodesCount(); ++j)
|
|
Shinya Kitaoka |
120a6e |
if (!organizedGraphs[i].getNode(j).hasAttribute(
|
|
Shinya Kitaoka |
120a6e |
JointSequenceGraph::ELIMINATED)) // due to junction recovery
|
|
Shinya Kitaoka |
120a6e |
for (k = 0; k < organizedGraphs[i].getNode(j).getLinksCount(); ++k) {
|
|
Shinya Kitaoka |
120a6e |
Sequence &s = *organizedGraphs[i].node(j).link(k);
|
|
Shinya Kitaoka |
120a6e |
if (s.isForward()) {
|
|
Shinya Kitaoka |
120a6e |
// vi->getStroke(n)->setStyle(s.m_color);
|
|
Shinya Kitaoka |
120a6e |
strokes[n]->setStyle(s.m_color);
|
|
Shinya Kitaoka |
120a6e |
++n;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Order vector image according to actual color-coverings at junctions.
|
|
Shinya Kitaoka |
120a6e |
orderColoredStrokes(organizedGraphs, strokes, cm, palette);
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
// Choose closest-to-black palette color
|
|
Shinya Kitaoka |
120a6e |
int blackStyleId = palette->getClosestStyle(TPixel32::Black);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
unsigned int i;
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < strokes.size(); ++i) strokes[i]->setStyle(blackStyleId);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|