Hello,
I have some difficulties to use overlay on wpf display.
I just want to get the position of the mouse (click or double click) in image coordinate to set an overlay (circle or arrow or …) on the display (and using coordinate mouse).
I tested :
private void Display_Cam_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
Stemmer.Cvb.Wpf.Controls.Display test = (Stemmer.Cvb.Wpf.Controls.Display)sender;
Point t = Mouse.GetPosition(test);
Point t1 = test.PointFromScreen(t);
Stemmer.Cvb.Wpf.Overlays.ImageOverlay overlay = new Stemmer.Cvb.Wpf.Overlays.ImageOverlay();
Rectangle rect = new Rectangle();
rect.StrokeThickness = 5;
rect.Stroke = new SolidColorBrush(Color.FromRgb(255, 0, 0));
rect.Height = 30;
rect.Width = 30;
rect.HorizontalAlignment = HorizontalAlignment.Left;
rect.VerticalAlignment = VerticalAlignment.Top;
overlay.Content = rect;
overlay.OverlayX = t.X;
overlay.OverlayY = t.Y;
}
But t1 is not the same as MouseOverInfo
.
How to add overlay to the Display?
Can you help me ?
I do this :
Stemmer.Cvb.Wpf.Controls.Display disp = (Stemmer.Cvb.Wpf.Controls.Display)sender;
Point t = Mouse.GetPosition(disp);
double x = (t.X - disp.ImageViewportHorizontalOffset )/ disp.ActualZoomFactor;
double y = (t.Y- disp.ImageViewportVerticalOffset) / disp.ActualZoomFactor;
Stemmer.Cvb.Wpf.Overlays.ImageOverlay overlay = new Stemmer.Cvb.Wpf.Overlays.ImageOverlay();
Rectangle rect = new Rectangle();
rect.StrokeThickness = 5;
rect.Stroke = new SolidColorBrush(Color.FromRgb(255, 0, 0));
rect.Height = 30;
rect.Width = 30;
rect.HorizontalAlignment = HorizontalAlignment.Left;
rect.VerticalAlignment = VerticalAlignment.Top;
overlay.Content = rect;
overlay.OverlayX = x - (rect.Width / 2);
overlay.OverlayY = y - (rect.Height / 2);
disp.Items.Add(overlay);
It work but is it ok ?
Hi @algoptic
I will abbreviate Stemmer.Cvb.Wpf.Controls.Display
to Display
from here on
Objects derived from Stemmer.Cvb.Wpf.Controls.Overlays
have the properties OverlayX
, OverlayY
, OverlayWidth
and OverlayHeight
. These properties are always measured in image coordinates rather than screen coordinates, making it easier to place these objects to a specific location in an image. So your approach of instantiating a Stemmer.Cvb.Wpf.Overlay.ImageOverlay
and setting the OverlayX
and OverlayY
property is basically ok.
However there are a two things to keep in mind:
- You do initially case your
sender
to a Stemmer.Cvb.Wpf.Controls.Display
object - if the even bubbled up the visual tree from a nested overlay this line will raise and exception, so it would be better to use
var disp = sender as Stemmer.Cvb.Wpf.Controls.Display;
if (disp == null)
return;
- Objects on the
Display
are subject to scaling transformations based on the zoom level. You already discovered the Display.ActualZoomFactor
property, which is good. But what you should be aware of is that as the user zooms into the display, that zoom factor will change and affect your added overlay, scaling size but also stroke thicknesses accordingly. If you want your result to be resilient versus these transformations you’ll need to take that into account:
- Instead of using a fixed
StrokeThickness = 5;
you might want to either bind overlay
's EffectiveLineWidth
property and set StandardLineWidth
to 5 (that way, you will make sure that your rectangle’s line with on display is always 5). Or you may want to subscribe to the property changes of the ActualZoomFactor
Dependency Property to get informed about changes and set your stroke thickness in code behind.
- Similar measures will need to be taken to make sure that your overlay always has the correct size. The road to take here depends on whether you want your rectangle to always have the correct size in terms of image pixels (like e. g. always be 5 x 5 image pixels big) and change its display size when the zoom factor changes or you might want to always have the rectangle a display size of 5 x 5 pixels regardless of zoom state. For the first case I’d recommend to have a look at
Stemmer.Cvb.Wpf.Overlays.RectangleOverlay
- just set OverlayX
, OverlayY
, OverlayWidth
and OverlayHeight
as well as StrokeThickness
as needed and you’re done (note that in this case you don’t need any extra treatment for stroke thickness as Stemmer.Cvb.Wpf.Overlays.RectangleOverlay
automatically scales stroke thickness as needed for display…). For the second case scaling will need to be applied like described above for the stroke thickness.
If you opt for RectangleOverlay
then try something like this (assuming you don’t want your overlay to be movable…):
var aoi = new RectangleOverlay()
{
OverlayX = x - 15,
OverlayY = y - 15,
OverlayWidth = 30,
OverlayHeight = 30,
Stroke = new SolidColorBrush(Colors.Red),
StrokeThickness = 5,
Movable = false,
Resizable = false,
CanCenterDrag = false
};
Another relatively simply usable object that might also fit your use case is Stemmer.Cvb.Wpf.Overlays.Crosshair
- with that one you’d just set OverlayX
and OverlayY
as well as CrosshairSize
(plust, of course, StrokeThickness
if you want).
1 Like