好不容易缕清了之前做的图片根据鼠标指向进行放大缩小功能,现在来记录一下。
注:
以下内容是紧接着: 的内容的,之前演示了如何移动和缩放label
显示的图片,以下内容演示如何让label
跟随鼠标指针指向来缩放。如果大佬有更好的方法,希望能够指点一二。
稍微构想一下,想要实现根据鼠标当前坐标放大图片,图片放大是完全不影响的,需要考虑的是图片的坐标,即让鼠标当前指向的图片上的位置所指向的点保持不动。
1、解释方法之前,先看我做的两个例子:
注
:
- 以下代码都是发生在滚轮事件中,滚动时会一直触发的。
- 移动图片和图片的放缩是通过设置
label
的setGeometry
属性实现的。
(1)沿着label的左上角点放缩:
此方法只要将左上角的点固定就行:
# 这句话中的各个参数分别代表了:
# lflabel1: 显示图片的label
# self.labelx: 指向lflabel1的左上角点的x坐标,除非发生拖拽,否则保持不动
# self.labely: 指向lflabel1的左上角点的y坐标,除非发生拖拽,否则保持不动
# self.label_wid: 指向lflabel1的当前宽度
# self.label_hig: 指向lflabel1的当前高度
self.ui.lflabel1.setGeometry(QtCore.QRect(
self.labelx,
self.labely,
self.label_wid,
self.label_hig))
那么label
就会沿着lflabel1
的左上角的点进行放缩。
(2)沿着label的右下角点放缩:
#写的有些复杂,慢慢解释吧
#resize_point: 是之前定义的缩放系数
#cur_lab_shape:指代label当前的宽高和channel的组
#int((1-self.resize_point/10)*self.cur_lab_shape[1]):
# 表示放缩系数乘以label当前的宽,用1去剪是因为1是下限,减去量是放缩系数的百分比
#int((1-self.resize_point/10)*self.cur_lab_shape[0]):
# 表示放缩系数乘以label当前的高,用1去剪是因为1是下限,减去量是放缩系数的百分比
self.ui.lflabel1.setGeometry(QtCore.QRect(
self.labelx+int((1-self.resize_point/10)*self.cur_lab_shape[1]),
self.labely+int((1-self.resize_point/10)*self.cur_lab_shape[0]),
self.label_wid,
self.label_hig))
其实这段代码不用看,就是把图片的放缩量的宽和高,加到左上角的x和y坐标上去。
那么label
就会沿着lflabel1
的右下角的点进行放缩。
同理,我只要把加数改为:
int((1-self.resize_point/10)*self.cur_lab_shape[1]/2)
也就是除以了一个2
,那label
就会变成沿着label
的中心点坐标进行放缩。
2、沿着鼠标当前指向的点:
如前面所说,想要使label
根据鼠标的指向的点进行放缩,只要把鼠标指向的点固定就行了。然而说的是很简单,但是想要实现可太难了。不使劲想还真想像不出来,我之前也是绞尽脑汁想了很久,然后不断地改参数,不断修改才实现的。
我想到的方法:获取鼠标相对于label的比值!
将我鼠标的坐标,与中点或是右下角的点的比值,替换到我的缩放位移中去。
既然放缩系数除以2
,就能使它沿着中心点坐标进行放缩,那我把放缩量乘以一个比值,是不是就能根据这个比值量指向的点位来放缩呢?
(1)比如我这样写:
self.ui.lflabel1.setGeometry(QtCore.QRect(
self.labelx+int((1-self.resize_point/10)*self.cur_lab_shape[1]/3),
self.labely+int((1-self.resize_point/10)*self.cur_lab_shape[0]/2),
self.label_wid,
self.label_hig))
那放缩时,就会沿着宽度的1/3
处,高度的1/2
处的点进行放缩。
(2)鼠标坐标的占比:
那我就要获取鼠标坐标对应图片宽高的占比。
大致顺序为:
获得鼠标相对于图片窗口中的位置,将该相对于label
的横坐标除以label
的宽,相对于label
的纵坐标除以label
的高,这样两个比值就有了,接着将这个比值替换之前的除数(由于这里是比值,所以应该改成乘)
代码实现:(一句一句解释吧)
# 获取鼠标的横纵坐标,这是相对于整个软件界面的坐标
x_1,y_1 = pag.position()
# 计算鼠标在窗口中的相对于label的横纵坐标
# 这里减去10是去除外部框体,self.ui.lflabel1.x()表示label的横坐标,在label之外的部分,要剔除
x_12 = (x_1 -10 - self.ui.lflabel1.x() )/self.ui.lflabel1.width()
# 同上
y_12 = (y_1 - 135 - self.ui.lflabel1.y())/self.ui.lflabel1.height()
# 由于当x_12小于0或大于1的时候,表示鼠标在窗体外,这时如果按鼠标位置缩放,容易跳出屏幕,所以转int判断
if int(x_12)==0 & int(y_12)==0:
# 这里为什么添加一个中转变量呢,因为即使我上面添加了判断,鼠标只要去到过label之外的区域,
# 上一个值还是会影响我的下一次缩放,导致跳出窗体
x_11 = x_12
y_11 = y_12
self.ui.lflabel1.setGeometry(QtCore.QRect(
# 由于除数是个比值,所以将前面的除以 2 替换成乘以 x_11
self.labelx +int((1-self.resize_point/10)*self.cur_lab_shape[1]*x_11),
self.labely + int((1-self.resize_point/10)*self.cur_lab_shape[0]*y_11),
self.label_wid,
self.label_hig))
运行结果:
由于只能上传5M
以内的gif
,抽帧导致效果不是特别明显,但是单是对比图中的第一次缩放和最后的缩放可以明显看到,第一次鼠标在最右,图片缩放后图片右侧没有和外框触碰,之后的缩放都与右侧外框接触了。
哈哈,然后这个问题解决了,但其实我的工作量并不止这么多,我还要把标注的图案一边对应坐标映射到原图上,然后再显示到label
中,一边还要把图案映射到标注的 ground truth
图像上,可以说是困难得多!等有空的时候我会在下面添加一个完整的示例的代码。