vcglib/wrap/qt/Outline2ToQImage.cpp

453 lines
14 KiB
C++

#include "Outline2ToQImage.h"
#include <wrap/qt/col_qt_convert.h>
using namespace vcg;
using namespace std;
void Outline2Dumper::rectSetToOutline2Vec(vector< Box2f > &rectVec, vector< vector<Point2f> > &outline2Vec)
{
outline2Vec.clear();
for(size_t i=0;i<rectVec.size();++i)
{
Box2f &b=rectVec[i];
outline2Vec.resize(outline2Vec.size()+1);
outline2Vec.back().push_back(b.min);
outline2Vec.back().push_back(Point2f(b.max[0],b.min[1]));
outline2Vec.back().push_back(b.max);
outline2Vec.back().push_back(Point2f(b.min[0],b.max[1]));
}
}
void Outline2Dumper::multiRectSetToSingleOutline2Vec(vector< Box2f > &rectVec,
vector<Similarity2f> &trVec, vector<int> &indVec,
int ind, vector< vector<Point2f> > &outline2Vec,
vector<Similarity2f> &trOutline2Vec)
{
outline2Vec.clear();
trOutline2Vec.clear();
for(size_t i=0;i<rectVec.size();++i)
if(indVec[i]==ind)
{
trOutline2Vec.push_back(trVec[i]);
Box2f &b=rectVec[i];
outline2Vec.resize(outline2Vec.size()+1);
outline2Vec.back().push_back(b.min);
outline2Vec.back().push_back(Point2f(b.max[0],b.min[1]));
outline2Vec.back().push_back(b.max);
outline2Vec.back().push_back(Point2f(b.min[0],b.max[1]));
}
}
void Outline2Dumper::multiOutline2VecToSingleOutline2Vec(const std::vector< std::vector<Point2f> > &multiPolyVec,
const std::vector<Similarity2f> &multiTrVec,
const std::vector<int> &indVec, int ind,
std::vector< std::vector<Point2f> > &singlePolyVec,
std::vector<Similarity2f> &singleTrVec)
{
singlePolyVec.clear();
singleTrVec.clear();
for(size_t i=0;i<multiPolyVec.size();++i)
if(indVec[i]==ind)
{
singleTrVec.push_back(multiTrVec[i]);
singlePolyVec.resize(singlePolyVec.size()+1);
singlePolyVec.back()=multiPolyVec[i];
}
}
void Outline2Dumper::dumpOutline2VecSVG(const char * imageName,
vector< vector<Point2f> > &outline2Vec,
vector<Similarity2f> &trVec,
Outline2Dumper::Param &pp)
{
vector< vector< vector<Point2f> > > outline2VecVec(outline2Vec.size());
for(size_t i=0;i<outline2Vec.size();++i)
{
outline2VecVec[i].resize(1);
outline2VecVec[i][0]=outline2Vec[i];
}
dumpOutline2VecSVG(imageName,outline2VecVec,trVec,pp);
}
void Outline2Dumper::dumpOutline2VecPNG(const char * imageName, vector< vector<Point2f> > &polyVec, vector<Similarity2f> &trVec, Outline2Dumper::Param &pp)
{
vector< vector< vector<Point2f> > > polyVecVec(polyVec.size());
for(size_t i=0;i<polyVec.size();++i)
{
polyVecVec[i].resize(1);
polyVecVec[i][0]=polyVec[i];
}
dumpOutline2VecPNG(imageName,polyVecVec,trVec,pp);
}
void Outline2Dumper::dumpOutline2VecPNG(const char * imageName, vector< vector< vector<Point2f> > > &polyVecVec, vector<Similarity2f> &trVec, Outline2Dumper::Param &pp)
{
vector<string> labelVec;
dumpOutline2VecPNG(imageName,polyVecVec,trVec,labelVec,pp);
}
void Outline2Dumper::dumpOutline2VecSVG(const char * imageName, vector< vector< vector<Point2f> > > &polyVecVec, vector<Similarity2f> &trVec, Outline2Dumper::Param &pp)
{
vector<string> labelVec(polyVecVec.size());
dumpOutline2VecSVG(imageName,polyVecVec,trVec,labelVec,pp);
}
///this class draw a black mask fora given polygon, cenetered and scaled to fit with
///the image size, it return the transformation to tranform back the polygon to 2D space
void Outline2Dumper::DrawPolygonMask(const vector< vector<Point2f> > &polyVec,
QImage &img,
Similarity2f &ret,
const Similarity2f &trans)
{
///RASTERIZE THE POLYGON
QPainter painter;
painter.begin(&img);
QBrush bb;
bb.setStyle(Qt::SolidPattern);
int resolution=img.width();
QPen qp;
qp.setWidthF(0);
///find the BB
vcg::Box2f bbox;
for(size_t i=0;i<polyVec.size();++i)
for(size_t j=0;j<polyVec[i].size();++j)
{
Point2f pp=polyVec[i][j];
pp.Rotate(trans.rotRad);
bbox.Add(pp);
}
vcg::Point2f pos=bbox.Center();
float scaleFact=(resolution/bbox.Diag());
///SET THE TRANSFORMATION TO CENTER WRT BBOX
painter.resetTransform();
painter.translate(resolution/2,resolution/2);
painter.rotate(math::ToDeg(trans.rotRad));
painter.scale(scaleFact,scaleFact);
painter.translate(-pos.V(0),-pos.V(1));
///SET TO RETURN BACK
ret.rotRad=0;
ret.sca=scaleFact;
ret.tra[0]=-pos.V(0)*scaleFact + resolution/2;
ret.tra[1]=-pos.V(1)*scaleFact + resolution/2;
///DRAW THE POLYGON
QPainterPath QPP;
for(size_t i=0;i<polyVec.size();++i)
{
QVector<QPointF> ppQ;
for(size_t j=0;j<polyVec[i].size();++j)
{
Point2f pp=polyVec[i][j];
//pp.Rotate(trans.rotRad);
ppQ.push_back(QPointF(pp[0],pp[1]));
}
ppQ.push_back(QPointF(polyVec[i][0][0],polyVec[i][0][1]));
QPP.addPolygon(QPolygonF(ppQ));
}
painter.setBrush(bb);
painter.setPen(qp);
painter.drawPath(QPP);
painter.end();
//img.save("test.png");
}
///return the max radius of a point inside a polygon ,given the mask image
///actually it evaluate the maximum bounding box
int Outline2Dumper::getMaxMaskRadius(int x,int y,QImage &img)
{
int sizeY=img.size().height();
int sizeX=img.size().width();
int Max_radiusX=std::min(abs(x-sizeX),x);
int Max_radiusY=std::min(abs(y-sizeY),y);
int Max_radius=std::min(Max_radiusX,Max_radiusY);
int val=qGray(img.pixel(x,y));
///if is outside
assert(val!=255);
int curr_radius=1;
while (curr_radius<Max_radius)
{
vcg::Box2i currBB=vcg::Box2i(vcg::Point2i(x,y),vcg::Point2i(x,y));
vcg::Box2i InsideBB=currBB;
currBB.Offset(curr_radius);
InsideBB.Offset(curr_radius-1);
///check on borders
for (int x0=currBB.min.X();x0<=currBB.max.X();x0++)
for (int y0=currBB.min.Y();y0<=currBB.max.Y();y0++)
{
if (InsideBB.IsIn(vcg::Point2i(x0,y0)))continue;
int val=qGray(img.pixel(x0,y0));
///if is outside
if (val==255)
return curr_radius;
}
curr_radius++;
}
return curr_radius;
}
///return the point inside the polygon with the bigger distance to the border,
///this is used to write labels within the polygon, it handle polygons with holes too
vcg::Point2f Outline2Dumper::GetIncenter(const vector< vector<Point2f> > &polyVec,
const Similarity2f &tra1,
float &radius,
int resolution)
{
///INITIALIZE THE IMAGE
QImage img(resolution,resolution,QImage::Format_RGB32);
img.fill(vcg::ColorConverter::ToQColor(vcg::Color4b::White));
Similarity2f tra0;
///DRAW THE MASK
DrawPolygonMask(polyVec,img,tra0,tra1);
//img = img.mirrored(false,true);
///THEN FIND THE CENTROID
float Maxradius=-1;
int sizeY=img.size().height();
int sizeX=img.size().width();
vcg::Point2i incenter=vcg::Point2i(sizeX/2,sizeY/2);
///THEN GO OVER ALL VERTICES
for (int x=0;x<sizeX;x++)
for (int y=0;y<sizeY;y++)
{
///flipped because of
///same artifacts of Mquads
int val=qGray(img.pixel(x,y));
///if is outside
if (val==255)continue;
int curr_radius=getMaxMaskRadius(x,y,img);
if (curr_radius>Maxradius)
{
Maxradius=curr_radius;
incenter=vcg::Point2i(x,y);
}
}
vcg::Point2f incenterf;
incenterf.Import(incenter);
// /FIRST TRASNFORMATION
// QPainter painter;
// painter.begin(&img);
// //painter.fillRect(incenter.V(0)-Maxradius,incenter.V(1)-Maxradius,Maxradius*2,Maxradius*2,Qt::red);
//// painter.fillRect(incenter.V(0)-1,incenter.V(1)-1,2,2,Qt::red);
// //painter.drawPoint(incenter.V(0),incenter.V(1));
// painter.end();
// static int num=0;
// num++;
// char path[100];
// sprintf(path,"mask%d.png",num);
// img.save(path);
incenterf.X()-=tra0.tra[0];
incenterf.Y()-=tra0.tra[1];
incenterf*=1.0/tra0.sca;
incenterf*=tra1.sca;
///SECOND TRANSFORMATION
assert(Maxradius>0);
radius=Maxradius;
return incenterf;
}
///write a polygon on a PNG file, format of the polygon is vector of vector of contours...nested contours are holes
///takes the name of the image in input, the set of polygons, the set of per polygons transformation,
///the label to be written and the global parameter for drawing style
void Outline2Dumper::dumpOutline2VecPNG(const char * imageName,
vector< vector< vector<Point2f> > > &polyVecVec,
vector<Similarity2f> &trVec,
vector<string> &labelVec,
Param &pp)
{
///SET THE FONT
assert(polyVecVec.size() == trVec.size());
int fontSize=ceil(std::max(pp.width,pp.height)/100.0);
QFont qf("courier",fontSize);
///SET THE DRAWING SIZE
QImage img(pp.width,pp.height,QImage::Format_RGB32);
img.fill(vcg::ColorConverter::ToQColor( pp.backgroundColor).rgb());
///SETUP OF DRAWING PROCEDURE
QPainter painter;
painter.begin(&img);
QBrush bb;
if (pp.fill)
bb.setStyle(Qt::SolidPattern);
QPen qp;
qp.setWidthF(0);
for(size_t i=0;i<polyVecVec.size();++i)
{
///SET THE CURRENT TRANSFORMATION
painter.resetTransform();
painter.translate(trVec[i].tra[0],trVec[i].tra[1]);
painter.rotate(math::ToDeg(trVec[i].rotRad));
painter.scale(trVec[i].sca,trVec[i].sca);
QPainterPath QPP;
for(size_t jj=0;jj<polyVecVec[i].size();++jj)
{
QVector<QPointF> ppQ;
for(size_t j=0;j<polyVecVec[i][jj].size();++j)
{
Point2f pp=polyVecVec[i][jj][j];
ppQ.push_back(QPointF(pp[0],pp[1]));
}
ppQ.push_back(QPointF(polyVecVec[i][jj][0][0],polyVecVec[i][jj][0][1]));
QPP.addPolygon(QPolygonF(ppQ));
}
if (pp.randomColor)
bb.setColor(vcg::ColorConverter::ToQColor(Color4b::Scatter(polyVecVec.size(),i)));
else
bb.setColor(vcg::ColorConverter::ToQColor(pp.FillColor));
painter.setBrush(bb);
painter.setPen(qp);
painter.drawPath(QPP);
if(!labelVec.empty())
{
///FIND THE BARYCENTER
float radius;
Point2f bc=GetIncenter(polyVecVec[i],trVec[i],radius,10);
///DRAW THE TEXT
painter.setFont(qf);
painter.resetTransform();
painter.translate(trVec[i].tra[0],trVec[i].tra[1]);
painter.drawText(bc[0]-radius,bc[1]-radius,radius*2,radius*2,Qt::AlignHCenter|Qt::AlignCenter,QString(labelVec[i].c_str()));
}
}
painter.end();
img.save(imageName);
}
///write a polygon on a SVG file, format of the polygon is vector of vector of contours...nested contours are holes
///takes the name of the image in input, the set of polygons, the set of per polygons transformation,
///the label to be written and the global parameter for drawing style
void Outline2Dumper::dumpOutline2VecSVG(const char * imageName,
vector< vector< vector<Point2f> > > &outline2VecVec,
vector<Similarity2f> &trVec,
vector< vector< string> > &labelVecVec,
vector< vector<Similarity2f> > &labelTrVecVec,
vector<vector<float> >&labelRadVecVec,
Outline2Dumper::Param &pp)
{
assert(outline2VecVec.size() == trVec.size());
///SET THE FONT
int fontSize;
if(pp.fontSize==0) fontSize=ceil(std::max(pp.width,pp.height)/200.0);
else fontSize=pp.fontSize;
QFont qf("courier",fontSize);
QSvgGenerator svg;
svg.setFileName(imageName);
///SET THE DRAWING SIZE
svg.setSize(QSize(pp.width,pp.height));
svg.setViewBox(QRect(0, 0, pp.width,pp.height));
svg.setResolution(int(pp.dpi));//
///SETUP OF DRAWING PROCEDURE
QPainter painter;
painter.begin(&svg);
QBrush bb;
if (pp.fill)
bb.setStyle(Qt::SolidPattern);
QPen qp;
///SET THE GLOBAL SCALING FACTOR
for(size_t i=0;i<outline2VecVec.size();++i)
{
// we assume that
float scalingFactorforPenWidth=1.f/(float)trVec[i].sca;
qp.setWidthF(pp.penWidth*scalingFactorforPenWidth);
qp.setColor(vcg::ColorConverter::ToQColor(pp.lineColor));
///SET THE CURRENT TRANSFORMATION
painter.resetTransform();
painter.translate(trVec[i].tra[0],trVec[i].tra[1]);
painter.rotate(math::ToDeg(trVec[i].rotRad));
painter.scale(trVec[i].sca,trVec[i].sca);
QPainterPath QPP;
for(size_t jj=0;jj<outline2VecVec[i].size();++jj)
{
QVector<QPointF> ppQ;
for(size_t j=0;j<outline2VecVec[i][jj].size();++j)
{
Point2f pp=outline2VecVec[i][jj][j];
ppQ.push_back(QPointF(pp[0],pp[1]));
}
ppQ.push_back(QPointF(outline2VecVec[i][jj][0][0],outline2VecVec[i][jj][0][1]));
QPP.addPolygon(QPolygonF(ppQ));
}
///FIND THE INCENTER
if (pp.randomColor)
bb.setColor(vcg::ColorConverter::ToQColor(Color4b::Scatter(outline2VecVec.size(),i)));
else
bb.setColor(vcg::ColorConverter::ToQColor(pp.FillColor));
///DRAW THE POLYGON
painter.setBrush(bb);
painter.setPen(qp);
painter.drawPath(QPP);
///DRAW THE TEXT
painter.setFont(qf);
float radius;
// int radiusInt;
Point2f bc;
// if we do not have labelPos use the old method of empty disk.
if(labelTrVecVec.empty()) bc=GetIncenter(outline2VecVec[i],trVec[i],radius);
// radius = radiusInt;
for(size_t labelInd=0;labelInd<labelVecVec[i].size();++labelInd)
{
if(!labelTrVecVec.empty())
{
bc = labelTrVecVec[i][labelInd].tra;
bc.Rotate(trVec[i].rotRad);
bc *= trVec[i].sca;
radius=labelRadVecVec[i][labelInd];
radius *= trVec[i].sca;
}
painter.resetTransform();
painter.translate(trVec[i].tra[0],trVec[i].tra[1]);
qp.setColor(vcg::ColorConverter::ToQColor(pp.labelColor));
painter.setPen(qp);
painter.drawText(bc[0]-radius,bc[1]-radius,radius*2,radius*2,Qt::AlignHCenter|Qt::AlignCenter,QString(labelVecVec[i][labelInd].c_str()));
}
}
painter.end();
}
void Outline2Dumper::dumpOutline2VecSVG(const char * imageName,
vector< vector< vector<Point2f> > > &polyVecVec,
vector<Similarity2f> &trVec,
vector< string > &labelVec,
Outline2Dumper::Param &pp)
{
vector< vector< string> > labelVecVec(labelVec.size());
vector< vector<Similarity2f> > labelTrVec;
vector< vector<float> >labelRadVec;
for(size_t i=0;i<labelVec.size();++i)
{
labelVecVec[i].push_back(labelVec[i]);
}
dumpOutline2VecSVG(imageName,polyVecVec,trVec,labelVecVec,labelTrVec,labelRadVec,pp);
}