【问题标题】:Pyautogui: Mouse Movement with bezier curvePyautogui:具有贝塞尔曲线的鼠标移动
【发布时间】:2017-11-12 00:49:46
【问题描述】:

我试图在 Pyautogui 中以贝塞尔曲线运动来移动鼠标,以模拟更多的人类运动,如下所示:

pyautogui 中有一些补间/缓动函数,但没有一个代表贝塞尔曲线类型的运动。我创建了一个小脚本来计算它在最终到达目的地之前会到达的随机位置。

默认“机器人”线性路径:

不幸的是,每个目的地鼠标都会暂时停止。

import pyautogui
import time
import random
print "Randomized Mouse Started."
destx = 444;
desty = 631;
x, y = pyautogui.position() # Current Position
moves = random.randint(2,4)
pixelsx = destx-x
pixelsy = desty-y
if moves >= 4:
        moves = random.randint(2,4)
avgpixelsx = pixelsx/moves
avgpixelsy = pixelsy/moves
print "Pixels to be moved X: ", pixelsx," Y: ",pixelsy, "Number of mouse movements: ", moves, "Avg Move X: ", avgpixelsx, " Y: ", avgpixelsy

while moves > 0:
        offsetx = (avgpixelsx+random.randint(-8, random.randint(5,10)));
        offsety = (avgpixelsy+random.randint(-8, random.randint(5,10)));
        print x + offsetx, y + offsety, moves
        pyautogui.moveTo(x + offsetx, y + offsety, duration=0.2)
        moves = moves-1
        avgpixelsx = pixelsx / moves
        avgpixelsy = pixelsy / moves

信息:

  • Windows 10
  • Python 2.7
  • 愿意使用其他库,如有需要,Python版本

我看过这个帖子:python random mouse movements

但不知道如何定义“开始和停止”位置。答案与我正在寻找的非常接近。

关于如何实现这一点的任何想法?

【问题讨论】:

  • 你能解释一下你的代码吗?我正在做类似的事情

标签: python random pyautogui


【解决方案1】:

对于一个简单的解决方案,您可以尝试将numpybezier 库一起使用:

import pyautogui
import bezier
import numpy as np


# Disable pyautogui pauses (from DJV's answer)
pyautogui.MINIMUM_DURATION = 0
pyautogui.MINIMUM_SLEEP = 0
pyautogui.PAUSE = 0

# We'll wait 5 seconds to prepare the starting position
start_delay = 5 
print("Drawing curve from mouse in {} seconds.".format(start_delay))
pyautogui.sleep(start_delay)

# For this example we'll use four control points, including start and end coordinates
start = pyautogui.position()
end = start[0]+600, start[1]+200
# Two intermediate control points that may be adjusted to modify the curve.
control1 = start[0]+125, start[1]+100
control2 = start[0]+375, start[1]+50

# Format points to use with bezier
control_points = np.array([start, control1, control2, end])
points = np.array([control_points[:,0], control_points[:,1]]) # Split x and y coordinates

# You can set the degree of the curve here, should be less than # of control points
degree = 3
# Create the bezier curve
curve = bezier.Curve(points, degree)
# You can also create it with using Curve.from_nodes(), which sets degree to len(control_points)-1
# curve = bezier.Curve.from_nodes(points)

curve_steps = 50  # How many points the curve should be split into. Each is a separate pyautogui.moveTo() execution
delay = 1/curve_steps  # Time between movements. 1/curve_steps = 1 second for entire curve

# Move the mouse
for i in range(1, curve_steps+1):
    # The evaluate method takes a float from [0.0, 1.0] and returns the coordinates at that point in the curve
    # Another way of thinking about it is that i/steps gets the coordinates at (100*i/steps) percent into the curve
    x, y = curve.evaluate(i/curve_steps)
    pyautogui.moveTo(x, y)  # Move to point in curve
    pyautogui.sleep(delay)  # Wait delay

我想出了这个尝试写一些东西来用鼠标绘制SVG Paths。运行上面的代码将使您的鼠标沿着与下面相同的路径移动。红点位于定义曲线的每个控制点处。

