C++ GDI+ how to draw rectangle with border radius - c++

This is how I draw a rectangle using GDI+.
Graphics g(hdc);
SolidBrush blueColor((Color(255, 74, 134, 232)));
g.FillRectangle(&blueColor, x, y, width, height);
DeleteObject(&blueColor);
Now I want to add some border-radius, how can I do that?

You can implement this function through GraphicsPath::AddArc and related APIs.
Some code that worked for me:
void GetRoundRectPath(GraphicsPath *pPath, Rect r, int dia)
{
// diameter can't exceed width or height
if(dia > r.Width) dia = r.Width;
if(dia > r.Height) dia = r.Height;
// define a corner
Rect Corner(r.X, r.Y, dia, dia);
// begin path
pPath->Reset();
// top left
pPath->AddArc(Corner, 180, 90);
// tweak needed for radius of 10 (dia of 20)
if(dia == 20)
{
Corner.Width += 1;
Corner.Height += 1;
r.Width -=1; r.Height -= 1;
}
// top right
Corner.X += (r.Width - dia - 1);
pPath->AddArc(Corner, 270, 90);
// bottom right
Corner.Y += (r.Height - dia - 1);
pPath->AddArc(Corner, 0, 90);
// bottom left
Corner.X -= (r.Width - dia - 1);
pPath->AddArc(Corner, 90, 90);
// end path
pPath->CloseFigure();
}
void DrawRoundRect(Graphics* pGraphics, Rect r, Color color, int radius, int width)
{
int dia = 2*radius;
// set to pixel mode
int oldPageUnit = pGraphics->SetPageUnit(UnitPixel);
// define the pen
Pen pen(color, 1);
pen.SetAlignment(PenAlignmentCenter);
// get the corner path
GraphicsPath path;
// get path
GetRoundRectPath(&path, r, dia);
// draw the round rect
pGraphics->DrawPath(&pen, &path);
// if width > 1
for(int i=1; i<width; i++)
{
// left stroke
r.Inflate(-1, 0);
// get the path
GetRoundRectPath(&path, r, dia);
// draw the round rect
pGraphics->DrawPath(&pen, &path);
// up stroke
r.Inflate(0, -1);
// get the path
GetRoundRectPath(&path, r, dia);
// draw the round rect
pGraphics->DrawPath(&pen, &path);
}
// restore page unit
pGraphics->SetPageUnit((Unit)oldPageUnit);
}
More references: RoundRect, WINAPI Edit control with custom border

Related

How to erace (delete) the filled cairo shape?

I want to paint a rectangle to select the area according to mouse coordinates. So, the rectangle should be created and deleted every frame (the if statement below executes every frame). I was trying to call these functions, but nothing happened - shapes were painting one above another.
cairo_surface_destroy(surface);
cairo_destroy(cr);
if (xevent.type == MotionNotify && isPressed == true)
{
int tmp_x = xevent.xmotion.x_root;
int tmp_y = xevent.xmotion.y_root;
int scr = DefaultScreen(xdisplay);
cairo_surface_t *surface = cairo_xlib_surface_create(xdisplay, xroot, DefaultVisual(xdisplay, scr), DisplayWidth(xdisplay, scr), DisplayHeight(xdisplay, scr));
cairo_t *cr = cairo_create(surface);
cairo_rectangle(cr, init_x, init_y, tmp_x - init_x, tmp_y - init_y); /* set rectangle */
cairo_set_source_rgba(cr, 0.3, 0.4, 0.6, 0.1); /* set fill color */
cairo_fill(cr);
cairo_destroy(cr);
}

ALLEGRO5 change pixel color of text based on background

