How to make the previous figure on the box PictureBox not disappear? - c#

This is the code that draws the shapes in the picture by coordinates.
I need to make it so that the previous forms are also saved. How can I do this?
List<Point> shadePoints = new List<Point>();
shadePoints.Add(new Point(0, pictureBox1.ClientSize.Height));
shadePoints.Add(new Point(pictureBox1.ClientSize.Width, 0));
shadePoints.Add(new Point(pictureBox1.ClientSize.Width,
pictureBox1.ClientSize.Height));
e.Graphics.FillPolygon(Brushes.LightGray, shadePoints.ToArray());
// scale the drawing
using (Matrix m = new Matrix())
{
m.Scale(1, 1);
e.Graphics.Transform = m;
List<Point> polyPoints = new List<Point>();
polyPoints.Add(new Point(508, 1231));
polyPoints.Add(new Point(509, 123));
polyPoints.Add(new Point(509, 124));
polyPoints.Add(new Point(508, 124));
using (SolidBrush br = new SolidBrush(Color.FromArgb(100, Color.Yellow)))
{
e.Graphics.FillPolygon(br, polyPoints.ToArray());
}
e.Graphics.DrawPolygon(Pens.DarkBlue, polyPoints.ToArray());
foreach (Point p in polyPoints)
{
e.Graphics.FillEllipse(Brushes.Red,
new Rectangle(p.X - 2, p.Y - 2, 4, 4));
}
}

Related

Remove outliers from a list of points in C#

