2011-02-14 29 views
8

Related Question¿Cómo puedo transformar las coordenadas XY y la altura/ancho de una imagen escalada en una imagen de tamaño original?

Estoy tratando de hacer lo mismo que en la pregunta vinculada, pero con C#. Estoy mostrando una imagen escalada y estoy permitiendo que un usuario seleccione un área para cosechar. Sin embargo, no puedo tomar las coordenadas x1y1, x2y2 de la selección de imagen escalada y recortarla del original. Intenté hacer algunas matemáticas básicas como en la otra pregunta, pero obviamente tampoco es el enfoque correcto (definitivamente está más cerca).

Editar

originales Dimensiones de la imagen: w = 1024 h = 768

Scaled Dimensiones de la imagen: w = 550 h = 412

comienzo con una imagen, dicen 1024x768. Quiero que se ajuste lo más grande posible en una caja de 550x550. Estoy usando el siguiente método para obtener el tamaño de imagen escalado (manteniendo la relación de aspecto). Luego hago un cambio de tamaño básico a esas nuevas dimensiones.

En cuanto a un área de selección, puede ser cualquier cosa (0,0) a (100,100).

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; 
} 
+1

¿dónde está el cero de la imagen escalada? En la parte superior izquierda o en la parte inferior izquierda? –

+0

Supongo que arriba a la izquierda – scottm

+1

Escala una imagen con una transformación (matriz 2x2). Realiza una conversión de coordenadas con un inverso de esa matriz. Proporcione ejemplos numéricos específicos del tamaño de la imagen original, la ubicación y el tamaño de la imagen transformada, la ubicación: hace que sea más fácil para algunos pensar de esa manera, además de que elimina cierta ambigüedad. –

Respuesta

7

Sin un poco más de detalle, supongo que eres en realidad que sufren errores de redondeo ...
- Cuando se escala la coordenada (arriba, izquierda) al original, debe redondear hacia abajo (hacia la esquina superior izquierda).
- Cuando se cambia la escala del (abajo, derecha) de coordenadas nuevo a la original, tiene que redondear hacia arriba (hacia la parte inferior derecha)

Tome un ejemplo simple de una cuadrícula de 12x12 que el original, y un 4x4 rejilla como la versión escalada.
- (1,1) :(2,2) en la versión a escala = (3,3) :(8,8)
- 2x2 píxel = 25% del área de la versión a escala
- 6x6 píxeles = 25% del área de la versión original

Si se tuviera que multiplicar simplemente por los mismos factores de escala, esto daría (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:

Una mejor manera de explicar lo que estoy tratando de decir que sería dibujar un Picutre. Y yo apestaba en ASCII Art. Así que aquí hay otra prueba con palabras.

Un píxel no es un punto.Es un pequeño rectángulo por derecho propio.

Cuando utiliza un píxel para representar la parte superior izquierda de un rectángulo, está incluyendo el área desde el Punto más alto de la izquierda del píxel.

Cuando se utiliza un píxel para representar el Abajo a la derecha de un rectángulo, que estás incluyendo el área de todo el camino a la Abajo a la derecha del punto más del píxel.


Uso de la (12x12) => (4x4) ejemplo de nuevo, cada píxel escalado representa un conjunto de 3x3 conjunto de píxeles en el original. Cuando se habla de la esquina superior izquierda, se selecciona el píxel superior izquierdo del grupo de 3x3 píxeles en el original. Y cuando hablamos de la parte inferior derecha, seleccionas la parte inferior derecha del grupo de 3x3 píxeles en el original.


EDITAR: Usando sólo números enteros.

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

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


La única consideración es asegurarse de que no desborde el tipo de datos después de la multiplicación. Pero con las imágenes, no lo harás, a menos que sea una gran imagen.

+0

Esto podría ser cierto. Mi cosecha aparece en el área general, pero no se alinea del todo bien. – scottm

+0

¿Cómo se determina el factor de escala? ¿Simplemente escalado/origy? – scottm

+0

Sí, solo asegúrate de mantenerlo como un doble o algo bonito y floaty preciso. (Y calcule diferentes factores de escala X e Y) – MatBailie

0

Puede obtener las ubicaciones por ciento para las imágenes escaladas y convertirlos de nuevo en coordenadas de la imagen sin escala:

pX1 = scaledX1/scaled_width 
pY1 = scaledY1/scaled_height 

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

Aunque es intuitivo, no se ocupa de las coordenadas de abajo a la derecha. Un píxel no es un punto, es un pequeño rectángulo propio. Desea capturar la nueva representación de coordenadas de la esquina inferior derecha del rectángulo del píxel. – MatBailie

+0

Usar este método parece ayudarme a entender dónde estaba. Todavía está en el área general, pero no del todo. – scottm

Cuestiones relacionadas