First attempt:
void Tower::_DrawHealthBarText(std::string text, int x, int y, ALLEGRO_FONT* font)
{
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
ALLEGRO_BITMAP* bmp = al_create_bitmap(196, 17);
int bmpIndex[196][17] = { };
al_set_target_bitmap(bmp);
al_draw_rectangle(5, 20, 200, 20 + 15, al_map_rgb(255, 255, 255), 1.0f);
al_draw_filled_rectangle(5, 20, 5 - 195.0f + ((195.0f / _player->playerMaxHealth) * _player->playerHealth) + 195.0f, 20 + 15, al_map_rgb(255, 255, 255));
al_draw_filled_rectangle(4, 19, 201, 20 + 15 + 1, al_map_rgb(0, 0, 0));
for (int x = 0; x < 196; x++)
{
for (int y = 0; y < 17; y++)
{
unsigned char r, g, b;
al_unmap_rgb(al_get_pixel(bmp, x, y), &r, &g, &b);
if ((r + g + b) / 3 == 255)
{
bmpIndex[x][y] = 0;
}
else if ((r + g + b) / 3 == 0)
{
bmpIndex[x][y] = 1;
}
}
}
// Clear to transparent background
al_clear_to_color(rgba(0, 0, 0, 0));
al_draw_text(getFont(12), al_map_rgb(255, 255, 255), 0, 0, 0, text.c_str());
al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP);
al_set_target_backbuffer(g_Window);
al_draw_bitmap(bmp, x, y, 0);
al_destroy_bitmap(bmp);
}
Second attempt:
int bmpIndex[196][17] = { };
void Tower::_DrawHealthBarText(std::string text, int _x, int _y, ALLEGRO_FONT* font)
{
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
al_hold_bitmap_drawing(true);
for (int x = 0; x < 196; x++)
{
for (int y = 0; y < 17; y++)
{
unsigned char r, g, b;
al_unmap_rgb(al_get_pixel(al_get_backbuffer(g_Window), _x + x, _y + y), &r, &g, &b);
if ((r + g + b) / 3 == 255)
{
bmpIndex[x][y] = 0;
}
else if ((r + g + b) / 3 == 0)
{
bmpIndex[x][y] = 1;
}
}
}
al_hold_bitmap_drawing(false);
al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP);
}
I've googled and tried my own code as you can see above... However using this multi-leveled loop is very slow. My thought was to use a shader but I haven't the slightest clue how to use them yet.
I want the text to change color based off the background of where the text is located...
Basically it's a health bar and I want to show the text ontop of the health bar and change colors based on the background... If the background is black, the corresponding pixels are changed to white. Subsequently if the background pixels are white, the pixels of the text change to black.
like this:
photoshop render concept
MY FIX:
// Hacky bullshit
_DrawText(std::to_string((int)_player->playerHealth), 5 + ((195.0f - al_get_text_width(getFont(12), std::to_string((int)_player->playerHealth).c_str())) / 2), py + 18, getFont(12), al_map_rgb(255, 0, 0), 0);
al_draw_rectangle(px + 5, py + 20, px + 200, py + 20 + 15, al_map_rgb(255, 255, 255), 1.0f);
ALLEGRO_BITMAP* bmp = al_create_bitmap(200, 20);
{
al_set_target_bitmap(bmp);
al_draw_filled_rectangle(5, 0, 5 + ((195.0f / _player->playerMaxHealth) * _player->playerHealth), 15, al_map_rgb(255, 255, 255));
_DrawText(std::to_string((int)_player->playerHealth), 5 + ((195.0f - al_get_text_width(getFont(12), std::to_string((int)_player->playerHealth).c_str())) / 2), -2, getFont(12), al_map_rgb(155, 0, 0), 0);
al_set_target_backbuffer(g_Window);
al_draw_bitmap_region(bmp, 0, 0, 5 + ((195.0f / _player->playerMaxHealth) * _player->playerHealth), 20, px, py + 20, 0);
}
al_destroy_bitmap(bmp);
The simplest way is to use the clipping rectangle, a common feature of most graphics APIs. When you set the clipping rectangle, nothing can be drawn outside of it.
First, set the clipping rectangle to cover the white part of the progress bar. Draw your text in black.
Then, set the clipping rectangle to cover the black part of the progress bar. Draw your text in white, in the same position as it was drawn in black.
int x = 0, y = 0;
int bar_width = 196, bar_height = 17;
int bar_position = static_cast<int>(
bar_width * _player->playerHealth / _player->playerMaxHealth);
// Set the clipping rectangle so text only appears on the left
// side of the bar (which is white),
al_set_clipping_rectangle(x, y, bar_position, bar_height);
// Draw black text.
al_draw_text(getFont(12), al_map_rgb(0, 0, 0), x, y, 0, text.c_str());
// Set the clipping rectangle so text only appears on the right
// side of the bar (which is black).
al_set_clipping_rectangle(x + bar_position, y, bar_width - bar_position, bar_height);
// Draw white text in the same position as the black text.
al_draw_text(getFont(12), al_map_rgb(255, 255, 255), x, y, 0, text.c_str());
// Reset clipping rectangle so you can draw graphics as usual again.
al_reset_clipping_rectangle();