Problem
I have a list of points in C# that I draw on a panel on a Windows Forms object. The lists variables are two listA and listB. The points in listB are the points in listA except that they have gone through some transformation to deform it to resemble the shape formed by points in listA and then added some outliers to make them look different. If you can try these on your visual studio then this is the code...
class Form1 : Form
{
//declare the list to hold points for
//shapes
List<Point> listA = new List<Point>();
List<Point> listB = new List<Point>();
//this methods transforms,applies outliers and draws the shapes on panel1
private void button1_click(EventArgs e, object sender)
{
//clear the lists for initializing
listA.Clear();
listB.Clear();
Point p1a = new Point(20, 30);
Point p2a = new Point(120, 50);
Point p3a = new Point(160, 80);
Point p4a = new Point(180, 300);
Point p5a = new Point(100, 220);
Point p6a = new Point(50, 280);
Point p7a = new Point(20, 140);
//Hold the Points in an array
Point[] mypoints = new Point[] { p1a, p2a, p3a, p4a, p5a, p6a, p7a };
//add the points to the List with one call
listA.AddRange(mypoints);
//define a new Transformation
//that will translate shapeA to have a slightly different imageB
Transformation t2 = new Transformation();
t2.A = 1.05; t2.B = 0.05; t2.T1 = 15; t2.T2 = 22;
//assign the new translated points to listB
listB = applytransformation(t2, listA);
//Add outliers to listb by manipulating the values in the list
Shape2[2] = new Point(Shape2[2].X + 10, Shape2[2].Y + 3);
//create a new instance of pen
//for drawing imageA in blue
Pen penner = new Pen(Brushes.Blue, 3);
//Create a new instance of pen for
//drawing imageB in red
Pen mypen = new Pen(Brushes.Red, 3);
//get the graphic context
Graphics g = panel1.CreateGraphics();
//draw both shapes
DisplayShape(listA, penner, g);
DisplayShape(listB, mypen, g);
}
//the method below does the transformation of imagea into imageb by manipulating the points and the transformation
List<Point> applytransformation(Transformation x, List<Point> shape)
{
List<Point> Tlist = new List<Point>();
foreach (Point c in shape) {
double xprime = x.A * c.X + x.B * c.Y + x.T1;
double yprime = x.B * c.X * -1 + x.A * c.Y + x.T2;
Point ptrans = new Point((int)xprime, (int)yprime);
Tlist.Add(ptrans);
}
//it returns the points that will be used to draw imageB
return Tlist;
}
//this method draws the points on the panel
void DisplayShape(List<Point> Shp, Pen pen, Graphics G)
{
Point? prevPoint = null;//nullable
foreach (Point pt in Shp) {
G.DrawEllipse(pen, new Rectangle(pt.X - 2, pt.Y - 2, 4, 4));
if (prevPoint != null) {
G.DrawLine(pen, (Point)prevPoint, pt);
}
prevPoint = pt;
}
G.DrawLine(pen, Shp[0], Shp[Shp.Count - 1]);
}
}
public class Transformation
{
public double A { get; set; }
public double B { get; set; }
public double T1 { get; set; }
public double T2 { get; set; }
}
Goal
I want to remove all the outliers in imageB so that it resembles imageA even if it won't be perfect. All methods or algorithms are welcome ie RANSAC,minimum cost function. I have tried to find an authoritative source online that can guide or help me achieve this in C# with zero success. The code I have provided is a minimum reproducible example that can be replicated on any visual studio IDE.Please help, Thank You for your time and contribution.
Expected Output
I added an image to make it clear the result I want
If you have many points forming a cloud of points where the line defining the shape goes through, then you can remove outliers. As an example see Removing outliers. But in this case, every point in the list seems to be a vertex of the shape. Removing a point will alter the shape considerably.
Can you explain what these shapes represent? hat should happen if you remove an outlier? Should it be replaced by another point?
While this is not an answer to your question, here is an improved and simplified version of the code:
List<Point> listA, listB; // Initialization not required.
private void button1_click(EventArgs e, object sender)
{
// Simplify initialization with collection and object initializers.
listA = new List<Point> {
new Point(20, 30), new Point(120, 50),
new Point(160, 80), new Point(180, 300),
new Point(100, 220), new Point(50, 280),
new Point(20, 140)
};
var t2 = new Transformation { A = 1.05, B = 0.05, T1 = 15, T2 = 22 };
listB = ApplyTransformation(t2, listA);
// Simplify shifting point.
Shape2[2] += new Size(10, 3);
// Invalidate panel and let Panel1_Paint draw it.
// Never create your own Graphics object.
panel1.Invalidate();
}
private void Panel1_Paint(object sender, PaintEventArgs e)
{
if (listA != null && listB != null) {
// Use predefined pens instead of creating brushes.
DisplayShape(listA, Pens.Blue, e.Graphics);
DisplayShape(listB, Pens.Red, e.Graphics);
}
}
List<Point> ApplyTransformation(Transformation x, List<Point> shape)
{
// Prevent list resizing by specifying initial size.
var transformedList = new List<Point>(shape.Count);
foreach (Point c in shape) {
double xprime = x.A * c.X + x.B * c.Y + x.T1;
double yprime = x.B * c.X * -1 + x.A * c.Y + x.T2;
transformedList.Add(new Point((int)xprime, (int)yprime));
}
return transformedList;
}
void DisplayShape(List<Point> shape, Pen pen, Graphics g)
{
// By using "for" instead of "foreach" we have indexes we can use to
// simplify closing the shape, since we always have a previous point.
for (int i = 0; i < shape.Count; i++) {
Point prevPoint = i > 0 ? shape[i - 1] : shape[shape.Count - 1];
Point pt = shape[i];
// No need to create a rectangle,
// there is an overload accepting location and size.
g.DrawEllipse(pen, pt.X - 2, pt.Y - 2, 4, 4);
g.DrawLine(pen, prevPoint, pt);
}
}
Since C# 8.0 and in .NET Core projects we can also write shape[^1] to get the last point instead of shape[shape.Count - 1].

The rotation of the rectangle relative to the rotated rectangle using C#

