#include "PolyToQImage.h" #include <wrap/qt/col_qt_convert.h> using namespace vcg; using namespace std; void PolyDumper::rectSetToPolySet(vector< Box2f > &rectVec, vector< vector<Point2f> > &polyVec) { polyVec.clear(); for(size_t i=0;i<rectVec.size();++i) { Box2f &b=rectVec[i]; polyVec.resize(polyVec.size()+1); polyVec.back().push_back(b.min); polyVec.back().push_back(Point2f(b.max[0],b.min[1])); polyVec.back().push_back(b.max); polyVec.back().push_back(Point2f(b.min[0],b.max[1])); } } void PolyDumper::dumpPolySetSVG(const char * imageName, vector< vector<Point2f> > &polyVec, vector<Similarity2f> &trVec, PolyDumperParam &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]; } dumpPolySetSVG(imageName,polyVecVec,trVec,pp); } void PolyDumper::dumpPolySetPNG(const char * imageName, vector< vector<Point2f> > &polyVec, vector<Similarity2f> &trVec, PolyDumperParam &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]; } dumpPolySetPNG(imageName,polyVecVec,trVec,pp); } void PolyDumper::dumpPolySetPNG(const char * imageName, vector< vector< vector<Point2f> > > &polyVecVec, vector<Similarity2f> &trVec, PolyDumperParam &pp) { vector<string> labelVec(polyVecVec.size()); dumpPolySetPNG(imageName,polyVecVec,trVec,labelVec,pp); } void PolyDumper::dumpPolySetSVG(const char * imageName, vector< vector< vector<Point2f> > > &polyVecVec, vector<Similarity2f> &trVec, PolyDumperParam &pp) { vector<string> labelVec(polyVecVec.size()); dumpPolySetSVG(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 PolyDumper::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 PolyDumper::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 PolyDumper::GetIncenter(const vector< vector<Point2f> > &polyVec, const Similarity2f &tra1, int &radius, int resolution) { ///INITIALIZE THE IMAGE QImage img(resolution,resolution,QImage::Format_RGB32); img.fill(vcg::ColorConverter::ToQColor(vcg::Color4b(255,255,255,255)).rgb()); 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 PolyDumper::dumpPolySetPNG(const char * imageName, vector< vector< vector<Point2f> > > &polyVecVec, vector<Similarity2f> &trVec, vector<string> &labelVec, PolyDumperParam &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)); } ///FIND THE BARYCENTER int radius; Point2f bc; bc=GetIncenter(polyVecVec[i],trVec[i],radius,100); 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); ///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 PolyDumper::dumpPolySetSVG(const char * imageName, vector< vector< vector<Point2f> > > &polyVecVec, vector<Similarity2f> &trVec, vector< vector< string> > &labelVecVec, vector<vector<Point2f> > &labelPosVecVec, vector<vector<float> >&labelRadVecVec, PolyDumperParam &pp) { assert(polyVecVec.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 float Scalesvg=1.f/(float)trVec[0].sca; qp.setWidthF(Scalesvg); 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)); } ///FIND THE INCENTER if (pp.randomColor) bb.setColor(vcg::ColorConverter::ToQColor(Color4b::Scatter(polyVecVec.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(labelPosVecVec.empty()) bc=GetIncenter(polyVecVec[i],trVec[i],radiusInt); radius = radiusInt; for(size_t labelInd=0;labelInd<labelVecVec[i].size();++labelInd) { if(!labelPosVecVec.empty()) { bc= labelPosVecVec[i][labelInd]; 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]); 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 PolyDumper::dumpPolySetSVG(const char * imageName, vector< vector< vector<Point2f> > > &polyVecVec, vector<Similarity2f> &trVec, vector< string > &labelVec, PolyDumperParam &pp) { vector< vector< string> > labelVecVec(labelVec.size()); vector< vector<Point2f> > labelPosVec; vector< vector<float> >labelRadVec; for(size_t i=0;i<labelVec.size();++i) { labelVecVec[i].push_back(labelVec[i]); } dumpPolySetSVG(imageName,polyVecVec,trVec,labelVecVec,labelPosVec,labelRadVec,pp); }