Object reconstruction from structure from motion with mask RCNN

I'm doing object reconstruction from structure from motion. The current situation right now, is I'm getting a multiple views for a car and apply a mask rcnn for that object to remove the background, because I only want that object to reconstruct and have a clean object.
My current issues, right now are that The Object is not fully reconstructured.
The mask that I get from Mask RCNN is not always have a fixed size for the SFM to work
A background noise is still present in the scene reconstructed object
Camera parameters are messed up when I use only the mask that are got from different views, how to fix that ?
Here are some results:
Original image of course there are mutliple views of it
Mask RCNN results that I use for SFM
and here is the result from SFM
// Draw the predicted bounding box, colorize and show the mask on the image
void drawBox(Mat& frame, int classId, float conf, Rect box, Mat& objectMask, std::vector<Mat> &contours_images)
{
//Draw a rectangle displaying the bounding box
//rectangle(frame, Point(box.x, box.y), Point(box.x + box.width, box.y + box.height), Scalar(255, 178, 50), 3);
//Get the label for the class name and its confidence
string label = format("%.2f", conf);
if (!classes.empty())
{
CV_Assert(classId < (int)classes.size());
label = classes[classId] + ":" + label;
}
//Display the label at the top of the bounding box
int baseLine;
Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
box.y = max(box.y, labelSize.height);
//rectangle(frame, Point(box.x, box.y - round(1.5 * labelSize.height)), Point(box.x + round(1.5 * labelSize.width), box.y + baseLine), Scalar(255, 255, 255), FILLED);
//putText(frame, label, Point(box.x, box.y), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 0, 0), 1);
// Resize the mask, threshold, color and apply it on the image
// Scalar color = colors[classId % colors.size()];
// Resize the mask, threshold, color and apply it on the image
resize(objectMask, objectMask, Size(box.width, box.height));
Mat mask = (objectMask > maskThreshold);
//Mat coloredRoi = (0.3 * color + 0.7 * frame(box));
// coloredRoi.convertTo(coloredRoi, CV_8UC3);
Mat coloredRoi(frame(box));
// Draw the contours on the image
vector<Mat> contours;
Mat hierarchy;
mask.convertTo(mask, CV_8U);
findContours(mask, contours, hierarchy, RETR_CCOMP, cv::CHAIN_APPROX_NONE);
//drawContours(coloredRoi, contours, -1, color, 5, LINE_8, hierarchy, 100);
// coloredRoi.copyTo(frame(box), mask);
Mat outframe;
coloredRoi.copyTo(outframe, mask);
cv::resize(outframe, outframe, cv::Size(400, 400));
contours_images.push_back(outframe);
// imshow("outframe", outframe);
// waitKey(0);
}
// For each frame, extract the bounding box and mask for each detected object
void postprocess(Mat& frame, const vector<Mat>& outs, vector<Mat> & maskes)
{
Mat outDetections = outs[0];
Mat outMasks = outs[1];
// Output size of masks is NxCxHxW where
// N - number of detected boxes
// C - number of classes (excluding background)
// HxW - segmentation shape
const int numDetections = outDetections.size[2];
const int numClasses = outMasks.size[1];
outDetections = outDetections.reshape(1, outDetections.total() / 7);
for (int i = 0; i < numDetections; ++i)
{
float score = outDetections.at<float>(i, 2);
if (score > confThreshold)
{
// Extract the bounding box
int classId = static_cast<int>(outDetections.at<float>(i, 1));
int left = static_cast<int>(frame.cols * outDetections.at<float>(i, 3));
int top = static_cast<int>(frame.rows * outDetections.at<float>(i, 4));
int right = static_cast<int>(frame.cols * outDetections.at<float>(i, 5));
int bottom = static_cast<int>(frame.rows * outDetections.at<float>(i, 6));
left = max(0, min(left, frame.cols - 1));
top = max(0, min(top, frame.rows - 1));
right = max(0, min(right, frame.cols - 1));
bottom = max(0, min(bottom, frame.rows - 1));
Rect box = Rect(left, top, right - left + 1, bottom - top + 1);
// Extract the mask for the object
Mat objectMask(outMasks.size[2], outMasks.size[3], CV_32F, outMasks.ptr<float>(i, classId));
// Draw bounding box, colorize and show the mask on the image
drawBox(frame, classId, score, box, objectMask, maskes);
}
}
}

