WPF-Bild, Schwenken, Zoomen und Blättern mit den Ebenen auf einer Leinwand

Ich hoffe jemand kann mir helfen hier. Ich bin erstellen einer WPF-imaging-Anwendung, die nimmt live-Bilder von einer Kamera, so dass Anwender, um das Bild anzuzeigen, und anschließend markieren Sie die Regionen von Interesse (ROI) auf das Bild. Informationen über die ROIs (width, height, Position relativ zu einem Punkt auf dem Bild, etc) wird dann zurück zu der Kamera in der Tat sagen/training der Kamera-firmware, wo Sie zu suchen für Dinge wie barcodes, text, Füllstände, dreht an einer Schraube, usw. auf dem Bild). Die gewünschte Funktion ist die Möglichkeit zum schwenken und Zoomen auf das Bild und es ist ROIs, sowie scrollen, wenn das Bild gezoomt wird, die größer als der Anzeigebereich. Die StrokeThickness und-Größe der ROI ' s halten müssen, um dort original-Skala, aber die Breite und Höhe des shapes innerhalb einer ROI-Maßstab mit dem Bild (das ist wichtig zu erfassen genauen pixel zu übertragen, um die Kamera). Ich habe die meisten dieser aus-gearbeitet, mit Ausnahme von Blättern und ein paar andere Probleme. Meine zwei Problembereiche sind:

  1. Wenn ich die Einführung eines ScrollViewer-ich bekomme keine scroll-Verhalten. Wie ich es verstehe, muss ich ein LayoutTransform, um die richtigen ScrollViewer-Element Verhalten. Allerdings, wenn ich tun, dass auch andere Bereiche beginnen zu brechen (z.B. ROIs nicht halten Ihre richtige position über dem Bild, oder der Mauszeiger beginnt zu kriechen, Weg von den ausgewählten Punkt auf dem Bild beim schwenken, oder die linke Ecke von meinem Bild springt auf die aktuelle position der Maus auf MouseDown .)

  2. Kann ich nicht so Recht, die Skalierung der mein ROI ist die Art, wie ich Sie brauche. Ich habe diese arbeiten, aber es ist nicht ideal. Was habe ich nicht behalten, die genaue Strichstärke, und ich habe nicht geschaut in ignorieren Skala des textblocks. Hoffentlich wirst du sehen, was ich mache in den Codebeispielen.

Ich bin sicher, meine Frage hat etwas zu tun mit meinen Mangel an Verständnis von Transformationen und Ihre Beziehung zu den WPF-layout-system. Hoffentlich eine Darstellung der code, der das demonstriert, was ich bisher erreicht habe helfen (siehe unten).

FYI, wenn Funktionsindikatoren sind die Anregung, das wird nicht funktionieren in meinem Fall, weil ich könnte am Ende mit mehr funktionsindikatoren als unterstützt werden (Gerücht 144 funktionsindikatoren ist, wenn Dinge beginnen zu brechen nach unten).

First off, unten ist ein screenshot zeigt ein Bild mit der ROI ' s (text und eine Form). Das Rechteck, ellipse und text Folgen müssen Sie den Bereich auf dem Bild in der Skalierung und rotation, aber nicht Sie sollten nicht Maßstab in der Dicke oder Größe.

WPF-Bild, Schwenken, Zoomen und Blättern mit den Ebenen auf einer Leinwand

Hier ist der XAML-Code, der zeigt das Bild oben, zusammen mit einem Schieberegler für das Zoomen (Mausrad-zoom wird später kommen)

<Window x:Class="PanZoomStackOverflow.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    mc:Ignorable="d"
    Title="MainWindow" Height="768" Width="1024">

