Come faccio a convertire le coordinate del mouse per coordinate in pixel di un TransformedBitmap?

0

Domanda

La mia domanda è simile a Come ottenere una corretta posizione dei pixel da coordinate del mouse?, con l'ulteriore avvertenza che l'immagine è potenzialmente un TransformedBitmapdove salti mortali e rotazioni potrebbe essere applicato, e ancora restituire le coordinate in pixel dell'immagine originale.

Il mio Window's design simile a questo:

    <DockPanel>
        <Label DockPanel.Dock="Bottom" Name="TheLabel" />
        <Image DockPanel.Dock="Top" Name="TheImage" Stretch="Uniform" RenderOptions.BitmapScalingMode="NearestNeighbor" MouseMove="TheImage_MouseMove" />
    </DockPanel>

e il codebehind assomiglia a questo:

        public MainWindow()
        {
            InitializeComponent();

            const int WIDTH = 4;
            const int HEIGHT = 3;
            byte[] pixels = new byte[WIDTH * HEIGHT * 3];
            pixels[0] = Colors.Red.B;
            pixels[1] = Colors.Red.G;
            pixels[2] = Colors.Red.R;
            pixels[(WIDTH * (HEIGHT - 1) + (WIDTH - 1)) * 3 + 0] = Colors.Blue.B;
            pixels[(WIDTH * (HEIGHT - 1) + (WIDTH - 1)) * 3 + 1] = Colors.Blue.G;
            pixels[(WIDTH * (HEIGHT - 1) + (WIDTH - 1)) * 3 + 2] = Colors.Blue.R;
            BitmapSource bs = BitmapSource.Create(WIDTH, HEIGHT, 96.0, 96.0, PixelFormats.Bgr24, null, pixels, WIDTH * 3);
            TheImage.Source = bs;
        }

        private void TheImage_MouseMove(object sender, MouseEventArgs e)
        {
            Point p = e.GetPosition(TheImage);
            if (TheImage.Source is TransformedBitmap tb)
                TheLabel.Content = tb.Transform.Inverse.Transform(new Point(p.X * tb.PixelWidth / TheImage.ActualWidth, p.Y * tb.PixelHeight / TheImage.ActualHeight)).ToString();
            else if (TheImage.Source is BitmapSource bs)
                TheLabel.Content = new Point(p.X * bs.PixelWidth / TheImage.ActualWidth, p.Y * bs.PixelHeight / TheImage.ActualHeight).ToString();
        }

Quando si passa il mouse nell'angolo in basso a destra (che ho colorato di blu per una facile rintracciabilità) di non trasformato immagine, vedere correttamente le coordinate di (~4, ~3), che sono le dimensioni dell'immagine.

enter image description here

Tuttavia, una volta che si applica una trasformazione, per esempio cambiando TheImage.Source = bs; per TheImage.Source = new TransformedBitmap(bs, new RotateTransform(90.0));passando sopra il blu dà invece (~4, ~0).

enter image description here

Penso si possa guardare l'effettiva i valori della matrice di trasformazione, e di determinare le modalità per regolare il punto in tutti i vari casi, ma sembra che ci dovrebbe essere una soluzione più semplice utilizzando la trasformata inversa.

.net bitmapsource c# image
2021-11-23 06:19:28
1

Migliore risposta

1

Quando un elemento dell'Immagine rende un TransformedBitmap, il punto centrale della Trasformazione viene ignorato e la bitmap viene spostato in un apposito coordinare gamma.

Dal momento che questo spostamento non è applicata transfomation di un Punto, si dispone di compensare, ad esempio come questo:

var p = e.GetPosition(TheImage);

if (TheImage.Source is BitmapSource bs)
{
    p = new Point(
        p.X * bs.PixelWidth / TheImage.ActualWidth,
        p.Y * bs.PixelHeight / TheImage.ActualHeight);

    if (TheImage.Source is TransformedBitmap tb)
    {
        var w = tb.Source.PixelWidth;
        var h = tb.Source.PixelHeight;

        p = tb.Transform.Inverse.Transform(p);

        p = new Point((p.X + w) % w, (p.Y + h) % h);
    }

    TheLabel.Content = $"x: {(int)p.X}, y: {(int)p.Y}";
}

Il codice di cui sopra, tuttavia, non funzionano correttamente quando la Trasformazione del centro è impostato su un valore diverso da (0,0).

In ordine per farlo funzionare per Trasformazioni arbitrarie punto centrale, è necessario cancellare i valori di offset nella matrice di trasformazione:

var p = e.GetPosition(TheImage);

if (TheImage.Source is BitmapSource bs)
{
    p = new Point(
        p.X * bs.PixelWidth / TheImage.ActualWidth,
        p.Y * bs.PixelHeight / TheImage.ActualHeight);

    if (TheImage.Source is TransformedBitmap tb)
    {
        var w = tb.Source.PixelWidth;
        var h = tb.Source.PixelHeight;
        var t = tb.Transform.Value;
        t.Invert();
        t.OffsetX = 0d;
        t.OffsetY = 0d;

        p = t.Transform(p);

        p = new Point((p.X + w) % w, (p.Y + h) % h);
    }

    TheLabel.Content = $"x: {(int)p.X}, y: {(int)p.Y}";
}
2021-11-23 10:54:45

Grazie! Se uno incorpora il Image in un Grid che ha un background e sposta il MouseMove evento per il Gridil pixel di coordinate non sono più accurate se al di fuori dei limiti dell'immagine dal momento che si dà solo risposte da 0..larghezza e 0..altezza. Qualsiasi idea di come risolvere questo problema?
Craig W

Ci sono diversi modi. Più semplice, collegare il gestore di eventi per il nesting di un altro elemento che ha le stesse dimensioni dell'Immagine. Altrimenti ci sono metodi come TransformToDescendant o simili.
Clemens

Non sono sicuro di seguire. Posso tradurre il punto dal genitore griglia per l'immagine non è un problema. Ma per esempio quando l'utente posiziona il cursore a destra dell'immagine ruotata, mi piacerebbe che la coordinata y di essere negativo per riflettere che sono al di sopra dei limiti dell'immagine originale orientamento. Devo modificare la mia domanda o iniziare uno nuovo?
Craig W

Meglio scrivere una nuova.
Clemens

In altre lingue

Questa pagina è in altre lingue

Русский
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................