14 Stimmen

Wie kann ich XY-Koordinaten und Höhe/Breite eines skalierten Bildes in ein Bild in Originalgröße umwandeln?

Verwandte Frage

Ich versuche, die gleiche Sache wie in der verlinkten Frage zu tun, aber mit C#. Ich zeige ein skaliertes Bild und erlaube dem Benutzer, einen Bereich zum Zuschneiden auszuwählen. Ich kann jedoch nicht einfach die Koordinaten x1y1, x2y2 aus der skalierten Bildauswahl nehmen und diese aus dem Original beschneiden. Ich habe versucht, einige grundlegende Mathematik wie in der anderen Frage zu tun, aber das ist offensichtlich nicht der richtige Ansatz entweder (es ist definitiv näher).

Editar

Abmessungen des Originalbildes: w = 1024 h = 768

Skalierte Bildabmessungen: w = 550 h = 412

Ich beginne mit einem Bild, sagen wir 1024x768. Ich möchte, dass es so groß wie möglich in ein Feld von 550x550 passt. Ich verwende die folgende Methode, um die skalierte Bildgröße zu erhalten (unter Beibehaltung des Seitenverhältnisses). Dann führe ich eine grundlegende Größenänderung auf diese neuen Abmessungen durch.

Der Auswahlbereich kann zwischen (0,0) und (100,100) liegen.

private static Rectangle MaintainAspectRatio(Image imgPhoto, Rectangle thumbRect)
{
    int sourceWidth = imgPhoto.Width; int sourceHeight = imgPhoto.Height; int sourceX = 0; int sourceY = 0; int destX = 0; int destY = 0;

    float nPercent = 0;
    float nPercentW = 0;
    float nPercentH = 0;

    nPercentW = ((float)thumbRect.Width / (float)sourceWidth);
    nPercentH = ((float)thumbRect.Height / (float)sourceHeight);

    //if we have to pad the height pad both the top and the bottom
    //with the difference between the scaled height and the desired height
    if (nPercentH < nPercentW)
    {
        nPercent = nPercentH;
        destX = (int)((thumbRect.Width - (sourceWidth * nPercent)) / 2);
    }
    else
    {
        nPercent = nPercentW;
        destY = (int)((thumbRect.Height - (sourceHeight * nPercent)) / 2);
    }

    int destWidth = (int)(sourceWidth * nPercent);
    int destHeight = (int)(sourceHeight * nPercent);

    Rectangle retRect = new Rectangle(thumbRect.X, thumbRect.Y, destWidth, destHeight);
    return retRect;
}

12voto

MatBailie Punkte 77040

Ohne nähere Angaben vermute ich, dass Sie tatsächlich unter Rundungsfehlern leiden...
- Wenn Sie die Koordinate (oben, links) auf das Original zurückskalieren, müssen Sie abrunden (nach links oben).
- Wenn Sie die (untere, rechte) Koordinate auf das Original zurückskalieren, müssen Sie aufrunden (nach rechts unten)

Nehmen Sie ein einfaches Beispiel mit einem 12x12-Gitter als Original und einem 4x4-Gitter als skalierte Version.
- (1,1):(2,2) in der skalierten Version = (3,3):(8,8)
- 2x2 Pixel = 25% der Fläche der skalierten Version
- 6x6 Pixel = 25% der Fläche der Originalversion

Würde man einfach mit denselben Skalierungsfaktoren multiplizieren, ergäbe dies (3,3):(6,6).

OriginalTop = INT(ScaledTop * YScalingFactor);
OriginalLeft = INT(ScaledLeft * XScalingFactor);

OriginalBottom = INT((ScaledBottom + 1) * YScalingFactor) - 1;
OriginalRight = INT((ScaledRight + 1) * XScalingFactor) - 1;

EDITAR :

Am besten kann ich das, was ich zu sagen versuche, anhand eines Bildes erklären. Und ich bin schlecht in ASCII-Kunst. Also hier ein weiterer Versuch mit Worten.

Ein Pixel ist kein Punkt. Es ist ein kleines, eigenständiges Rechteck.

Wenn Sie ein Pixel verwenden, um die linke obere Ecke eines Rechtecks darzustellen, schließen Sie den Bereich ab dem obersten linken Punkt des Pixels ein.

Wenn Sie ein Pixel verwenden, um die Unten rechts eines Rechtecks, wird die Fläche bis zum Rand mit einbezogen. Unten rechts der größte Punkt des Pixels.

Wenn man das Beispiel (12x12) => (4x4) wieder aufgreift, repräsentiert jedes skalierte Pixel einen ganzen Satz von 3x3 Pixeln im Original. Wenn Sie von oben links sprechen, wählen Sie das oberste linke Pixel der 3x3-Pixel-Gruppe im Original. Und wenn Sie von unten rechts sprechen, wählen Sie das untere rechte Pixel der 3x3-Pixel-Gruppe des Originals.

EDITAR : Nur ganze Zahlen verwenden.

NewTop    = ((   OldTop    ) * NewHeight / OldHeight);
NewLeft   = ((   OldLeft   ) * NewWidth  / OldWidth );

NewBottom = ((OldBottom + 1) * NewHeight / OldHeight) - 1;
NewRight  = ((OldRight  + 1) * NewWidth  / OldWidth ) - 1;

Sie müssen nur darauf achten, dass Ihr Datentyp nach der Multiplikation nicht überläuft. Aber bei Bildern ist das nicht der Fall, es sei denn, es handelt sich um ein riesiges Bild.

0voto

Justin808 Punkte 20019

Sie können die prozentualen Positionen für die skalierten Bilder abrufen und sie in Koordinaten für das nicht skalierte Bild zurückverwandeln:

pX1 = scaledX1/scaled_width
pY1 = scaledY1/scaled_height

unscaledX1 = ceiling(unscaled_width * pX1)
unscaledY1 = ceiling(unscaled_height * pY1)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X