<DockPanel>
  <Slider x:Name="_ImageZoomSlider" DockPanel.Dock="Bottom"
          Value="2"
          HorizontalAlignment="Center" Margin="6,0,0,0" 
          Width="143" Minimum=".5" Maximum="20" SmallChange=".1" 
          LargeChange=".2" TickFrequency="2" 
          TickPlacement="BottomRight" Padding="0" Height="23"/>

  <!-- This resides in a user control in my solution -->
  <Grid x:Name="LayoutRoot">
    <ScrollViewer Name="border" HorizontalScrollBarVisibility="Auto" 
                  VerticalScrollBarVisibility="Auto">
      <Grid x:Name="_ImageDisplayGrid">
        <Image x:Name="_DisplayImage" Margin="2" Stretch="None"
               Source="Untitled.bmp"
               RenderTransformOrigin ="0.5,0.5"
               RenderOptions.BitmapScalingMode="NearestNeighbor"
               MouseLeftButtonDown="ImageScrollArea_MouseLeftButtonDown"
               MouseLeftButtonUp="ImageScrollArea_MouseLeftButtonUp"
               MouseMove="ImageScrollArea_MouseMove">                            
           <Image.LayoutTransform>
             <TransformGroup>
               <ScaleTransform />
               <TranslateTransform />
             </TransformGroup>
           </Image.LayoutTransform>
         </Image>
         <AdornerDecorator> <!-- Using this Adorner Decorator for Move, Resize and Rotation and feedback adornernments -->
           <Canvas x:Name="_ROICollectionCanvas"
                   Width="{Binding ElementName=_DisplayImage, Path=ActualWidth, Mode=OneWay}"
                   Height="{Binding ElementName=_DisplayImage, Path=ActualHeight, Mode=OneWay}"
                   Margin="{Binding ElementName=_DisplayImage, Path=Margin, Mode=OneWay}">

             <!-- This is a user control in my solution -->
             <Grid IsHitTestVisible="False" Canvas.Left="138" Canvas.Top="58" Height="25" Width="186">
               <TextBlock Text="Rectangle ROI" HorizontalAlignment="Center" VerticalAlignment="Top" 
                          Foreground="Orange" FontWeight="Bold" Margin="0,-15,0,0"/>
                 <Rectangle StrokeThickness="2" Stroke="Orange"/>
             </Grid>

             <!-- This is a user control in my solution -->
             <Grid IsHitTestVisible="False" Canvas.Left="176" Canvas.Top="154" Height="65" Width="69">
               <TextBlock Text="Ellipse ROI" HorizontalAlignment="Center" VerticalAlignment="Top" 
                          Foreground="Orange" FontWeight="Bold" Margin="0,-15,0,0"/>
               <Ellipse StrokeThickness="2" Stroke="Orange"/>
             </Grid>
           </Canvas>
         </AdornerDecorator>
       </Grid>
     </ScrollViewer>
  </Grid>
</DockPanel>

Hier ist das C# - Verwaltung von pan und zoom.

public partial class MainWindow : Window
{
private Point origin;
private Point start;
private Slider _slider;

public MainWindow()
{
    this.InitializeComponent();

    //Setup a transform group that we'll use to manage panning of the image area
    TransformGroup group = new TransformGroup();
    ScaleTransform st = new ScaleTransform();
    group.Children.Add(st);
    TranslateTransform tt = new TranslateTransform();
    group.Children.Add(tt);
    //Wire up the slider to the image for zooming
    _slider = _ImageZoomSlider;
    _slider.ValueChanged += _ImageZoomSlider_ValueChanged;
    st.ScaleX = _slider.Value;
    st.ScaleY = _slider.Value;
    //_ImageScrollArea.RenderTransformOrigin = new Point(0.5, 0.5);
    //_ImageScrollArea.LayoutTransform = group;
    _DisplayImage.RenderTransformOrigin = new Point(0.5, 0.5);
    _DisplayImage.RenderTransform = group;
    _ROICollectionCanvas.RenderTransformOrigin = new Point(0.5, 0.5);
    _ROICollectionCanvas.RenderTransform = group;
}

//Captures the mouse to prepare for panning the scrollable image area
private void ImageScrollArea_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    _DisplayImage.ReleaseMouseCapture();
}

