Comment puis-je convertir les coordonnées de la souris pour les coordonnées des pixels d'une TransformedBitmap?

0

La question

Ma question est similaire à la Façon dont pour obtenir la bonne position de pixel de coordonnées de la souris?, avec la mise en garde que l'image est potentiellement un TransformedBitmapoù sauts et rotations pourraient être appliquées, et toujours retourner les coordonnées des pixels de l'image originale.

Mon Window's design ressemble à ceci:

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

et le code ressemble à ceci:

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

Lorsque vous placez le curseur dans le coin inférieur droit (que j'ai coloré en bleu pour faciliter le suivi) de la non-transformée de l'image, à vous de voir correctement les coordonnées de (~4, ~3), qui sont les dimensions de l'image.

enter image description here

Cependant, une fois que vous appliquer une transformation, pour exemple, l'évolution du TheImage.Source = bs; pour TheImage.Source = new TransformedBitmap(bs, new RotateTransform(90.0));, planant au-dessus de la bleue à la place donne (~4, ~0).

enter image description here

Je pense que l'on peut voir les valeurs de matrice de la transformation, et de déterminer comment ajuster le point dans tous les cas, mais il semble qu'il devrait y avoir une solution plus facile à l'aide de la transformation inverse.

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

La meilleure réponse

1

Lorsqu'un élément de l'Image rend un TransformedBitmap, le point central de la Transformation est effectivement ignorée et l'image est décalé dans un de coordonnées approprié de la gamme.

Depuis cette maj n'est pas appliqué à la transfomation de un Point, vous avez pour compenser, par exemple comme ceci:

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

Le code ci-dessus ne sera cependant pas fonctionner correctement lorsque le centre de la Transformation est définie sur une valeur autre que (0,0).

Afin de faire travailler les Transformations arbitraires centre, vous avez pour effacer les valeurs de décalage dans la matrice de transformation:

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

Merci! Si l'on intègre l' Image dans un Grid qui a un arrière-plan et déplace le MouseMove de l'événement à l' Gridle pixel de coordonnées ne sont plus précis quand à l'extérieur des limites de l'image, car elle ne donne de réponses à partir de 0..largeur et de 0..hauteur. Une idée de comment résoudre ce problème?
Craig W

Il existe de multiples façons. Le plus simple, fixez le gestionnaire d'événement à l'autre imbriquée à l'élément parent qui a les mêmes dimensions que l'Image. Sinon il existe des méthodes comme TransformToDescendant ou similaire.
Clemens

Pas sûr que j'ai suivi. Je peux traduire le point de départ de la mère de la grille de l'image, pas de problème. Mais par exemple lorsque l'utilisateur place le pointeur vers la droite de l'image pivotée, j'aimerais que la coordonnée y être négatif pour refléter le fait qu'ils sont au-dessus des limites de l'image dans l'orientation d'origine. Dois-je modifier ma question ou en commencer une nouvelle?
Craig W

De mieux en écrire un nouveau.
Clemens

Dans d'autres langues

Cette page est dans d'autres langues

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