Skip to content

Instantly share code, notes, and snippets.

@jerrylususu
Created April 16, 2023 08:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jerrylususu/937efba6f69f320bdecce140c7b00896 to your computer and use it in GitHub Desktop.
Save jerrylususu/937efba6f69f320bdecce140c7b00896 to your computer and use it in GitHub Desktop.
progress bar checker
# built with chatgpt
import pyautogui
import cv2 # opencv-python
import numpy as np
import time
from datetime import datetime, timedelta
# also need: pillow
# Define some constants
SELECT_AREA_WINDOW_TITLE = 'Select Area'
PROGRESS_BAR_WINDOW_TITLE = 'Progress Bar'
CAPTURE_INTERVAL_SEC = 1
# Define some variables
selected_area = [0,0,0,0]
last_captured_time = time.time()
previous_intervals = []
# Define a mouse callback function for selecting the area on the screen
def draw_rect(event, x, y, flags, params):
if event != cv2.EVENT_MOUSEMOVE:
print("draw rect call back!, event=", event,x,y)
global selected_area
if event == cv2.EVENT_LBUTTONDOWN:
selected_area[0] = x
selected_area[1] = y
elif event == cv2.EVENT_LBUTTONUP:
selected_area[2] = x - selected_area[0]
selected_area[3] = y - selected_area[1]
start_pt = (selected_area[0], selected_area[1])
end_pt = (x,y)
# start_pt[0], start_pt[1], end_pt[0] - start_pt[0], end_pt[1] - start_pt[1]
# selected_area = pyautogui.screenshot(region=(selected_area))
cv2.rectangle(params['img'], start_pt, end_pt, (0, 255, 0), 2)
cv2.imshow(SELECT_AREA_WINDOW_TITLE, params['img'])
cv2.setMouseCallback(SELECT_AREA_WINDOW_TITLE, lambda *args : None, None) # Disable mouse callback after selection
# Define a function to update the progress metric and overlay the result on the progress bar image
def update_progress_metric():
global selected_area, last_captured_time, previous_intervals
if selected_area is not None and time.time() - last_captured_time >= CAPTURE_INTERVAL_SEC:
# Capture the selected area and convert it to a NumPy array
screenshot = np.array(pyautogui.screenshot(region=(selected_area)))
# Convert the screenshot to grayscale
gray = cv2.cvtColor(screenshot, cv2.COLOR_RGB2GRAY)
# Threshold the image to separate the progress bar and the rest of the GUI
_, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)
# Find the contour of the progress bar
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
contour = max(contours, key=cv2.contourArea)
# Find the bounding box of the progress bar
x, y, w, h = cv2.boundingRect(contour)
# Find the edges of the progress bar using Canny edge detection
progress_bar_img = cv2.cvtColor(screenshot, cv2.COLOR_RGB2BGR)
progress_bar_img_crop = progress_bar_img[y+2:y+h-2, x+2:x+w-2] # Crop a little to avoid the edge of the progress bar
edges = cv2.Canny(progress_bar_img_crop, 40, 80)
# Find the position of the boundary between the done and to do parts
threshold = 1
boundary_x = None
try:
for i in range(x, x + w):
if edges[y + h // 2, i - x] != 0:
j = i
while j < x + w and edges[y + h // 2, j - x] != 0:
j += 1
if j - i >= threshold:
boundary_x = i
break
except IndexError:
print("index error")
if boundary_x is None:
boundary_x = x + w // 2
# Calculate the percentage finished and estimated remaining time
done_fraction = (boundary_x - x) / w
remaining_fraction = (w - (boundary_x - x)) / w
percentage_finished = round(done_fraction * 100,2)
progress_text = f'{percentage_finished}% finished'
print(progress_text)
if len(previous_intervals) == 0 or previous_intervals[-1][0] < percentage_finished:
previous_intervals.append((percentage_finished, time.time()))
if len(previous_intervals) > 20:
previous_intervals.pop(0)
avg_speed = (previous_intervals[-1][0] - previous_intervals[0][0]) / (previous_intervals[-1][1] - previous_intervals[0][1])
delta = timedelta(seconds=(100 - percentage_finished) / avg_speed)
eta = datetime.now() + delta
eta_text = f'ETA: {eta.strftime("%m/%d/%Y %H:%M:%S")} remaining: {delta}'
print(eta_text)
# last_captured_time = time.time()
# Capture a screenshot of the screen
screenshot = pyautogui.screenshot()
# Convert the screenshot to a NumPy array
img = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
# Create a window to display the screenshot and set the mouse callback function
cv2.namedWindow(SELECT_AREA_WINDOW_TITLE)
cv2.setMouseCallback(SELECT_AREA_WINDOW_TITLE, draw_rect, {'img': img})
# Display the screenshot and wait for the user to select an area or quit
cv2.imshow(SELECT_AREA_WINDOW_TITLE, img)
cv2.waitKey(0)
print("selection done", selected_area)
exit = False
if cv2.waitKey(1) == ord('q'):
exit = True
# # Main loop to select and update the progress bar
while not exit:
# Update the progress metric and overlay the result on the progress bar image
try:
update_progress_metric()
except Exception as e:
print("exception:", e)
time.sleep(CAPTURE_INTERVAL_SEC)
# Clean up the windows and exit
cv2.destroyAllWindows()
import tkinter as tk
from tkinter import ttk
class ProgressBar:
def __init__(self):
# Create the main window
self.window = tk.Tk()
self.window.title("Progress Bar")
# Create the progress bar and set its initial value
self.progress_bar = ttk.Progressbar(self.window, mode="determinate", length=300)
self.progress_bar.pack(pady=10)
self.progress_label = tk.Label(self.window, text="0%")
self.progress_label.pack()
self.progress = 0
self.max_progress = 100
# Start the progress bar
self.start()
# Start the GUI loop
self.window.mainloop()
def start(self):
# Update the progress bar every second
if self.progress < self.max_progress:
self.progress += 1
progress_percent = int(self.progress/self.max_progress * 100)
self.progress_bar["value"] = self.progress
self.progress_label.configure(text=f"{progress_percent}%")
self.window.after(1000, self.start)
# Close the progress bar when it reaches 100%
else:
self.window.destroy()
# Create an instance of the progress bar
pb = ProgressBar()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment