Это очень простой пример измерения сегментированной линии, нарисованной на изображении в winforms.
Он использует PictureBox
для отображения изображения, Label
для отображения текущего результата, и для хорошей меры я добавил две Buttons
, чтобы очистить все точки и отменить / удалить последнюю.
Я собираю пиксельные позиции в List<Point>
:
List<Point> points = new List<Point>();
Две кнопки редактирования довольно просты:
private void btn_Clear_Click(object sender, EventArgs e)
{
points.Clear();
pictureBox1.Invalidate();
show_Length();
}
private void btn_Undo_Click(object sender, EventArgs e)
{
if (points.Any())points.Remove(points.Last());
pictureBox1.Invalidate();
show_Length();
}
Обратите внимание, как я запускаю событие Paint
, делая изображение недействительным при каждом изменении набора точек.
Остальная часть кода также проста; Я вызываю функцию для расчета и отображения суммы всех длин сегмента. Обратите внимание, что мне нужно по крайней мере две точки, прежде чем я смогу это сделать или отобразить первую строку ..
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
points.Add(e.Location);
pictureBox1.Invalidate();
show_Length();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (points.Count > 1) e.Graphics.DrawLines(Pens.Red, points.ToArray());
}
void show_Length()
{
lbl_len.Text = (pointsF.Count) + " point(s), no segments. " ;
if (!(points.Count > 1)) return;
double len = 0;
for (int i = 1; i < points.Count; i++)
{
len += Math.Sqrt((points[i-1].X - points[i].X) * (points[i-1].X - points[i].X)
+ (points[i-1].Y - points[i].Y) * (points[i-1].Y - points[i].Y));
}
lbl_len.Text = (points.Count-1) + " segments, " + (int) len + " pixels";
}
Несколько заметок:
Изображение отображается без увеличения. PictureBox
имеет свойство SizeMode
для упрощения масштабирования. В таком случае я рекомендую хранить не прямые пиксельные местоположения мыши, а «не масштабированные» значения и использовать «повторно увеличенный» список значений для отображения. Таким образом, вы можете увеличивать и уменьшать масштаб, сохраняя при этом точки в правильных местах.
Для этого вы должны использовать List<PointF>
, чтобы сохранить точность.
При масштабировании, например, увеличив PictureBox
, возможно, после его вложения в Panel
, убедитесь, что вы сохранили соотношение сторон, равное Image
, или выполните полный расчет , чтобы включить дополнительное пространство слева или сверху; в SizeMode.Normal
изображение всегда будет стоять на одном уровне TopLeft , но в других режимах это не всегда будет так.
Для расчета фактических, то есть физических расстояний, просто поделите на фактическое значение dpi.
Посмотрим, что у нас в действии:

Обновление:
Чтобы получить возможность подгонки клёров и повышения точности, нам, очевидно, нужно увеличить изображение.
Вот необходимые изменения:
Мы добавляем список «плавающих точек»:
List<PointF> pointsF = new List<PointF>();
И использовать его для хранения не масштабированных позиций мыши при наведении мыши вниз:
pointsF.Add( scaled( e.Location, false));
Мы заменяем все остальные вхождения points
на pointsF
.
Событие Paint
всегда вычисляет масштабированные точки до текущего уровня масштабирования:
if (pointsF.Count > 1)
{
points = pointsF.Select(x => Point.Round(scaled(x, true))).ToList();
e.Graphics.DrawLines(Pens.Red, points.ToArray());
}
А функция масштабирования выглядит следующим образом:
PointF scaled(PointF p, bool scaled)
{
float z = scaled ? 1f * zoom : 1f / zoom;
return new PointF(p.X * z, p.Y * z);
}
Используется переменная уровня класса float zoom = 1f;
, которая устанавливается вместе с Clientsize
в графическом окне в событии Scroll
трекбара:
private void trackBar1_Scroll(object sender, EventArgs e)
{
List<float> zooms = new List<float>()
{ 0.1f, 0.2f, 0.5f, 0.75f, 1f, 2, 3, 4, 6, 8, 10};
zoom = zooms[trackBar1.Value];
int w = (int)(pictureBox2.Image.Width * zoom);
int h = (int)(pictureBox2.Image.Height * zoom);
pictureBox2.ClientSize = new Size(w, h);
lbl_zoom.Text = "zoom: " + (zoom*100).ToString("0.0");
}
Picturebox вложен в Panel
с включенным AutoScroll
. Теперь мы можем увеличивать и масштабировать при добавлении сегментов:
