【C#】C#实现鼠标滚轮的图像居中缩放

【fishing-pan:https://blog.csdn.net/u013921430 转载请注明出处】

  最近接触了一下C# 的内容,遇到一个需求,就是关于图像的的缩放。查找了网上的一些资源,发现这些方法存在一些或多或少的问题,而且大部分都是相互抄袭的。所以今天花点时间把自己查阅资料和实践的心得分享出来,希望对有需要的人有所帮助。
  如果这篇博客对你有所帮助,请点个赞哈。

准备工作

  在创建了C#的工程后,为了实现图像缩放,首先需要添加一个 Panel 容器至窗口中;然后再向 Panel 中添加一个 PictureBox 公共控件,并且将 PictureBoxSizeMode 设置为Zoom,最后将 Panel 容器停靠在父窗口。至此,准备工作就结束了。添加进父窗口的方法就是点击下图中的小三角形,然后选择停靠在父窗口。

在这里插入图片描述

创建事件

  在做完准备工作后就要添加事件了,但是在自带的事件中并没有MouseWheel事件,所以需要自己添加。

  首先在Designer.cs文件的panel部分添加以下事件声明,以创建鼠标滚动事件。

this.panel1.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseWheel);

实现缩放事件

  在实现缩放事件前,首先需要明确一些事情。

  1. 这里采用的方法是通过改变窗口大小来进行缩放的;
  2. 网络上的很多资料通过改变 PictureBox 相对于 panel 的位置来实现居中或者根据鼠标位置定点缩放。就是后面的的方式; this.pictureBox.pictureBox.Location = point(Left, Top);
  3. 窗口滑条有两个很重要的特征,首先就是滑条的长度表示窗口的大小,也就是 panel 的高和宽;第二,滑条的位置对于水平滑条来说,是滑条左侧端点的位置,垂直滑条的位置是上端点的位置。(这一条听起来有点懵,后面会解释)

  那么首先来说第二点;网络上常用的这种方法确实可以实现定点缩放;但是由于改变位置后的左上点一般是负值;会导致在窗口左侧和上侧的图像无法访问,试过的人应该都知道。是不可取的,但是我们通过修改滑条的位置来实现定点缩放就不会存在这种问题。所以我们在上面会提到滑条的一些特性。
  再来说说第三点;我们知道,当图像大小小于或者等于窗口大小时,是不需要滑条的,因为此时窗口可以放下图像;当图像大于窗口大小时,则需要滑条来调节。而滑条所在的整个区间的代表的是 PictureBox 的尺寸,滑条代表窗口的大小。几者之间满足以下等式;
L e n g t h S c r o l l L e n g t h R a n g e = S i z e W i n d o w S i z e P i c t u r e B o x \frac{LengthScroll}{LengthRange}=\frac{SizeWindow}{SizePictureBox} LengthRangeLengthScroll=SizePictureBoxSizeWindow

  从上面的关系式不难分析,滑条端点的位置取决于窗口展示的图像在整个 PictureBox 中的相对位置。了解以上关系,就可以实现定点缩放,接下来以窗口中心定点缩放来进行分析;

   PictureBox 相对于 panel 的位置 LeftTop 是可以直接获得的属性; panel 的尺寸 WidthHeight 也是可以直接获得的属性。根据这两个属性我们可以知道窗口中心位置的像素 CentorPictureBox 中的位置为;

int iOriginCentorX=(this.panel1.Width/2-this.pictureBox.Left);
int iOriginCentorY=(this.panel1.Height/2-this.pictureBox.Top);

  而在了解缩放比例后,中心点在图像中的坐标也是可以知道的;而窗口大小是不变的;就可以求出位于窗口左上位置的像素点在图像中的坐标;
n e w L e f t = n e w C e n t o r X − W i n d o w W i d t h 2 newLeft=newCentorX-\frac{WindowWidth}{2} newLeft=newCentorX2WindowWidth
n e w T o p = n e w C e n t o r Y − W i n d o w H e i g h t 2 + D e l t a newTop=newCentorY-\frac{WindowHeight}{2}+Delta newTop=newCentorY2WindowHeight+Delta
  而这个位置就是我们需要的滑条的位置。但是有个问题,滑动滚轮时,滑条位置会被改变;所以上面的公式中垂直滑条的位置要加上一个Delta,既是滚轮滑动一次,滑条滑动的距离。下面就是函数的代码。完整的项目资源,我放在了这里

