Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/ImageJCsharp.App/Form1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ private void BuildUi()
var analyze = AddMenu(menu, "&Analyze");
AddActiveImageItem(analyze, "&Measure", MeasureCurrentRoi, Keys.Control | Keys.M);
AddActiveImageItem(analyze, "&Histogram", ShowHistogram, shortcutKeyDisplayString: "H");
AddActiveImageItem(analyze, "Plot &Profile", ShowProfile);
AddActiveImageItem(analyze, "Set &Scale...", SetScale);
AddItem(analyze, "Set &Measurements...", SetMeasurements);
AddResultsItem(analyze, "Export &Results...", ExportResults, Keys.Control | Keys.E);
Expand Down Expand Up @@ -445,6 +446,21 @@ private void ShowHistogram()
form.Show(this);
}

private void ShowProfile()
{
if (_document is null)
{
return;
}

var profile = _roi is null
? Profile.HorizontalCenterLine(_document.Image)
: Profile.HorizontalCenterLine(_document.Image, _roi.Value);

var form = new ProfileForm(_document.DisplayName, profile);
form.Show(this);
}

private void ExportResults()
{
using var dialog = new SaveFileDialog
Expand Down
63 changes: 63 additions & 0 deletions src/ImageJCsharp.App/ProfileForm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using ImageJCsharp.Core;

namespace ImageJCsharp.App;

public sealed class ProfileForm : Form
{
private readonly ProfileResult _profile;
private readonly Panel _plotPanel = new Panel();

public ProfileForm(string imageName, ProfileResult profile)
{
_profile = profile ?? throw new ArgumentNullException(nameof(profile));
Text = "Plot Profile of " + imageName;
Width = 640;
Height = 360;
BuildUi();
}

private void BuildUi()
{
_plotPanel.Dock = DockStyle.Fill;
_plotPanel.BackColor = Color.White;
_plotPanel.Paint += PlotPanelPaint;
Controls.Add(_plotPanel);
}

private void PlotPanelPaint(object? sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.White);
if (_profile.Values.Length == 0)
{
return;
}

var bounds = _plotPanel.ClientRectangle;
bounds.Inflate(-32, -24);
e.Graphics.DrawRectangle(Pens.LightGray, bounds);

var max = Math.Max(1, (int)_profile.Values.Max());
PointF Map(int index, ushort value)
{
var x = bounds.Left + (bounds.Width * (index / (float)Math.Max(1, _profile.Values.Length - 1)));
var y = bounds.Bottom - (bounds.Height * (value / (float)max));
return new PointF(x, y);
}

if (_profile.Values.Length == 1)
{
var point = Map(0, _profile.Values[0]);
e.Graphics.FillEllipse(Brushes.RoyalBlue, point.X - 2, point.Y - 2, 4, 4);
return;
}

var points = _profile.Values
.Select((value, index) => Map(index, value))
.ToArray();
e.Graphics.DrawLines(Pens.RoyalBlue, points);
}
}
53 changes: 53 additions & 0 deletions src/ImageJCsharp.Core/Profile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System;
using System.Linq;

namespace ImageJCsharp.Core;

public sealed class ProfileResult
{
public ProfileResult(ushort[] values)
{
Values = values?.ToArray() ?? throw new ArgumentNullException(nameof(values));
}

public ushort[] Values { get; }
}

public static class Profile
{
public static ProfileResult HorizontalCenterLine(GrayImage image)
{
if (image is null)
{
throw new ArgumentNullException(nameof(image));
}

return HorizontalCenterLine(image, new RectRoi(0, 0, image.Width, image.Height));
}

public static ProfileResult HorizontalCenterLine(GrayImage image, RectRoi roi)
{
if (image is null)
{
throw new ArgumentNullException(nameof(image));
}

var startX = Math.Max(0, roi.X);
var endX = Math.Min(image.Width, roi.Right);
var startY = Math.Max(0, roi.Y);
var endY = Math.Min(image.Height, roi.Bottom);
if (startX >= endX || startY >= endY)
{
throw new ArgumentException("ROI does not intersect the image.", nameof(roi));
}

var y = startY + ((endY - startY) / 2);
var values = new ushort[endX - startX];
for (var x = startX; x < endX; x++)
{
values[x - startX] = image[x, y];
}

return new ProfileResult(values);
}
}
31 changes: 31 additions & 0 deletions tests/ImageJCsharp.Core.Tests/CoreImageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,4 +240,35 @@ public void HistogramRejectsValuesOutsideEightBitRange()

Assert.Contains("8-bit", exception.Message);
}

[Fact]
public void ProfileUsesHorizontalCenterLineOfImage()
{
var image = GrayImage.FromPixels(3, 3, new ushort[]
{
1, 2, 3,
4, 5, 6,
7, 8, 9
});

var profile = Profile.HorizontalCenterLine(image);

Assert.Equal(new ushort[] { 4, 5, 6 }, profile.Values);
}

[Fact]
public void ProfileUsesHorizontalCenterLineOfRectRoi()
{
var image = GrayImage.FromPixels(4, 4, new ushort[]
{
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16
});

var profile = Profile.HorizontalCenterLine(image, new RectRoi(1, 1, 2, 2));

Assert.Equal(new ushort[] { 10, 11 }, profile.Values);
}
}
Loading