How can I set a mouse scroll to zoom in / out on the image? [opencv-python]

1.5k views Asked by At

I have a code, which works well when I want to use mouse scroll to zoom in / zoom out on the image, but it does so ONLY towards the left-upper corner:

import cv2
import pyautogui

img_ = cv2.imread(r'path_to_file')

# Adjust the image to fit the screen
_, screen_height = pyautogui.size()
new_height = int(screen_height * 1.1)
new_width = int(new_height * img_.shape[1] / img_.shape[0])
img = cv2.resize(img_, (new_width, new_height))

def select_roi(event, x, y, flags, param):
    global img, new_height, new_width
    img_copy = img.copy()
    if event == cv2.EVENT_MOUSEWHEEL:
        if flags > 0:
            new_height = int(new_height * 1.1)
        else:
            new_height = int(new_height / 1.1)
        new_width = int(new_height * img_copy.shape[1] / img_copy.shape[0])
        img = cv2.resize(img_, (new_width, new_height))
        cv2.imshow('Selected area', img)

cv2.namedWindow('Selected area')
cv2.setMouseCallback('Selected area', select_roi)
cv2.imshow('Selected area', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

The best solution would be to be able to zoom the image in the place where the mouse cursor is currently on the image (this happens, for example, when we open any image on Windows and use the key combination 'ctrl' + ' mouse scroll').

However, a sufficient approach would be to have the 'Shift+Scroll' key combination to zoom towards the lower right corner of the image.

I need this solution because I want to select specific form fields in the image that I'm interested in, which are often too small without zooming in to capture. If any field is in the lower part of the image, then zooming only towards the upper left corner is insufficient.

1

There are 1 answers

1
kaerli On

I know I'm a little late, but this might help. I changed your code a little bit, but I think this is what you were looking for:

import cv2

base_img = cv2.imread(r"path_to_file")

img = base_img.copy()
zoom = 1
min_zoom = 1
max_zoom = 5


def select_roi(event, x, y, flags, param):
    global base_img, zoom, min_zoom, max_zoom
    if event == cv2.EVENT_MOUSEWHEEL:
        if flags > 0:
            zoom *= 1.1
            zoom = min(zoom, max_zoom)
        else:
            zoom /= 1.1
            zoom = max(zoom, min_zoom)

        img = base_img.copy()

        # Calculate zoomed-in image size
        new_width = round(img.shape[1] / zoom)
        new_height = round(img.shape[0] / zoom)

        # Calculate offset
        x_offset = round(x - (x / zoom))
        y_offset = round(y - (y / zoom))

        # Crop image
        img = img[
            y_offset : y_offset + new_height,
            x_offset : x_offset + new_width,
        ]

        # Stretch image to full size
        img = cv2.resize(img, (base_img.shape[1], base_img.shape[0]))
        cv2.imshow("Selected area", img)


cv2.namedWindow("Selected area")
cv2.setMouseCallback("Selected area", select_roi)
cv2.imshow("Selected area", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Because OpenCV handles keyboard and mouse events differently, I only used the mousewheel for scrolling.