private void panel1_MouseWheel(object sender, MouseEventArgs e)
        {
            if (Control.ModifierKeys==Keys.Control)
            {
                float fZoomFactor = 1.2f;      // 缩放因子
                int iOriginCentorX=(this.panel1.Width/2-this.pictureBox.Left);      //缩放前
                int iOriginCentorY=(this.panel1.Height/2-this.pictureBox.Top);

                //防止无限制的缩放
                if ((this.pictureBox.Width < 200 && e.Delta < 0) || (this.pictureBox.Width > 10000 && e.Delta > 0))
                    return;

                if(e.Delta>0)
                {
                    //缩放后的picture box的大小。
                    this.pictureBox.Width = (int)(fZoomFactor * this.pictureBox.Width);
                    this.pictureBox.Height = (int)(fZoomFactor * this.pictureBox.Height);
                    //缩放后的中心点距离picture box左上角的距离。
                    int iNewCentorX=(int)(iOriginCentorX*fZoomFactor);
                    int iNewCentorY=(int)(iOriginCentorY*fZoomFactor);

                    //缩放后的滚轮的位置。
                    this.panel1.AutoScrollPosition = new Point((int)(iNewCentorX - this.panel1.Width / 2),
                        (int)(iNewCentorY - this.panel1.Height / 2 + e.Delta));
                }
                else
                {   
                    this.pictureBox.Width = (int)(this.pictureBox.Width / fZoomFactor);
                    this.pictureBox.Height = (int)(this.pictureBox.Height / fZoomFactor);

                    int iNewCentorX = (int)(iOriginCentorX / fZoomFactor);
                    int iNewCentorY = (int)(iOriginCentorY / fZoomFactor);

                    this.panel1.AutoScrollPosition = new Point((int)(iNewCentorX - this.panel1.Width / 2),
                        (int)(iNewCentorY - this.panel1.Height / 2 + e.Delta));
                }
            }
            
        }

另一种缩放图像的方法。

  上面的过程,只是修改了装载图像的Picture Box的大小,而没有真正的修改图像的大小;所以当你保存图像的话,应该还是原图的大小。这里我提供一种修改了图像大小的缩放方法(就是Bitmap的缩放方法)。

private void panel1_MouseWheel(object sender, MouseEventArgs e)
        {
            if (Control.ModifierKeys == Keys.Control)
            {
                float fZoomFactor = 1.2f;      // 缩放因子
                int iOriginCentorX = (this.panel1.Width / 2 - this.pictureBox.Left);      //缩放前
                int iOriginCentorY = (this.panel1.Height / 2 - this.pictureBox.Top);

                //防止无限制的缩放
                if ((this.pictureBox.Width < 200 && e.Delta < 0) || (this.pictureBox.Width > 10000 && e.Delta > 0))
                    return;

                if (e.Delta > 0)
                {
                    //缩放后的picture box的大小。
                    int iNewWidth = (int)(fZoomFactor * this.pictureBox.Width);
                    int iNewHeight = (int)(fZoomFactor * this.pictureBox.Height);

                    //定义新的Bitmap;
                    Bitmap BitNewImg = new Bitmap(iNewWidth, iNewHeight);
                    //定义对BitNewImg的绘制方法;
                    Graphics graph = Graphics.FromImage(BitNewImg);
                    graph.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
                    //用原始图像绘制新图像;
                    graph.DrawImage((Bitmap)this.pictureBox.Image, new Rectangle(0, 0, iNewWidth, iNewHeight),
                        new Rectangle(0, 0, this.pictureBox.Width, this.pictureBox.Height), GraphicsUnit.Pixel);
                    //缩放后的中心点距离picture box左上角的距离。
                    int iNewCentorX = (int)(iOriginCentorX * fZoomFactor);
                    int iNewCentorY = (int)(iOriginCentorY * fZoomFactor);

                    this.pictureBox.Image = BitNewImg;
                    this.pictureBox.Width = this.pictureBox.Image.Width;
                    this.pictureBox.Height = this.pictureBox.Image.Height;
                    //缩放后的滚轮的位置。
                    this.panel1.AutoScrollPosition = new Point((int)(iNewCentorX - this.panel1.Width / 2),
                        (int)(iNewCentorY - this.panel1.Height / 2 + e.Delta));

                    graph.Dispose();
                }
                else
                {
                    int iNewWidth = (int)(this.pictureBox.Width / fZoomFactor);
                    int iNewHeight = (int)(this.pictureBox.Height / fZoomFactor);

                    Bitmap BitNewImg = new Bitmap(iNewWidth, iNewHeight);
                    //定义对BitNewImg的绘制方法;
                    Graphics graph = Graphics.FromImage(BitNewImg);
                    graph.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
                    //用原始图像绘制新图像;
                    graph.DrawImage((Bitmap)this.pictureBox.Image, new Rectangle(0, 0, iNewWidth, iNewHeight),
                        new Rectangle(0, 0, this.pictureBox.Width, this.pictureBox.Height), GraphicsUnit.Pixel);

                    this.pictureBox.Image = BitNewImg;
                    this.pictureBox.Width = this.pictureBox.Image.Width;
                    this.pictureBox.Height = this.pictureBox.Image.Height;

                    int iNewCentorX = (int)(iOriginCentorX / fZoomFactor);
                    int iNewCentorY = (int)(iOriginCentorY / fZoomFactor);

                    this.panel1.AutoScrollPosition = new Point((int)(iNewCentorX - this.panel1.Width / 2),
                        (int)(iNewCentorY - this.panel1.Height / 2 + e.Delta));
                }
            }

        }

最后

  从文章可以看出,其实图像缩放的实现并不难,重要的是理解滑条的位置的意义,从而决定缩放后滑条的位置,以达到定点缩放。虽然这篇博客讲的是以窗口中心的像素点进行定点缩放,但是了解了原理,根据鼠标位置进行缩放也并不难。
  如果这篇博客对你有所帮助,就点个赞吧。

  • 18
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在C#中使用OpenCV和鼠标滚轮实现对PictureBox中图像放大缩小功能,你可以按照以下步骤进行操作: 1. 在Visual Studio中创建一个新的Windows Forms应用程序项目。 2. 添加必要的引用: - 在解决方案资源管理器中,右键单击项目并选择“管理NuGet程序包”。 - 在NuGet包管理器中搜索并安装`OpenCvSharp4`。 3. 在窗体上添加一个PictureBox控件,并将其命名为`pictureBox1`。 4. 在窗体的构造函数中添加以下代码,用于注册鼠标滚轮事件: ```csharp public Form1() { InitializeComponent(); pictureBox1.MouseWheel += PictureBox1_MouseWheel; } ``` 5. 实现鼠标滚轮事件处理程序: ```csharp private void PictureBox1_MouseWheel(object sender, MouseEventArgs e) { // 获取当前PictureBox中显示的图像 Image image = pictureBox1.Image; // 判断是否有图像 if (image == null) return; // 获取当前图像的尺寸 int width = image.Width; int height = image.Height; // 设置缩放的比例 const float scaleStep = 0.1f; // 缩放步长 float scale = e.Delta > 0 ? (1 + scaleStep) : (1 - scaleStep); // 根据滚轮方向确定缩放比例 // 计算缩放后的图像尺寸 int newWidth = (int)(width * scale); int newHeight = (int)(height * scale); // 使用OpenCV进行图像缩放 Mat src = BitmapConverter.ToMat((Bitmap)image); // 将图像转换为OpenCV的Mat格式 Mat dst = new Mat(); Cv2.Resize(src, dst, new Size(newWidth, newHeight)); // 将缩放后的图像显示在PictureBox中 pictureBox1.Image = BitmapConverter.ToBitmap(dst); // 释放资源 src.Dispose(); dst.Dispose(); } ``` 在上述代码中,我们首先获取当前PictureBox中显示的图像。然后,根据鼠标滚轮的方向确定缩放比例。接下来,使用OpenCV的`Cv2.Resize()`函数将图像进行缩放,并将缩放后的图像显示在PictureBox中。 希望这个示例对你有帮助!如果还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值