Как измерить длину линии, которая нарисована на изображении? С#

Вопрос: Я хотел бы написать приложение, которое будет измерять фрагменты образца, исследованного под микроскопом. Я думал, что лучший способ - захватить изображение и нарисовать отдельные части образца, а затем подсчитать значение рисованной линии в пикселях (а затем преобразовать это значение в соответствующий блок). Есть ли что-нибудь, что помогает решить уже выпущенную проблему или какой-либо инструмент/пакет

Вопрос:

Я хотел бы написать приложение, которое будет измерять фрагменты образца, исследованного под микроскопом. Я думал, что лучший способ – захватить изображение и нарисовать отдельные части образца, а затем подсчитать значение рисованной линии в пикселях (а затем преобразовать это значение в соответствующий блок).

Есть ли что-нибудь, что помогает решить уже выпущенную проблему или какой-либо инструмент/пакет или что-то такое, что позволяет такие вычисления?

Я также охотно узнаю о решениях на других языках программирования, если они позволят решить эту проблему более простым способом или просто каким-то образом.

Лучший ответ:

Это очень простой пример измерения сегментированной линии, нарисованной на изображении в 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 чтобы сделать масштабированный дисплей простым. В таком случае я рекомендую хранить не прямые пиксельные местоположения мыши, а значения “unzoomed” и использовать “rezoomed” список значений для отображения. Таким образом, вы можете увеличивать и уменьшать масштаб и по-прежнему удерживать очки в правильных местах.

  • Для этого вы должны использовать 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»); }

Картинка находится внутри Panel с AutoScroll. Теперь мы можем масштабировать и прокручивать, добавляя сегменты:

Оцените статью
Добавить комментарий