¿Cómo puedo convertir de coordenadas del ratón a las coordenadas de píxel de un TransformedBitmap?

0

Pregunta

Mi pregunta es similar a Cómo conseguir la correcta posición de píxel de coordenadas del ratón?, con la salvedad de que la imagen es potencialmente un TransformedBitmap, donde los giros y rotaciones podría ser aplicado, y todavía devolver las coordenadas de píxel de la imagen original.

Mi Window's diseño se parece a esto:

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

y el código subyacente se parece a esto:

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

Cuando se pasa el mouse en la esquina inferior derecha (que yo de color azul para facilitar el seguimiento de las no transformadas de la imagen, puede ver correctamente las coordenadas de (~4, ~3), que son las dimensiones de la imagen.

enter image description here

Sin embargo, una vez que usted aplica una transformación, por ejemplo cambiar TheImage.Source = bs; a TheImage.Source = new TransformedBitmap(bs, new RotateTransform(90.0));, se cierne sobre el azul en lugar de da (~4, ~0).

enter image description here

Creo que uno podía mirar a los reales valores de la matriz de la transformación, y determinar cómo ajustar el punto en todos los casos, pero parece que debe haber una solución más fácil el uso de la inversa de la transformación.

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

Mejor respuesta

1

Cuando un elemento de la Imagen representa un TransformedBitmap, el punto central de la Transformación es el ignorados y el mapa de bits se desplaza en una de coordenadas apropiado de la gama.

Dado que este cambio no se aplica a la transfomation de un Punto, usted tiene que compensar, por ejemplo, como este:

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}";
}

El código anterior sin embargo no funciona correctamente cuando el centro de Transformación se establece en un valor distinto de (0,0).

Con el fin de hacer que funcione para Transformaciones arbitrarias centro de punto, usted tiene que borrar los valores de desplazamiento en la transformación de la matriz:

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

Gracias! Si uno incorpora el Image en un Grid que tiene un fondo y se mueve el MouseMove evento para el Gridel píxel de coordenadas no son más precisas cuando fuera de los límites de la imagen, ya que sólo da respuestas desde 0..de ancho y 0..de altura. ¿Alguna idea de cómo solucionar este problema?
Craig W

Hay múltiples maneras. Más simple, conecte el controlador de eventos para que otra instrucción de los padres elemento que tiene las mismas dimensiones de la Imagen. De lo contrario, hay métodos como TransformToDescendant o similar.
Clemens

No estoy seguro de que siga. Puedo traducir el punto de que el padre de la cuadrícula de la imagen no hay problema. Pero, por ejemplo, cuando el usuario se desplaza a la derecha de la imagen rotada, me gustaría que la coordenada a ser negativo para reflejar que están por encima de los límites de la imagen en la orientación original. Debo editar mi pregunta o iniciar uno nuevo?
Craig W

Mejor escribir uno nuevo.
Clemens

En otros idiomas

Esta página está en otros idiomas

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