//Moves/Pans the scrollable image area  assuming mouse is captured.
private void ImageScrollArea_MouseMove(object sender, MouseEventArgs e)
{
    if (!_DisplayImage.IsMouseCaptured) return;

    var tt = (TranslateTransform)((TransformGroup)_DisplayImage.RenderTransform).Children.First(tr => tr is TranslateTransform);

    Vector v = start - e.GetPosition(border);
    tt.X = origin.X - v.X;
    tt.Y = origin.Y - v.Y;
}

//Cleanup for Move/Pan when mouse is released
private void ImageScrollArea_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    _DisplayImage.CaptureMouse();
    var tt = (TranslateTransform)((TransformGroup)_DisplayImage.RenderTransform).Children.First(tr => tr is TranslateTransform);
    start = e.GetPosition(border);
    origin = new Point(tt.X, tt.Y);
}

//Zoom according to the slider changes
private void _ImageZoomSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    //Panel panel = _ImageScrollArea;
    Image panel = _DisplayImage;

    //Set the scale coordinates on the ScaleTransform from the slider
    ScaleTransform transform = (ScaleTransform)((TransformGroup)panel.RenderTransform).Children.First(tr => tr is ScaleTransform);
    transform.ScaleX = _slider.Value;
    transform.ScaleY = _slider.Value;


    //Set the zoom (this will affect rotate too) origin to the center of the panel
    panel.RenderTransformOrigin = new Point(0.5, 0.5);

    foreach (UIElement child in _ROICollectionCanvas.Children)
    {
        //Assume all shapes are contained in a panel
        Panel childPanel = child as Panel;

        var x = childPanel.Children;

        //Shape width and heigh should scale, but not StrokeThickness
        foreach (var shape in childPanel.Children.OfType<Shape>())
        {
            if (shape.Tag == null)
            {
                //Hack: This is be a property on a usercontrol in my solution
                shape.Tag = shape.StrokeThickness;
            }
            double orignalStrokeThickness = (double)shape.Tag;

            //Attempt to keep the underlying shape border/stroke from thickening as well
            double newThickness = shape.StrokeThickness - (orignalStrokeThickness / transform.ScaleX);

            shape.StrokeThickness -= newThickness;
        }
    }
}
}

Sollte der code funktionieren in einem .NET 4.0 oder 4.5-Projekt und Lösung, vorausgesetzt, es ist kein cut/paste Fehler.

Irgendwelche Gedanken? Vorschläge sind willkommen.

  • Die Anwendung RenderTransforms nur die Darstellung beeinflusst. Es hat keinen Einfluss auf Layout, das ist, warum Sie sind nicht immer alle Scrollbalken.
  • Ok, ich habe eine komplette Umgestaltung Ihrer Probe in einem MVVM-Mode (das ist der RICHTIGE Weg zu tun, WPF). Ich poste es morgen. Ich werde jetzt gleich schlafen.
  • HighCore, ja, ich erkenne den Grund bin ich nicht zu sehen, scrollbars, ist, weil ich bin nicht der Anwendung einer LayoutTransform. Wie ich bereits in meinem ursprünglichen post, wenn ich mir vorstellen, dass in der Mischung der Stücke, die arbeiten (Pan, Zoom, ROI-Positionierung) starten, um ungewöhnliches Verhalten. Ich habe versucht, dass sowohl meine Waage und Übersetzen Sie verwandelt sich in eine LayoutTransform, und ich habe versucht, trennen Sie die Waage in einer RenderTransform und das Übersetzen in eine LayoutTransform. Jedes mal, wenn Dinge beginnen zu brechen ziemlich schnell. Ich bin interessiert an einem code-Beispiel, wenn Sie Ideen.
InformationsquelleAutor KyleLib | 2013-06-05
Schreibe einen Kommentar