2010-04-02 7 views
3

J'essaie d'utiliser la position de la souris pour calculer le facteur d'échelle pour la mise à l'échelle d'une image. Fondamentalement, plus on s'éloigne du centre de l'image, plus il devient gros; et plus vous vous rapprochez du centre, plus il est petit. J'ai du code jusqu'ici, mais c'est vraiment étrange et je n'ai absolument plus d'idées. D'abord je vous le ferai savoir, une chose que j'essayais de faire est de faire une moyenne de 5 distances pour obtenir une animation de redimensionnement plus fluide. Voici mon code:Mise à l'échelle d'une image à l'aide de la souris dans une application WinForms?

private void pictureBoxScale_MouseMove(object sender, MouseEventArgs e) 
{ 
    if (rotateScaleMode && isDraggingToScale) 
    { 
     // For Scaling    
     int sourceWidth = pictureBox1.Image.Width; 
     int sourceHeight = pictureBox1.Image.Height; 
     float dCurrCent = 0; // distance between the current mouse pos and the center of the image 
     float dPrevCent = 0; // distance between the previous mouse pos and the center of the image 

     System.Drawing.Point imgCenter = new System.Drawing.Point(); 

     imgCenter.X = pictureBox1.Location.X + (sourceWidth/2); 
     imgCenter.Y = pictureBox1.Location.Y + (sourceHeight/2); 

     // Calculating the distance between the current mouse location and the center of the image 
     dCurrCent = (float)Math.Sqrt(Math.Pow(e.X - imgCenter.X, 2) + Math.Pow(e.Y - imgCenter.Y, 2)); 

     // Calculating the distance between the previous mouse location and the center of the image 
     dPrevCent = (float)Math.Sqrt(Math.Pow(prevMouseLoc.X - imgCenter.X, 2) + Math.Pow(prevMouseLoc.Y - imgCenter.Y, 2)); 

     if (smoothScaleCount < 5) 
     { 
      dCurrCentSmooth[smoothScaleCount] = dCurrCent; 
      dPrevCentSmooth[smoothScaleCount] = dPrevCent; 
     } 


     if (smoothScaleCount == 4) 
     { 
      float currCentSum = 0; 
      float prevCentSum = 0; 
      for (int i = 0; i < 4; i++) 
      { 
       currCentSum += dCurrCentSmooth[i]; 
      } 
      for (int i = 0; i < 4; i++) 
      { 
       prevCentSum += dPrevCentSmooth[i]; 
      } 

      float scaleAvg = (currCentSum/5)/(prevCentSum/5); 


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

      // If statement is for limiting the size of the image 
      if (destWidth > (currentRotatedImage.Width/2) && destWidth < (currentRotatedImage.Width * 3) && destHeight > (currentRotatedImage.Height/2) && destWidth < (currentRotatedImage.Width * 3)) 
      { 
       AForge.Imaging.Filters.ResizeBilinear resizeFilter = new AForge.Imaging.Filters.ResizeBilinear(destWidth, destHeight); 
       pictureBox1.Image = resizeFilter.Apply((Bitmap)currentRotatedImage); 
       pictureBox1.Size = pictureBox1.Image.Size; 
       pictureBox1.Refresh(); 
      } 

      smoothScaleCount = -1; 
     } 
     prevMouseLoc = e.Location; 
     currentScaledImage = pictureBox1.Image; 
     smoothScaleCount++; 

    } 
} 

EDIT: Merci à Ben Voigt et tout Ray fonctionne bien maintenant. La seule chose qui ne va pas, c'est qu'avec la façon dont je le fais, l'image ne garde pas son ratio; mais je réparerai ça plus tard. Voici ce que j'ai pour ceux qui veulent savoir:

private void pictureBoxScale_MouseMove(object sender, MouseEventArgs e) 
    { 
     if (rotateScaleMode && isDraggingToScale) 
     { 
      // For Scaling    
      int sourceWidth = pictureBox1.Image.Width; 
      int sourceHeight = pictureBox1.Image.Height; 
      int scale = e.X + p0.X; //p0 is the location of the mouse when the button first came down 
      int destWidth = (int)(sourceWidth + (scale/10)); //I divide it by 10 to make it slower 
      int destHeight = (int)(sourceHeight + (scale/10)); 

      if (destWidth > 20 && destWidth < 1000 && destHeight > 20 && destWidth < 1000) 
      { 
       AForge.Imaging.Filters.ResizeBilinear resizeFilter = new AForge.Imaging.Filters.ResizeBilinear(destWidth, destHeight); 
       pictureBox1.Image = resizeFilter.Apply((Bitmap)currentRotatedImage); 
       pictureBox1.Size = pictureBox1.Image.Size; 
       pictureBox1.Refresh(); 
      } 
      currentScaledImage = pictureBox1.Image; // This is only so I can rotate the scaled image in another part of my program 

     } 
    } 
+1

Alors, quelle est votre question? – Aaronaught

+0

@Aaronaught: "Pourquoi est-ce que cela se comporte bizarrement?" –

+1

Je suggérerais des tests unitaires et/ou des tests avec un débogueur. Je l'essaierais aussi sans la "mise à l'échelle douce" car il y a des pièces qui semblent suspectes. –

Répondre

1

La mise à l'échelle ne sera pas fluide si vous utilisez le centre de l'image. Au lieu de cela, utilisez le point initial de la souris (appelez-le p0). De même, plutôt que d'utiliser la distance entre ce point et le point de glissement actuel (e), prenez simplement la différence le long d'un axe (par exemple exp (e.Y - p0.Y)).

+0

Je ne sais pas pourquoi vous proposez exp pour le calcul de la norme d'infini. Vouliez-vous dire max (abs (x1-x2), abs (y1-y2))? –

+0

Ca a du sens pour moi, j'aime ça. – Gaax

+0

@Ben. Vous ne voulez pas de norme. Vous avez besoin de +/- valeurs. L'exp est juste un moyen d'obtenir une valeur d'échelle à partir d'une valeur +/-. – Ray

1

Il me semble (du calcul de scaleAvg) comme vous l'image déjà redimensionnant échelle. C'est une très mauvaise idée car la mise à l'échelle est perte et les erreurs s'accumulent. Au lieu de cela, gardez une copie de l'image originale nette et mettez l'original directement à la taille actuelle.

Aussi, je suggère d'utiliser une norme différente, peut-être la distance de Manhattan, au lieu de la distance cartésienne actuelle qui est une norme à deux.

Si vous continuez à utiliser la norme deux, pensez à vous débarrasser des appels Math.Pow. Ils sont probablement une si petite partie de la complexité de mise à l'échelle globale que cela n'a pas d'importance, mais la multiplication par elle-même devrait être beaucoup plus rapide que Math.Pow pour la quadrature d'un nombre.