WPF Image Pan, Zoom и Scroll со слоями на холсте

Я надеюсь, что кто-то может помочь мне здесь. Я'm создание приложения для работы с изображениями WPF, которое получает живые изображения с камеры, позволяя пользователям просматривать изображение, а затем выделять области интереса (ROI) на этом изображении. Информация о ROI (ширина, высота, местоположение относительно точки на изображении и т. Д.) Затем отправляется обратно в камеру, фактически сообщая / обучая прошивку камеры, где искать такие вещи, как штрих-коды, текст, уровни жидкости, повороты на винт и т. д. на изображении). Желаемой функцией является возможность панорамирования и масштабирования изображения, иs ROI, а также прокрутка, когда изображение увеличено больше, чем область просмотра. StrokeThickness и размер шрифта ROI 'Необходимо сохранить исходный масштаб, но ширина и высота форм в области интереса должны масштабироваться вместе с изображением (это важно для захвата точных точек пикселей для передачи на камеру). Я'Мы разработали большую часть этого, за исключением прокрутки и некоторых других вопросов. Мои две проблемные области:

Когда я представляю ScrollViewer, я неНе получайте никакого поведения прокрутки. Насколько я понимаю, мне нужно ввести LayoutTransform, чтобы получить правильное поведение ScrollViewer. Однако, когда я это делаю, другие области начинают разрушаться (например, рентабельность инвестиций не• удерживайте их правильное положение над изображением, или указатель мыши начинает ползти от выбранной точки на изображении при панорамировании, или левый угол моего изображения отскакивает к текущей позиции мыши на MouseDown.)

Я могу'не понимаю масштаб моего ROIтак, как они мне нужны. У меня это работает, но это не идеально. Что у меня нетне сохранить точную толщину хода, и я неЯ смотрел на игнорирование масштаба текстовых блоков. Надеюсь, тыпосмотрим что яя делаю в примерах кода.

Я уверен, что моя проблема связана с моим непониманием Transforms и их отношения к системе макетов WPF. Надеюсь, что исполнение кода, который показывает то, что яВыполнение пока поможет (см. ниже).

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

Во-первых, ниже скриншот, показывающий изображение с ROI 's (текст и форма). Прямоугольник, эллипс и текст должны следовать за областью на изображении в масштабе и вращении, но не должныМасштаб в толщину или размер шрифта.

Вот's XAML, который показывает вышеупомянутое изображение, вместе с ползунком для масштабирования (масштабирование с помощью колесика мыши появится позже)




  

  
  
    
      
                                    
           
             
               
               
             
           
         
          
           

             
             
               
                 
             

             
             
               
               
             
           
         
       
     
  

Вот'Это C #, который управляет панорамированием и масштабированием.

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 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())
        {
            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;
        }
    }
}
}

Код должен работать в проекте и решении .NET 4.0 или 4.5, при условии отсутствия ошибок вырезания / вставки.

Какие-нибудь мысли? Предложения приветствуются.

Ответы на вопрос(2)

Ваш ответ на вопрос