Why don't the calls to LineTo & SetPixel draw anything?

I've written a simple MFC application to draw a polygon in a dialog, the complete code being here.
The code opens a dialog, with default standard grey background, defines
std::vector<CPoint> m_LeftPolygon;
then does as following:
void DrawPitons(std::vector<CPoint> points, COLORREF rgbColor, HDC hDC)
{
static unsigned short XDiff[7] = { 5,4,4,3,2,1,0 },
YDiff[7] = { 0,1,2,3,4,4,5 };
for (unsigned pnt = 0; pnt < points.size(); pnt++)
{
SetPixel(hDC, points[pnt].x, points[pnt].y, rgbColor);
for (unsigned short i = 0; i < 7; i++)
{
SetPixel(hDC, points[pnt].x + XDiff[i], points[pnt].y + YDiff[i], rgbColor);
SetPixel(hDC, points[pnt].x + XDiff[i], points[pnt].y - YDiff[i], rgbColor);
SetPixel(hDC, points[pnt].x - XDiff[i], points[pnt].y + YDiff[i], rgbColor);
SetPixel(hDC, points[pnt].x - XDiff[i], points[pnt].y - YDiff[i], rgbColor);
}
}
}
void CROIDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CPaintDC dc(this); // device context for painting
HDC hDC = dc.GetSafeHdc();
HPEN hPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0)),
oldPen = (HPEN)SelectObject(hDC, hPen);
SetROP2(hDC, R2_COPYPEN);
// Draw the polygon
if (m_LeftPolygon.size() > 1)
{
BOOL stat = MoveToEx(hDC, (int)m_LeftPolygon[0].x, (int)m_LeftPolygon[0].y, NULL);
for (size_t index = 1; index < m_LeftPolygon.size(); index++)
stat = LineTo(hDC, (int)m_LeftPolygon[index].x, (int)m_LeftPolygon[index].y);
stat = LineTo(hDC, (int)m_LeftPolygon[0].x, (int)m_LeftPolygon[0].y);
}
// Draw the control points
DrawPitons(m_LeftPolygon, RGB(255, 0, 0), hDC);
SelectObject(hDC, oldPen);
DeleteObject(hPen);
}
}
void CROIDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
m_LeftPolygon.push_back(point);
SendMessage(WM_PAINT);
}
For some reason, nothing is drawn, though I would expect the pitons and connecting lines to be drawn in red over the grey background.
What am I missing?

MFC: Ring - no color change

I'm trying to learn MFC from book: MV C++ Windows Application by Example(2008). There is example app. where I can draw rings filled witch chosen color:
void CRingView::OnDraw(CDC* pDC)
{
CRingDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
PointArray& pointArray = pDoc->GetPointArray();
ColorArray& colorArray = pDoc->GetColorArray();
int iSize = static_cast<int>(pointArray.GetSize());
for (int iIndex = 0; iIndex < iSize; iIndex++)
{
CPoint point = pointArray[iIndex];
COLORREF color = colorArray[iIndex];
CPen pen(PS_SOLID, 0, BLACK);
CBrush brush(color);
pDC->Ellipse(point.x - RADIUS, point.y - RADIUS, point.x + RADIUS, point.y + RADIUS);
CPen* pOldPen = pDC->SelectObject(&pen);
CBrush* pOldBrush = pDC->SelectObject(&brush);
}
}
but there is no color change(always white like bg) even if I do:
CBrush brush(BLACK);
So question is: What I'm doing wrong? I'm using Visual Studio 2013 but with new project there shouldn't be any compatibility errors.
And BLACK is:
static const COLORREF BLACK = RGB(0, 0, 0);
The DC draws with whatever brush, pen, font, etc. objects are currently selected. So SelectObject of the pen and the brush should happen before doing the drawing.