I have two rectangle:
first parent rotated -15 degrees relative to the center of the canvas
next children rotated -15 degrees relative to the center of the canvas and rotated 5 degrees relative to the center of parent.
Taking the original image:
Made the described modifications in the image editor:
It is necessary to repeat these operations with rectangles, here is my code:
var parentAngle = -15;
var childrenAngle = 5;
var parent = new Rectangle(new Point(50, 160), new Size(200, 300));
var children = new Rectangle(new Point(25, 175), new Size(50, 50));
// load transformed file to as canvas
var bmp = Image.FromFile(#"D:\Temp\transform.png");
var size = bmp.Size;
var canvasCenter = new PointF(size.Width / 2, size.Height / 2);
var parentCenter = new PointF(parent.Location.X + parent.Width / 2, parent.Location.Y + parent.Height / 2);
var parentLocation = parent.Location;
var parentVertices = parent.GetVertices();
var childrenVertices = children.GetVertices();
// rotate by canvas center
var rotateMatrix = new Matrix();
rotateMatrix.RotateAt(parentAngle, canvasCenter);
rotateMatrix.TransformPoints(parentVertices);
// rotate children vertices
var rotateMatrix2 = new Matrix();
rotateMatrix2.RotateAt(childrenAngle, parentCenter);
rotateMatrix2.TransformPoints(childrenVertices);
// translate vertices
var translateMatrix = new Matrix();
translateMatrix.Translate(parentLocation.X, parentLocation.Y);
translateMatrix.TransformPoints(childrenVertices);
// rotate by canvas center
rotateMatrix.TransformPoints(childrenVertices);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawPolygon(Pens.Green, parentVertices);
g.DrawPolygon(Pens.Blue, childrenVertices);
}
Result:
I was mistaken somewhere and parent matches but children don't match. Maybe everything breaks down at the calculate parent offset?
Update:
The GetVertices function is implemented as a helper and looks like this:
public static PointF[] GetVertices(this Rectangle rect)
{
return new[] {
rect.Location,
new PointF(rect.Right, rect.Top),
new PointF(rect.Right, rect.Bottom),
new PointF(rect.Left, rect.Bottom)
};
}
I found a few problems:
First - paint.net rotate selected layer relative to the center of the canvas. Therefore, nothing came together and had to redraw the test case
Next - I had to redo the calculation of transferring the location of the child to the top.
Now it looks like this:
var parentAngle = -15;
var childrenAngle = 5;
var parent = new Rectangle(new Point(50, 160), new Size(200, 300));
var children = new Rectangle(new Point(25, 175), new Size(50, 50));
// load transformed file to as canvas
var bmp = Image.FromFile(#"D:\Temp\rotate_5.png");
var size = bmp.Size;
var canvasCenter = new PointF(size.Width / 2, size.Height / 2);
var parentLocation = parent.Location;
var parentCenter = new PointF(parentLocation.X + parent.Width / 2, parentLocation.Y + parent.Height / 2);
var childrenLocation = children.Location;
// translate location children by parent location
children.Location = childrenLocation = new Point(parentLocation.X + childrenLocation.X, childrenLocation.Y + parentLocation.Y);
var childrenCenter = new PointF(childrenLocation.X + children.Width / 2, childrenLocation.Y + children.Height / 2);
var parentVertices = parent.GetVertices();
var childrenVertices = children.GetVertices();
//rotate by canvas center
var rotateChildrenMatrix = new Matrix();
rotateChildrenMatrix.RotateAt(childrenAngle, parentCenter);
rotateChildrenMatrix.TransformPoints(childrenVertices);
// rotate by canvas center
var rotateMatrix = new Matrix();
rotateMatrix.RotateAt(parentAngle, canvasCenter);
rotateMatrix.TransformPoints(parentVertices);
rotateMatrix.TransformPoints(childrenVertices);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawPolygon(Pens.Green, parentVertices);
g.DrawPolygon(Pens.Blue, childrenVertices);
}
Result:

Change the direction of a Pen's arrow end cap

I want to draw a line and show the arrow cap at the 'tail' of the line, like this:
Here is what I tried. The arrow cap is placed at the line's end, but its direction is not correct. It's coming downwards while I want it upwards like in the above image.
AdjustableArrowCap bigArrow = new AdjustableArrowCap(5, 5);
Pen p = new Pen(Color.Black, 2);
p.CustomEndCap = bigArrow;
g.DrawLine(p, X, Y, X, 50);
This is a workaround, using a one-pixel extra line, but I think will do the job:
var img = new System.Drawing.Bitmap(200, 200);
using (var g = System.Drawing.Graphics.FromImage(img)) {
using (var p1 = new System.Drawing.Pen(System.Drawing.Color.Black, 2),
p2 = new System.Drawing.Pen(System.Drawing.Color.Black, 2)) {
using (var bigArrow = new AdjustableArrowCap(5, 5)) {
p2.CustomEndCap = bigArrow;
g.DrawLine(p1, 25, 50, 25, 100);
g.DrawLine(p2, 25, 100, 25, 99);
}
}
}
Here is my output:
This one uses CustomLineCap, it's not perfect but hopefully will give you a good direction
Graphics g= e.Graphics;
using (var path = new GraphicsPath()) {
path.AddLine(new Point(-4, 4), new Point(4, 4));
path.AddLine(new Point(4, 4), new Point(0, -1));
path.AddLine(new Point(0, -1), new Point(-4, 4));
using (var cap = new CustomLineCap(path, null))
using (var customCapPen = new Pen(Color.Black, 2) {CustomEndCap = cap}) { g.DrawLine(customCapPen, 10, 10, 10, 50); }
}

EmguCV snake function

