首页 > 解决方案 > 如何在 Python 中使用补间而不损失准确性?

问题描述

我一直在努力使用补间来使 Python 中的鼠标移动平滑,我目前正在尝试自动化一些重复性任务。

我尝试使用补间来消除在未应用平滑的情况下出现的一些粗糙度,但是这样做我会失去明显的准确性,毕竟我的dydx值都被 a 分割,number最终得到余数。这可以通过获取greatest common factor我的两个值来解决(因为两者都dx需要dy被相同的拆分number)不幸的是,这会导致 GCD 太小。

由于鼠标无法在屏幕上移动像素的其余部分,我最终会明显损失精度。

问题:如何在不损失准确性的情况下对鼠标移动应用补间?

import pytweening
import win32api
import win32con
from time import sleep

dy = [50, 46, 42, 38, 33, 29, 24, 20, 15, 10, 10]
dx = [-35, 6, -55, -43, 0, 17, 29, 38, 42, 42, 38]

while True:

    count = 0

    values = [(pytweening.getPointOnLine(0, 0, x, y, 0.20)) for x, y in zip(dx, dy)]

    while win32api.GetAsyncKeyState(win32con.VK_RBUTTON) and win32api.GetAsyncKeyState(win32con.VK_LBUTTON):

        if count < len(dx):

            for _ in range(5):
                win32api.mouse_event(1, int(values[count][0]), int(values[count][1]), 0, 0)
                sleep(0.134 / 5)

            count += 1

标签: pythonsmoothingeasing

解决方案


这里的基本问题是您使用整数量的相对运动,这不会加起来您正在寻找的总运动。如果你只想线性移动,你也根本不需要 PyTweening。这个解决方案怎么样?

import win32api
import win32con
from time import sleep

Npoints = 5
sleeptime = 0.134 / Npoints

dys = [50, 46, 42, 38, 33, 29, 24, 20, 15, 10, 10]
dxs = [-35, 6, -55, -43, 0, 17, 29, 38, 42, 42, 38]

x, y = win32api.GetCursorPos()

for dx, dy in zip(dxs, dys):
    ddx = dx/Npoints
    ddy = dy/Npoints
    for _ in range(Npoints):
        x += ddx
        y += ddy

        win32api.SetCursorPos(int(x), int(y))
        sleep(sleeptime)

请注意,仍然会有一些非常小的舍入误差,并且光标将在点之间沿直线移动。如果光标从 (0, 0) 开始,这就是它将形成的形状(红叉是光标将被设置到的点):

鼠标移动的形状

如果您想通过点以平滑曲线移动并且您可以使用 numpy 和 scipy,这将处理:

import numpy as np
import scipy.interpolate as sci

totalpoints = 50  # you can set this to a larger number to get closer spaced points
x, y = win32api.GetCursorPos()

# work out absolute coordinates of new points
xs = np.cumsum([x, *dxs])
ys = np.cumsum([y, *dys])

# fit spline between the points (s=0 makes the spline hit all the points)
tck, u = sci.splprep([xs, ys], s=0)

# Evaluate the spline and move to those points
for x, y in zip(*sci.splev(np.linspace(0, 1, totalpoints), tck)):
    win32api.SetCursorPos(int(x), int(y))
    sleep(sleeptime)

这导致如下所示的位置:

点之间的样条插值


推荐阅读