请注意,如果您想像我在 GIMP 中所做的那样单击并拖动,则必须在脚本末尾的循环之前添加 pyautogui.mouseDown() 和在循环之后添加 pyautogui.mouseUp()

您可以在此处查看bezier 文档:https://bezier.readthedocs.io/en/stable/index.html

【讨论】:

    【解决方案2】:

    使用scipy, numpy 和任何可以简单地移动鼠标光标的东西:

    import pyautogui
    import random
    import numpy as np
    import time
    from scipy import interpolate
    import math
    
    def point_dist(x1,y1,x2,y2):
        return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
    
    cp = random.randint(3, 5)  # Number of control points. Must be at least 2.
    x1, y1 = pyautogui.position()  # Starting position
    
    # Distribute control points between start and destination evenly.
    x = np.linspace(x1, x2, num=cp, dtype='int')
    y = np.linspace(y1, y2, num=cp, dtype='int')
    
    # Randomise inner points a bit (+-RND at most).
    RND = 10
    xr = [random.randint(-RND, RND) for k in range(cp)]
    yr = [random.randint(-RND, RND) for k in range(cp)]
    xr[0] = yr[0] = xr[-1] = yr[-1] = 0
    x += xr
    y += yr
    
    # Approximate using Bezier spline.
    degree = 3 if cp > 3 else cp - 1  # Degree of b-spline. 3 is recommended.
                                      # Must be less than number of control points.
    tck, u = interpolate.splprep([x, y], k=degree)
    # Move upto a certain number of points
    u = np.linspace(0, 1, num=2+int(point_dist(x1,y1,x2,y2)/50.0))
    points = interpolate.splev(u, tck)
    
    # Move mouse.
    duration = 0.1
    timeout = duration / len(points[0])
    point_list=zip(*(i.astype(int) for i in points))
    for point in point_list:
        pyautogui.moveTo(*point)
        time.sleep(timeout)
    

    您可以通过设置移除pyautogui 中的任何内置延迟:

    # Any duration less than this is rounded to 0.0 to instantly move the mouse.
    pyautogui.MINIMUM_DURATION = 0  # Default: 0.1
    # Minimal number of seconds to sleep between mouse moves.
    pyautogui.MINIMUM_SLEEP = 0  # Default: 0.05
    # The number of seconds to pause after EVERY public function call.
    pyautogui.PAUSE = 0  # Default: 0.1
    

    P.S.:上面的示例不需要任何这些设置,因为它不使用 public moveTo 方法。

    【讨论】:

    • 删除了控制中的 Unicode“C”,并添加了更多目标点,并为其提供了最少量的内部点(非零等),效果很好!谢谢!
    • 修复了python2的非ascii问题。
    • 如何更改鼠标速度?该代码需要大约 20 秒来移动鼠标。更改持续时间没有任何效果。 for 循环迭代 1920 次。我怀疑每次迭代都会以 100 毫秒的持续时间移动鼠标,而不是“超时”中指定的量(要低得多:~0.0001 秒)。我该如何解决这个问题?
    • 在这里仍然可以正常工作。如果您使用公共pyautogui 方法移动鼠标,那么您需要移除公共函数调用之间的那些内置延迟。可能pyautogui 不是最好的工具。我使用它只是因为它被提出问题的人使用。
    • @DJV 你会推荐任何库吗?喜欢这个剧本。它一直运行良好 - 但一段时间后它似乎变慢了。
    【解决方案3】:

    你只需要知道move_mouse((300,300))会让你鼠标到达(300,300),然后永远不会改变。看看这个工具,它只是调用了WIN32 apimouse_event。阅读它,你会发现有没有“开始和停止”位置。我不知道如何绘制贝塞尔曲线。

        while True:
            pos = (random.randrange(*x_bound),random.randrange(*y_bound))
            move_mouse(pos)
            time.sleep(1.0/steps_per_second)
    

    看,这就是动画的秘密。你需要做的就是写一个pos = draw_bezier_curve(t)

    【讨论】:

    • 感谢您的提示。这也是我正在寻找的。 :) 如果有一个库或其他东西可以将所有贝塞尔运动记录到一个数组中,这将是完美的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多