I am trying to use snake active contour from EmguCV ,but i don't take anything.Here is my code:
Image<Gray, Byte> img = new Image<Gray, Byte>(300, 300, new Gray());
Point center = new Point(100, 100);
double width = 20;
double height = 40;
Rectangle rect = new Rectangle(center, new Size(20, 20));
img.Draw(rect, new Gray(255.0), -1);
using (MemStorage stor = new MemStorage())
{
Seq<Point> pts = new Seq<Point>((int)SEQ_TYPE.CV_SEQ_POLYGON, stor);
pts.Push(new Point(20, 20));
pts.Push(new Point(20, 280));
pts.Push(new Point(280, 280));
pts.Push(new Point(280, 20));
//Image<Gray, Byte> canny = img.Canny(100.0, 40.0);
Seq<Point> snake = img.Snake(pts, 0.1f, 0.5f, 0.4f, new Size(21, 21), new MCvTermCriteria(500, 0.1), stor);
img.Draw(pts, new Gray(120), 1);
img.Draw(snake, new Gray(80), 2);
What i am doing wrong?Any idea?
you miss to draw your initialization points.
I have setup some code for you and for the whole community as there are no emgu snakes sample out there.
private void TestSnake()
{
Image<Gray, Byte> grayImg = new Image<Gray, Byte>(400, 400, new Gray());
Image<Bgr, Byte> img = new Image<Bgr, Byte>(400, 400, new Bgr(255,255,255));
// draw an outer circle on gray image
grayImg.Draw(new Ellipse(new PointF(200,200),new SizeF(100,100),0), new Gray(255.0), -1);
// inner circle on gray image to create a donut shape :-)
grayImg.Draw(new Ellipse(new PointF(200, 200), new SizeF(50, 50), 0), new Gray(0), -1);
// this is the center point we'll use to initialize our contour points
Point center = new Point(200, 200);
// radius of polar points
double radius = 70;
using (MemStorage stor = new MemStorage())
{
Seq<Point> pts = new Seq<Point>((int)Emgu.CV.CvEnum.SEQ_TYPE.CV_SEQ_POLYGON, stor);
int numPoint = 100;
for (int i = 0; i < numPoint; i++)
{ // let's have some fun with polar coordinates
Point pt = new Point((int)(center.X + (radius * Math.Cos(2 * Math.PI * i / numPoint))), (int)(center.Y + (radius * Math.Sin(2 * Math.PI * i / numPoint))) );
pts.Push(pt);
}
// draw contour points on result image
img.Draw(pts, new Bgr(Color.Green), 2);
// compute snakes
Seq<Point> snake = grayImg.Snake(pts, 1.0f, 1.0f, 1.0f, new Size(21, 21), new MCvTermCriteria(100, 0.0002), stor);
// draw snake result
img.Draw(snake, new Bgr(Color.Yellow), 2);
// use for display in a winform sample
imageBox1.Image = grayImg;
imageBox2.Image = img;
}
}
Hope this helps, just change some params and you will be surprised of result.

Drawing a polygon according to the input coordinates

How can i draw a polygon according to the input coordinates which are given in C#.
You didn't show any code because based on those coordinate, you are applying some form of scaling to the image.
Using the Paint event of a PictureBox, here is an example using those coordinates on the screen. It fills in the polygon, then draws the border, then it loops through all the points to draw the red circle:
void pictureBox1_Paint(object sender, PaintEventArgs e) {
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.Clear(Color.White);
// draw the shading background:
List<Point> shadePoints = new List<Point>();
shadePoints.Add(new Point(0, pictureBox1.ClientSize.Height));
shadePoints.Add(new Point(pictureBox1.ClientSize.Width, 0));
shadePoints.Add(new Point(pictureBox1.ClientSize.Width,
pictureBox1.ClientSize.Height));
e.Graphics.FillPolygon(Brushes.LightGray, shadePoints.ToArray());
// scale the drawing larger:
using (Matrix m = new Matrix()) {
m.Scale(4, 4);
e.Graphics.Transform = m;
List<Point> polyPoints = new List<Point>();
polyPoints.Add(new Point(10, 10));
polyPoints.Add(new Point(12, 35));
polyPoints.Add(new Point(22, 35));
polyPoints.Add(new Point(24, 22));
// use a semi-transparent background brush:
using (SolidBrush br = new SolidBrush(Color.FromArgb(100, Color.Yellow))) {
e.Graphics.FillPolygon(br, polyPoints.ToArray());
}
e.Graphics.DrawPolygon(Pens.DarkBlue, polyPoints.ToArray());
foreach (Point p in polyPoints) {
e.Graphics.FillEllipse(Brushes.Red,
new Rectangle(p.X - 2, p.Y - 2, 4, 4));
}
}
}
You may use Graphics.DrawPolygon. You can store the coordinates in an array of Point and then you can pass that to DrawPolygon method. You may wanna see:
Drawing with Graphics in WinForms using C#
private System.Drawing.Graphics g;
System.Drawing.Point[] p = new System.Drawing.Point[6];
p[0].X = 0;
p[0].Y = 0;
p[1].X = 53;
p[1].Y = 111;
p[2].X = 114;
p[2].Y = 86;
p[3].X = 34;
p[3].Y = 34;
p[4].X = 165;
p[4].Y = 7;
g = PictureBox1.CreateGraphics();
g.DrawPolygon(pen1, p);
This simple function is able to generate an array of PointF equal to the vertices of the regular polygon to be drawn, where "center" is the center of the polygon, "sides" is its number of sides, "sideLength" is the size of each side in pixels and "offset" is its slope.
public PointF[] GetRegularPolygonScreenVertex(Point center, int sides, int sideLength, float offset)
{
var points = new PointF[sides];
for (int i = 0; i < sides; i++)
{
points[i] = new PointF(
(float)(center.X + sideLength * Math.Cos((i * 360 / sides + offset) * Math.PI / 180f)),
(float)(center.Y + sideLength * Math.Sin((i * 360 / sides + offset) * Math.PI / 180f))
);
}
return points;
}
The result obtained can be used to draw a polygon, e.g. with the function:
GraphicsObject.DrawPolygon(new Pen(Brushes.Black, GetRegularPolygonScreenVertex(new Point(X, Y), 6, 30, 60f));
Which will generate a regular hexagon with a side of 30 pixels inclined by 30°.
hex

Categories

Resources