0

I have two co-ordinates stored in my variable points : [(100, 50)] I'm trying to move my mouse with pyautogui.moveTo(points) and I get the error:

pyautogui.PyAutoGUIException: The supplied sequence must have exactly 2 or exactly 4 elements (0 were received).

I assume this means I'm passing a single list object rather than the coordinates.

What does the expression [(100, 50)] mean and how I can I transform x and y into two elements.

The source code where I'm getting points from:

import cv2 as cv
import numpy as np

class Vision:

# properties
needle_img = None
needle_w = 0
needle_h = 0
method = None

# constructor
def __init__(self, needle_img_path, method=cv.TM_CCOEFF_NORMED):
    self.needle_img = cv.imread(needle_img_path, cv.IMREAD_UNCHANGED)

    # Save the dimensions of the needle image
    self.needle_w = self.needle_img.shape[1]
    self.needle_h = self.needle_img.shape[0]

    self.method = method

def find(self, haystack_img, threshold=0.5, debug_mode=None):
    # run the OpenCV algorithm
    result = cv.matchTemplate(haystack_img, self.needle_img, self.method)
    # Get the all the positions from the match result that exceed our threshold
    locations = np.where(result >= threshold)
    locations = list(zip(*locations[::-1]))

    for loc in locations:
        rect = [int(loc[0]), int(loc[1]), self.needle_w, self.needle_h]
        # Add every box to the list twice in order to retain single (non-overlapping) boxes
        rectangles.append(rect)
        rectangles.append(rect)
    # Apply group rectangles
    rectangles, weights = cv.groupRectangles(rectangles, groupThreshold=1, eps=0.5)

    points = []
    if len(rectangles):

        line_color = (0, 255, 0)
        line_type = cv.LINE_4
        marker_color = (255, 0, 255)
        marker_type = cv.MARKER_CROSS

        # Loop over all the rectangles
        for (x, y, w, h) in rectangles:

            # Determine the center position
            center_x = x + int(w/2)
            center_y = y + int(h/2)
            # Save the points
            points.append((center_x, center_y))

            if debug_mode == 'rectangles':
                # Determine the box position
                top_left = (x, y)
                bottom_right = (x + w, y + h)
                # Draw the box
                cv.rectangle(haystack_img, top_left, bottom_right, color=line_color, 
                            lineType=line_type, thickness=2)
            elif debug_mode == 'points':
                # Draw the center point
                cv.drawMarker(haystack_img, (center_x, center_y), 
                            color=marker_color, markerType=marker_type, 
                            markerSize=40, thickness=2)

    if debug_mode:
        cv.imshow('Matches', haystack_img)

    return points
  • 1
    "I understand [ ] are used for things like lists or mutable data liable to change and ( ) are used for functions or tuples, things that don't change." Not really, the mutability is not really relevant – juanpa.arrivillaga Nov 04 '21 at 15:27
  • Please include your source code in the question - thanks. – Michael Tracy Nov 04 '21 at 15:28
  • 2
    In any case, in this context, `[(100, 50)]` is a list with a tuple in it... This is a sequence (a list) with a *single element*, the pair `(100, 50)` (which as a tuple, is itself a sequence) – juanpa.arrivillaga Nov 04 '21 at 15:30
  • *"I'm trying to move my mouse with pyautogui.moveTo(points) and I get the error"* - is your question about this error when using `pyautogui`, or is it about the meaning of the syntax `[(100, 50)]`? Please focus your question on one specific thing you want an answer to; if it's about the meaning of `[(100, 50)]` then your actual question has nothing to do with `pyautogui` and your mentioning about this error only confuses matters. – kaya3 Nov 04 '21 at 15:32
  • Apologies, it was both. I was wanting to understand what the brackets meant to help me answer the question I'm struggling with. –  Nov 04 '21 at 15:44

1 Answers1

0

What does the expression [(100, 50)] mean and how I can I transform x and y into two elements.

[...] creates a list containing whatever you put inside it. (100, 50) creates a tuple containing the integers 100 and 50. So you have a list that contains a tuple that contains two numbers.

I assume this means I'm passing a single list object rather than the coordinates.

You're right, kinda. The problem isn't that you're passing a single list object, you need to pass a single listor rather, sequence object. The problem is that that list object contains only one element: the tuple.

You can check this by looking at the len of the list:

>>> l = [(100, 50)]
>>> len(l)
1

The way you intend to use it, pyautogui.moveTo(points) wants a sequence (a list or a tuple) that contains two elements. These elements are the coordinates of the point you want to move to.

The tuple that is inside the list is this two-element sequence, so that's what you need to pass:

pyautogui.moveTo(points[0])
Pranav Hosangadi
  • 23,755
  • 7
  • 44
  • 70
  • 1
    Thanks @Pranav for the explanation that all makes sense and I'll remember the `len` trick. That's giving me the error `IndexError: list index out of range` whenever it can't find something and crashes the script but I think that's another question/something for me to look into! –  Nov 04 '21 at 17:04
  • @L23P the indexerror happens when you try to access an index that doesn't exist, In this case, because the list is empty. Checking if the list is empty is pretty straightforward, because empty sequences are falsey in python, so you can just do `if points: moveTo(points[0])` – Pranav Hosangadi Nov 04 '21 at 17:56
  • Lol! I just put up a post about it because I tried that slightly differently! If you want there is another correct answer to be claimed here: https://stackoverflow.com/questions/69843672/python-opencv-how-do-i-click-on-a-detected-object as that's working perfectly thank you! –  Nov 04 '21 at 18:00
  • 1
    I voted to close that one because it's been answered already :) An empty list is not `None`, but it is falsey, so `points != None` wouldn't work for `points = []` @L23P – Pranav Hosangadi Nov 04 '21 at 18:02