📄 imshape.cpp
字号:
// $masm\imshape.cpp 1.5 milbo$ routines for drawing shapes, profiles, and images// Warning: this is raw research code -- expect it to be quite messy.// milbo durban dec05//-----------------------------------------------------------------------------// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// A copy of the GNU General Public License is available at// http://www.r-project.org/Licenses///-----------------------------------------------------------------------------#include "all.hpp"//-----------------------------------------------------------------------------// If fTransparent is set then the point is the average of Red Green Blue and the underlying image pointvoid SetImagePoint (RgbImage &Img, unsigned Red, unsigned Green, unsigned Blue, int ix, int iy, bool fTransparent){int width = Img.width, height = Img.height;ix += width / 2;iy += height / 2;int i = ix + iy * width;if (i > 0 && i < width * height) { if (fTransparent) { Img(ix, iy).Red = Img(ix, iy).Red/2 + Red/2; Img(ix, iy).Green = Img(ix, iy).Green/2 + Green/2; Img(ix, iy).Blue = Img(ix, iy).Blue/2 + Blue/2; } else { Img(ix, iy).Red = Red; Img(ix, iy).Green = Green; Img(ix, iy).Blue = Blue; } }}//-----------------------------------------------------------------------------// This function uses a Bresenham-like algorithm to draw a line from x0,y0 to x1,y1//// Based on "Bresenham-based supercover line algorithm" by// Eugen.Dedu www.ese-metz.fr/~dedu/projects/bresenhamvoid BresenhamDrawLine (RgbImage &Img, unsigned Red, unsigned Green, unsigned Blue, int x0, int y0, int x1, int y1, bool fTransparent){int i; // loop counterint yStep, xStep; // the step on y and x axisint Error; // the error accumulated during the incrementint ddy, ddx;int x = x0, y = y0;int dx = x1 - x0;int dy = y1 - y0;SetImagePoint(Img, Red, Green, Blue, x, y, fTransparent); // first pointif (dy < 0) { yStep = -1; dy = -dy; }else yStep = 1;if (dx < 0) { xStep = -1; dx = -dx; }else xStep = 1;ddy = 2 * dy;ddx = 2 * dx;if (ddx >= ddy) // first octant (0 <= slope <= 1) { Error = dx; // start in the middle of the square for (i = 0; i < dx; i++) // do not use the first point (already done) { x += xStep; Error += ddy; if (Error > ddx) // increment y if AFTER the middle (>) { y += yStep; Error -= ddx; } SetImagePoint(Img, Red, Green, Blue, x, y, fTransparent); } }else { Error = dy; for (i = 0; i < dy; i++) { y += yStep; Error += ddx; if (Error > ddy) { x += xStep; Error -= ddy; } SetImagePoint(Img, Red, Green, Blue, x, y, fTransparent); } }}//-----------------------------------------------------------------------------void ImageWhiskers (RgbImage &Img, const SHAPE &Shape, unsigned Color, double Scale, double ProfAngle, bool fTransparent, unsigned ProfType, const tLand Lands[], const SHAPE *pAlignedAvShape){ASSERT(Lands);unsigned Blue = Color & 0xff;unsigned Green = (Color >> 8) & 0xff;unsigned Red = (Color >> 16) & 0xff;int nPoints = Shape.nrows();for (int iPoint = 0; iPoint < nPoints; iPoint++) { if (!fPointUsed(Shape, iPoint)) continue; if ((ProfType & PROF_2d) == 0) // 1D prof? { double DeltaX, DeltaY; GetProfStepSize(&DeltaX, &DeltaY, Shape, iPoint, ProfAngle, Lands, *pAlignedAvShape); int nProfWidthEachSide = 8; // TODO this should actually be determined by the model // We don't use the standard line drawing routine because I want to show exact posn of sampled points // I've tried to make this match prof.cpp:PrepareProf1D() so we draw points in the exact same place // as we sample them for 1D profiles. for (int iSamplePoint = -nProfWidthEachSide; iSamplePoint <= nProfWidthEachSide; iSamplePoint++) SetImagePoint(Img, Red, Green, Blue, iRound(Scale * GetX(Shape(iPoint, VX), -iSamplePoint, 0, DeltaX, DeltaY)), iRound(Scale * GetY(Shape(iPoint, VY), -iSamplePoint, 0, DeltaX, DeltaY)), fTransparent); // draw single bright point to show start of whisker int ix1 = iRound(Scale * GetX(Shape(iPoint, VX), -nProfWidthEachSide, 0, DeltaX, DeltaY)); int iy1 = iRound(Scale * GetY(Shape(iPoint, VY), -nProfWidthEachSide, 0, DeltaX, DeltaY)); unsigned Red1 = __min(Red*2, 255), Green1 = __min(Green*2, 255), Blue1 = __min(Blue*2, 255); Red1 = 200; Green1 = 255; Blue1 = 200; //TODO makes point more visible than above colors SetImagePoint(Img, Red1, Green1, Blue1, ix1, iy1, IM_NO_TRANSPARENT); } else // 2D prof { SHAPE SubShape(5, 2); int x = Shape(iPoint, VX); int y = Shape(iPoint, VY); int nProfWidthEachSide = 5; // TODO this should actually be determined by the model nProfWidthEachSide += 1; // add 1 so square profile is contained in the outline SubShape(0, VX) = x - nProfWidthEachSide; SubShape(0, VY) = y - nProfWidthEachSide; SubShape(1, VX) = x - nProfWidthEachSide; SubShape(1, VY) = y + nProfWidthEachSide; SubShape(2, VX) = x + nProfWidthEachSide; SubShape(2, VY) = y + nProfWidthEachSide; SubShape(3, VX) = x + nProfWidthEachSide; SubShape(3, VY) = y - nProfWidthEachSide; SubShape(4, VX) = x - nProfWidthEachSide; SubShape(4, VY) = y - nProfWidthEachSide; // connect back to first vertex DrawShape(Img, SubShape, Color, Scale, IM_CONNECT_DOTS, IM_NO_ANNOTATE, IM_NO_WHISKERS, 0, fTransparent); } }}//-----------------------------------------------------------------------------// Draw Shape in the image Img in the specified Color// Lands and AlignedAvShape are only used if fWhiskers is true// fAnnotate is ignored if image is too small for letteringvoid DrawShape (RgbImage &Img, // io const SHAPE &Shape, unsigned Color, double Scale, // in bool fConnectTheDots, bool fAnnotate, // in bool fWhiskers, unsigned ProfType, bool fTransparent, // in: ProfType determines what type of "whisker" to draw const tLand Lands[], const SHAPE *pAlignedAvShape, // in bool fDrawCircleAtLandmark, // in: current implementation is very slow unsigned ConnectDotsColor) // in: color used to connect dots, -1 to use same as dot color{unsigned Red = (Color >> 16) & 0xff;unsigned Green = (Color >> 8) & 0xff;unsigned Blue = Color & 0xff;int iFirstPoint = -1, iPoint1 = 0;int nPoints = Shape.nrows();for (int iPoint = 0; iPoint < nPoints; iPoint++) { if (!fPointUsed(Shape, iPoint)) continue; if (iFirstPoint == -1) iFirstPoint = iPoint; if (iPoint < nPoints-1) iPoint1 = iPoint + 1; while (iPoint1 < nPoints && !fPointUsed(Shape, iPoint1)) iPoint1++;#if 1 // july 2007: fixes bug which was a fencepost error when coord changes sign int ix = iRound(Scale * Shape(iPoint, VX)); int iy = iRound(Scale * Shape(iPoint, VY));#else // TODO old code int ix = int(Scale * Shape(iPoint, VX) + 0.5); int iy = int(Scale * Shape(iPoint, VY) + 0.5);#endif if (fConnectTheDots && iPoint1 < nPoints && (CONF_fSkipExtraEyeLinesInDisplayedShape || iPoint1 < MLEye0 || iPoint1 > MREye7)) { unsigned Red1 = Red; unsigned Green1 = Green; unsigned Blue1 = Blue; bool fTransparent1 = false; if (ConnectDotsColor != -1) { Red1 = (ConnectDotsColor >> 16) & 0xff; Green1 = (ConnectDotsColor >> 8) & 0xff; Blue1 = ConnectDotsColor & 0xff; fTransparent1 = true; } BresenhamDrawLine(Img, Red1, Green1, Blue1, ix, iy, iRound(Scale * Shape(iPoint1, VX)), iRound(Scale * Shape(iPoint1, VY)), fTransparent1); }#if 0 // connect first and last point BresenhamDrawLine(Img, Red, Green, Blue, iRound(Scale * Shape(nPoints-1, VX)), iRound(Scale * Shape(nPoints-1, VY)), iRound(Scale * Shape(0, VX)), iRound(Scale * Shape(0, VY)), fTransparent);#endif SetImagePoint(Img, Red, Green, Blue, ix, iy, FALSE);#if 0 //TODO different color i.e. green for extra eye landmarks if (iPoint > 67) SetImagePoint(Img, 0, 255, 0, ix, iy, FALSE);#endif if (fDrawCircleAtLandmark) // in { // draw circle at landmark (current implementation is very slow) int ix1 = ix + Img.width / 2; int iy1 = Img.height / 2 - iy; RgbEllipse(Img, ix1-3, iy1-3, ix1+3, iy1+3, Red, Green, Blue); } if (fAnnotate) { double xExtent = xShapeExtent(Shape); int iFontSize; if (xExtent > 100) iFontSize = 200; if (xExtent > 50) iFontSize = 100; else iFontSize = 60; RgbPrintf(Img, Img.width/2 + ix + 2, Img.height/2 - iy, Color, iFontSize, "%d", iPoint); } }if (fWhiskers) ImageWhiskers(Img, Shape, C_GREEN, Scale, 0, fTransparent, ProfType, Lands, pAlignedAvShape);}//-----------------------------------------------------------------------------// Like DrawShape but accepts a grayscale image and returns the color image// and even more horrid number of parametersvoid DrawShape1 (RgbImage &Img, // out const Image &InImg, const SHAPE &Shape1, const SHAPE *pShape2, unsigned Color, double Scale, // in bool fConnectTheDots, bool fAnnotate, // in bool fWhiskers, unsigned ProfType, bool fTransparent, bool fCropToFace, // in const tLand Lands[], const SHAPE *pAlignedAvShape, bool fDrawCircleAtLandmark) // in{ConvertGrayImageToRgb(Img, InImg);if (Scale != 1.0) ScaleRgbImage(Img, Img.width * Scale, Img.height * Scale);DrawShape(Img, Shape1, Color, Scale, fConnectTheDots, fAnnotate, fWhiskers, ProfType, fTransparent, Lands, pAlignedAvShape, fDrawCircleAtLandmark);if (pShape2) // optional extra shape, dots not connected DrawShape(Img, *pShape2, C_YELLOW, Scale, IM_NO_CONNECT_DOTS, IM_NO_ANNOTATE, IM_NO_WHISKERS, 0, IM_TRANSPARENT);if (fCropToFace) { DASSERT(pAlignedAvShape); CropImageToFace(Img, *pAlignedAvShape, Scale); }}//-----------------------------------------------------------------------------// If you want high resolution images, set Scale to something bigger than 1 like 2.// If you want to see the exact original image, use Scale=1//// If Scale>1, the image doesn't really have a higher resolution, because we are // simply scaling up, not adding information. But it has a bigger width and height// and the drawn landmark mesh is correspondingly finer, which can be useful.void ImageAllShapes (const SHAPE aShapes[], Image aImages[], char *saTags[], int nShapes, double Scale, bool fCropToFace, const SHAPE &AvShape, const tLand Lands[]){lprintf(" Writing images and shapes ");InitPacifyUser(nShapes);for (int iShape = 0; iShape < nShapes; iShape++) { PacifyUser(iShape); // show AlignedAvShape as well -- to do this get AvShape and align it to this shape SHAPE AlignedAvShape(AvShape); AlignShape(AlignedAvShape, aShapes[iShape]); RgbImage Img; DrawShape1(Img, aImages[iShape], aShapes[iShape], &AlignedAvShape, C_DRED, Scale, IM_CONNECT_DOTS, IM_ANNOTATE, IM_WHISKERS, 0, IM_TRANSPARENT, IM_CROP_TO_FACE, Lands, &AlignedAvShape); char sPath[SLEN]; sprintf(sPath, "%s/_%s", CONF_sOutDir, &saTags[iShape][FNAME_OFFSET]); WriteBmp(Img, sPath); }lprintf("0\n");}//-----------------------------------------------------------------------------static void DrawGridPoint (tRGB *p, int iRow, int iProf, int ncols1, int ncols){if (ncols1 > 1 && (iRow == ncols1/2 || iRow == ncols1/2+1)) // center row? { p->Red = 0; p->Green = 0; p->Blue = 0; } // blackelse if (ncols > 1 && (iProf == ncols/2 || iProf == ncols/2+1)) // center col? { p->Red = 0; p->Green = 0; p->Blue = 0; } // blackelse { p->Red = 42; p->Green = 137; p->Blue = 38; } // green}//-----------------------------------------------------------------------------// Crop the image so face fills whole imagevoid CropImageToFace (RgbImage &Img, // io const SHAPE &Shape, double Scale, bool fWideMargins) // in{// We can only crop the image to the face if certain face points are present// to tell us where the face is. So check first with this if statement.int nrows = Shape.nrows();if (nrows >= MLInnerTopEyeBrow // prevent index range error && iTranslatedPoint(MLInnerTopEyeBrow) < nrows && iTranslatedPoint(MTipOfChin) < nrows && iTranslatedPoint(MLJaw1) < nrows && iTranslatedPoint(MRJaw1) < nrows && fPointUsed(Shape, iTranslatedPoint(MLInnerTopEyeBrow)) && fPointUsed(Shape, iTranslatedPoint(MTipOfChin)) && fPointUsed(Shape, iTranslatedPoint(MLJaw1)) && fPointUsed(Shape, iTranslatedPoint(MRJaw1))) { int width = Img.width, height = Img.height; double Margin = 20, BottomMargin = 50; // magic 20 and 50 provide additional offset, values found empirically if (fWideMargins) { Margin *= 3; BottomMargin *= 3; } int iTopCrop = __max(height/2 - Scale * Shape(iTranslatedPoint(MLInnerTopEyeBrow), VY) - Margin, 0); int iBottomCrop = __max(height/2 + Scale * Shape(iTranslatedPoint(MTipOfChin), VY) - BottomMargin, 0); int iLeftCrop = __max(width/2 + Scale * Shape(iTranslatedPoint(MLJaw1), VX) - Margin, 0); int iRightCrop = __max(width/2 - Scale * Shape(iTranslatedPoint(MRJaw1), VX) - Margin, 0); CropRgbImage(Img, iTopCrop, iBottomCrop, iLeftCrop, iRightCrop, QUIET, IM_WIDTH_DIVISIBLE_BY_4); }}//-----------------------------------------------------------------------------// crop the image so the shape fills the whole imagevoidCropImageToShape (RgbImage &Img, // io const SHAPE &Shape) // in{// increase the following margins if you want more room around the shapedouble xMargin = 20, yMargin = 30;#define MAX(x,y) (((x) > (y)) ? (x) : (y))int nLeftCrop = int(MAX(0, Img.width/2 + Shape.col(VX).minElem() - xMargin)); int nRightCrop = int(MAX(0, Img.width/2 - Shape.col(VX).maxElem() - xMargin)); int nTopCrop = int(MAX(0, Img.height/2 - Shape.col(VY).maxElem() - yMargin)); int nBottomCrop = int(MAX(0, Img.height/2 + Shape.col(VY).minElem() - yMargin)); CropRgbImage(Img, nTopCrop, nBottomCrop, nLeftCrop, nRightCrop, QUIET, IM_WIDTH_DIVISIBLE_BY_4);}//-----------------------------------------------------------------------------// Get font size appropriate for image sizeint iGetFontSize (unsigned ImageBits){if (ImageBits & IM_DoubleScale) return 240;else if (ImageBits & IM_FullScale) return 160;else return 80;}//-----------------------------------------------------------------------------// Get output image scale based on ImageBitsdouble GetScaleOut (unsigned ImageBits, int iLev){if (ImageBits & IM_DoubleScale) return 2 * pow(2, iLev);else if (ImageBits & IM_FullScale) return pow(2, iLev);else return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -