import mmap
import ctypes
import win32event
import win32api
import cv2
import numpy as np
import win32con
import array
from math import pow, sqrt
import threading
import queue
title = 'KEK PEREKEK'
shared_memory_name = "Global\\OBSFRAME"
texture1_mutex_name = "Global\\OBSTEXTURE1_MUTEX"
texture2_mutex_name = "Global\\OBSTEXTURE2_MUTEX"
texture_ready_name = "Global\\OBSTEXTURE_READY"
META_INFO_SIZE = 1024
TEXTURE_SIZE = 45 * 1024 * 1024
TEXTURE_1_OFFSET = META_INFO_SIZE
TEXTURE_2_OFFSET = (TEXTURE_SIZE + TEXTURE_1_OFFSET)
SHARED_MEMORY_SIZE = (TEXTURE_2_OFFSET + TEXTURE_SIZE)
drawtask = queue.Queue(maxsize=2)
def show_window():
while True:
img = drawtask.get()
cv2.imshow(title, img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
def getdata(memory, offset, size, height, width):
return np.frombuffer(memory[offset:offset + size], np.uint8).reshape(height, width, 4)
def getmeta(memory):
return array.array('L', memory[0:16])
SQUARE_SIZE = 600
window_job = threading.Thread(target=show_window)
window_job.start()
# Dark Magenta
H_LOW = 139
S_LOW = 96
V_LOW = 129
# Light Magenta
H_HIGH = 169
S_HIGH = 225
V_HIGH = 225
magenta_dark = np.array([H_LOW, S_LOW, V_LOW])
magenta_light = np.array([H_HIGH, S_HIGH, V_HIGH])
TARGET_SIZE = 200
MAX_TARGET_DISTANCE = sqrt(2 * pow(TARGET_SIZE, 2))
def mouse_move(x, y):
win32api.mouse_event(win32con.MOUSEEVENTF_MOVE, x, y, 0, 0)
def is_activated():
return win32api.GetAsyncKeyState(0x14) != 0
frame_width = 1
frame_height = 1
def contour_distance(ct):
moment = cv2.moments(ct)
if moment["m00"] == 0:
return -1, None
cx = int(moment["m10"] / moment["m00"])
cy = int(moment["m01"] / moment["m00"])
mid = SQUARE_SIZE / 2
x = (mid - cx) if cx < mid else cx - mid
y = (mid - cy) if cy < mid else cy - mid
return [x, y]
def contour_filter(ct):
x, y = contour_distance(ct)
# Ensure that that the target is within the user defined max range
if x == -1 or x > TARGET_SIZE or y > TARGET_SIZE:
return False
# Attempt to filter out small contours
if cv2.contourArea(ct) < 1000:
return False
# Calculate the width and height of the contour
extreme_left = tuple(ct[ct[:, :, 0].argmin()][0])
extreme_right = tuple(ct[ct[:, :, 0].argmax()][0])
extreme_top = tuple(ct[ct[:, :, 1].argmin()][0])
extreme_bottom = tuple(ct[ct[:, :, 1].argmax()][0])
width = extreme_right[0] - extreme_left[0]
height = extreme_bottom[1] - extreme_top[1]
if width == 0 or height == 0:
return False
# Attempt to filter out wide objects
if abs(width / height) > 2.5:
return False
return True
def locate_target(frame, target):
# compute the center of the contour
moment = cv2.moments(target)
if moment["m00"] == 0:
return
cx = int(moment["m10"] / moment["m00"])
cy = int(moment["m01"] / moment["m00"])
mid = SQUARE_SIZE / 2
x = -(mid - cx) if cx < mid else cx - mid
y = -(mid - cy) if cy < mid else cy - mid
target_size = cv2.contourArea(target)
distance = sqrt(pow(x, 2) + pow(y, 2))
# There's definitely some sweet spot to be found here
# for the sensitivity in regards to the target's size
# and distance
slope = ((1.0 / 3.0) - 1.0) / (MAX_TARGET_DISTANCE / target_size)
multiplier = ((MAX_TARGET_DISTANCE - distance) / target_size) * slope + 1
if is_activated():
mouse_move(int(x * multiplier), int(y * multiplier))
if __debug__:
# draw the contour of the chosen target in green
cv2.drawContours(frame, [target], -1, (0, 255, 0), 2)
# draw a small white circle at their center of mass
cv2.circle(frame, (cx, cy), 7, (255, 255, 255), -1)
def process(frame):
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
magenta_color_range = cv2.inRange(hsv, magenta_dark, magenta_light)
res = cv2.bitwise_or(frame, frame, mask=magenta_color_range)
res = cv2.cvtColor(res, cv2.COLOR_RGB2GRAY)
# Extract magenta colors
thresh = cv2.adaptiveThreshold(res, 1, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 15, 1)
# Locate the objects with magenta outline
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Create a convex hull polygon around each extracted object
contours = map(lambda ct: cv2.convexHull(ct, False), contours)
# Sort the objects and extract the biggest
contours = sorted(contours, key=cv2.contourArea, reverse=True)
#if __debug__:
# Yellow contours are all contour matches, before filtering out
# cv2.drawContours(frame, contours, -1, (255, 255, 0), 1)
# Attempt to filter out extraneous contours, so that only characters exist
return list(filter(contour_filter, contours))
def main():
STANDARD_RIGHTS_REQUIRED = 0xF0000
SYNCHRONIZE = 0x100000
MUTANT_QUERY_STATE = 0x1
target_center = [0, 0]
diff = [0, 0]
target_center_frame_before = [0, 0]
sharedmemory = mmap.mmap(0, SHARED_MEMORY_SIZE, shared_memory_name, mmap.ACCESS_READ)
texture1_mutex = win32event.OpenMutex(SYNCHRONIZE, False, texture1_mutex_name)
texture2_mutex = win32event.OpenMutex(SYNCHRONIZE, False, texture2_mutex_name)
texture_ready_event = win32event.OpenEvent(SYNCHRONIZE, False, texture_ready_name)
while True:
if win32event.WAIT_OBJECT_0 == win32event.WaitForSingleObject(texture_ready_event, -1):
meta = getmeta(sharedmemory)
data = np.array([])
data_size = meta[0] * meta[1] * 4
height = meta[1]
width = meta[0]
if meta[3] == 1:
if win32event.WaitForSingleObject(texture1_mutex, 0) == win32event.WAIT_OBJECT_0:
# print('texture 1')
data = getdata(sharedmemory, TEXTURE_1_OFFSET, data_size, height, width)
win32event.ReleaseMutex(texture1_mutex)
elif win32event.WaitForSingleObject(texture2_mutex, 0) == win32event.WAIT_OBJECT_0:
# print('texture 2')
data = getdata(sharedmemory, TEXTURE_2_OFFSET, data_size, height, width)
win32event.ReleaseMutex(texture2_mutex)
else:
continue
elif meta[3] == 2:
if win32event.WaitForSingleObject(texture2_mutex, 0) == win32event.WAIT_OBJECT_0:
# print('texture 1')
data = getdata(sharedmemory, TEXTURE_2_OFFSET, data_size, height, width)
win32event.ReleaseMutex(texture2_mutex)
elif win32event.WaitForSingleObject(texture1_mutex, 0) == win32event.WAIT_OBJECT_0:
# print('texture 2')
data = getdata(sharedmemory, TEXTURE_1_OFFSET, data_size, height, width)
win32event.ReleaseMutex(texture1_mutex)
else:
continue
else:
continue
middle_y = int(height / 2)
mid_x = int(SQUARE_SIZE/2)
middle_x = int(width / 2)
mid_y = int(SQUARE_SIZE/2)
data = data[middle_y - mid_y : middle_y + mid_y, middle_x - mid_x : middle_x + mid_x]
frame = cv2.cvtColor(data, cv2.COLOR_RGBA2BGR)
contours = process(frame)
cv2.drawContours(frame, contours, -1, (255, 255, 0), 1)
if len(contours) > 1:
locate_target(frame, contours[1])
try:
drawtask.put_nowait(frame)
except:
pass
if __name__ == '__main__':
main()