I wrote this code to capture screen footage by taking screenshots everything second, however the OpenCv window cascades the screen when it's clicked on.
When you hover over the Opencv window, it shows me the screen without a hundred duplicates. What is exactly the bug? Picture:
The code for using the class I made:
from window_capture import Window_Capture
from time import time
import cv2 as cv
import numpy
loop_time = time()
wincap = Window_Capture()
while True:
screenshot = wincap.screenshare()
cv.imshow('Screen', screenshot)
print("FPS {}".format(round(1 / (time() - loop_time))))
loop_time = time()
if cv.waitKey(1) == ord('q'):
print("Capture Ended")
cv.destroyWindow(screenshot)
The class for screen capturing:
import pyautogui
import numpy
import cv2 as cv
from time import time
from PIL import ImageGrab
import win32gui, win32ui, win32con
from win32api import GetSystemMetrics
import time
class Window_Capture:
w = 0
h = 0
hwnd = None
def __init__(self, window_name=None):
# checking is windowname exists
if window_name is None:
print("No window set to capture: Setting to active Window")
time.sleep(3)
self.hwnd = win32gui.GetDesktopWindow()
print(win32gui.GetWindowText(win32gui.GetDesktopWindow()))
else:
# self.hwnd = win32gui.FindWindow(None, window_name)
self.hwnd = win32gui.FindWindow(None, window_name)
print("Window Found: Setting to preferred Window")
# define monitor height and width and hwnd
self.w = GetSystemMetrics(0)
self.h = GetSystemMetrics(1)
def screenshare(self):
wDC = win32gui.GetWindowDC(self.hwnd)
dcObj = win32ui.CreateDCFromHandle(wDC)
cDC = dcObj.CreateCompatibleDC()
dataBitMap = win32ui.CreateBitmap()
dataBitMap.CreateCompatibleBitmap(dcObj, self.w, self.h)
cDC.SelectObject(dataBitMap)
cDC.BitBlt((0, 0), (self.w, self.h), dcObj, (0, 0), win32con.SRCCOPY)
signedIntsArray = dataBitMap.GetBitmapBits(True)
img = numpy.frombuffer(signedIntsArray, dtype='uint8')
img.shape = (self.h, self.w, 4)
dcObj.DeleteDC()
cDC.DeleteDC()
win32gui.ReleaseDC(self.hwnd, wDC)
win32gui.DeleteObject(dataBitMap.GetHandle())
img = img[..., :3]
img = numpy.ascontiguousarray(img)
return img
This bug is preventing me from moving onto the next part my image detection project.
Better solution is :
import time
import cv2
import numpy as np
from mss import mss
#import pyautogui
#width, height= pyautogui.size()
width=900
height=900
mon = {'top': 0, 'left': 0, 'width': width, 'height': height}
with mss() as sct:
# mon = sct.monitors[0]
while True:
last_time = time.time()
img = sct.grab(mon)
print('fps: {0}'.format(1 / (time.time()-last_time)))
cv2.imshow('test', np.array(img))
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
Note:
When you hover then you won't be seeing many windows beacuse you see the complete window without the opencv window opended and else you see many of them
you see a cascade because you take a screenshot of the window itself, repeatedly.
it's like standing between two mirrors.
Related
So i have been trying to use this code to get a screenshot from a window, with this screenshot i will use opencv to match template, but every time that i try to match template i always get the same error, i have tried with a few other things like image grab from pillow, pyautogui and i am now trying with windowsAPI. i will say in advance this code is not mine.
Can anyone help me with this?
the error:
test = cv.matchTemplate(screenshot, target, cv.TM_CCORR_NORMED)
cv2.error: OpenCV(4.6.0) :-1: error: (-5:Bad argument) in function 'matchTemplate'
> Overload resolution failed:
> - templ is not a numpy array, neither a scalar
> - Expected Ptr<cv::UMat> for argument 'templ'
the source code:
import cv2 as cv
import numpy as np
import pyautogui
from time import time
import win32gui, win32ui, win32con
from PIL import ImageGrab
game = 'LOST ARK (64-bit, DX9) v.2.5.3.1'
target = 'box.png'
def list_window_names():
def winEnumHandler(hwnd, ctx):
if win32gui.IsWindowVisible(hwnd):
print(hex(hwnd), win32gui.GetWindowText(hwnd))
win32gui.EnumWindows(winEnumHandler, None)
def windowcapture():
hwnd = win32gui.FindWindow(None, game)
rect = win32gui.GetWindowRect(hwnd)
w = rect[2] - rect[0]
h = rect[3] - rect[1]
#hwnd = win32gui.FindWindow(None, windowname)
wDc = win32gui.GetWindowDC(hwnd)
dcObj = win32ui.CreateDCFromHandle(wDc)
cDC = dcObj.CreateCompatibleDC()
dataBitMap = win32ui.CreateBitmap()
dataBitMap.CreateCompatibleBitmap(dcObj, w, h)
cDC.SelectObject(dataBitMap)
cDC.BitBlt((0, 0), (w, h), dcObj, (0, 0), win32con.SRCCOPY)
dataBitMap.SaveBitmapFile(cDC, 'debug.bmp')
signedIntsArray = dataBitMap.GetBitmapBits(True)
img = np.fromstring(signedIntsArray, dtype='uint8')
img.shape = (h, w, 4)
dcObj.DeleteDC()
cDC.DeleteDC()
win32gui.ReleaseDC(hwnd, wDc)
win32gui.DeleteObject(dataBitMap.GetHandle())
return img
list_window_names()
loop_time = time()
while True:
#screenshot = ImageGrab.grab(bbox = (w,h,x,y))
#screenshot = pyautogui.screenshot()
#screenshot = np.array(screenshot)
#screenshot = cv.cvtColor(screenshot, cv.COLOR_RGB2BGR)
#print('top:{} , left:{}, w:{} ,h: {}'.format(w,h,x,y))
#screenshot.show()
#screenshot = np.array(screenshot)
#screenshot = screenshot[:, :, ::-1].copy()
#screenshot = screenshot[..., :3].copy()
screenshot = windowcapture()
cv.imshow("computer vision",screenshot)
method = cv.TM_CCORR
result = cv.matchTemplate(screenshot, target, method)
# debug the loop rate
print('FPS {}'.format(1 / (time() - loop_time)))
loop_time = time()
if cv.waitKey(1) == ord('q'):
cv.destroyAllWindows()
break
print('Done.')
I'm working on a Object Detection project for the game Cuphead using OpenCV and Python. Now I'm trying to capture objects in real time but when the detection window displays I get this rare black bar on the top and I don't know how to get rid of it, here's what I see, on the left my object detection window and in the right the Cuphead game window.
Here's the code for the class used for this:
import numpy as np
import win32gui, win32ui, win32con
class WindowCapture:
# define monitor's width and height
w = 0
h = 0
hwnd = None
# constructor
def __init__(self, window_name):
if window_name is None: # if we don't pass any window names capture desktop
self.hwnd = win32gui.GetDesktopWindow()
else:
# Find the game window
self.hwnd = win32gui.FindWindow(None, window_name)
if not self.hwnd:
raise Exception("Window not founnd: {}".format(window_name))
# define window's widht and height. the resolution we'll work with
window_rect = win32gui.GetWindowRect(self.hwnd)
self.w = window_rect[2] - window_rect[0]
self.h = window_rect[3] - window_rect[1]
def get_screenshot(self):
# get the window image data
wDC = win32gui.GetWindowDC(self.hwnd)
dcObj = win32ui.CreateDCFromHandle(wDC)
cDC = dcObj.CreateCompatibleDC()
dataBitMap = win32ui.CreateBitmap()
dataBitMap.CreateCompatibleBitmap(dcObj, self.w, self.h)
cDC.SelectObject(dataBitMap)
cDC.BitBlt((0,0), (self.w, self.h), dcObj, (0,0), win32con.SRCCOPY)
# create the screenshot image that we want to return to be processed
signedIntsArray = dataBitMap.GetBitmapBits(True)
img = np.fromstring(signedIntsArray, dtype='uint8')
img.shape = (self.h, self.w, 4)
# Free Resources
dcObj.DeleteDC()
cDC.DeleteDC()
win32gui.ReleaseDC(self.hwnd, wDC)
win32gui.DeleteObject(dataBitMap.GetHandle())
# get rid of the alpha channel in the img
img = img[..., :3]
img = np.ascontiguousarray(img)
return img
It seems img.shape = (self.h, self.w, 4) causes the problem. As GetWindowRect and #IInspectable said,
In Windows Vista and later, the Window Rect now includes the area
occupied by the drop shadow.
I need to make a screen capture of a specific application. If I grab the Windows desktop (hwnd = None), everything works, but I get a black screen when I try to grab the screen of a specific application, e.g. hwnd = win32gui.FindWindow(None, 'Albion Online Client').
import cv2 as cv
import numpy as np
import os
from time import time
import win32gui
import win32ui
import win32con
os.chdir(os.path.dirname(os.path.abspath(__file__)))
def window_capture():
w = 1920 # set this
h = 1080 # set this
#hwnd = None ### Everything works
hwnd = win32gui.FindWindow(None, 'Albion Online Client') ### Black Screen
wDC = win32gui.GetWindowDC(hwnd)
dcObj = win32ui.CreateDCFromHandle(wDC)
cDC = dcObj.CreateCompatibleDC()
dataBitMap = win32ui.CreateBitmap()
dataBitMap.CreateCompatibleBitmap(dcObj, w, h)
cDC.SelectObject(dataBitMap)
cDC.BitBlt((0, 0), (w, h), dcObj, (0, 0), win32con.SRCCOPY)
#Save screenshoot
#dataBitMap.SaveBitmapFile(cDC, 'debug.bmp' )
signedIntsArray = dataBitMap.GetBitmapBits(True)
img = np.fromstring(signedIntsArray, dtype='uint8')
img.shape = (h, w, 4)
# Free Resources
dcObj.DeleteDC()
cDC.DeleteDC()
win32gui.ReleaseDC(hwnd, wDC)
win32gui.DeleteObject(dataBitMap.GetHandle())
img = img[..., :3]
img = np.ascontiguousarray(img)
return img
# initialize the WindowCapture clas
loop_time = time()
while(True):
screenshot = window_capture()
cv.imshow('Computer Vision', screenshot)
# debug the loop rate
print('FPS {}'.format(1 / (time() - loop_time)))
loop_time = time()
# press 'q' with the output window focused to exit.
# waits 1 ms every loop to process key presses
if cv.waitKey(1) == ord('q'):
cv.destroyAllWindows()
break
print('Done.')
That's an OpenGL or Direct3D application. It doesn't draw to its own window. It creates textures and surfaces, and has the graphics card render its display list directly into the frame buffer.
When I try to capture a video screenshot of my screen in a region suddenly the .avi output file becomes a 7kb.
The is no error, so I do not know how to fix this
The output video is fine before selecting the region.
how can i fix this problem?
import cv2
import numpy as np
import pyautogui
# display screen resolution, get it from your OS settings
import tkinter as tk
from PIL.Image import Image
root = tk.Tk()
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
SCREEN_SIZE = (screen_width, screen_height)
fourcc = cv2.VideoWriter_fourcc(*"XVID")
# create the video write object
out = cv2.VideoWriter("output.avi", fourcc, 20.0, (SCREEN_SIZE))
while True:
# make a screenshot
img = pyautogui.screenshot(region=(350, 800, 500, 150))
# convert these pixels to a proper numpy array to work with OpenCV
frame = np.array(img)
# convert colors from BGR to RGB
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# write the frame
out.write(frame)
# show the frame
cv2.imshow("screenshot", frame)
# if the user clicks q, it exits
if cv2.waitKey(1) == ord("q"):
break
# make sure everything is closed when exited
cv2.destroyAllWindows()
out.release()
I am trying to take a video stream, from a web camera and detect circles in it using HoughCircles(). But when ever I try to run the code the video takes along time to load the image, or wont load the image at all. Any help on how to get the code to do circle detection would be greatly appreciated.
Note: I'm not trying to do anything real time. I just want to get some basic circle detection to work on a video stream from my web camera.
Here's the code:
import cv2
import numpy as np
import sys
cap = cv2.VideoCapture(0)
width = 320
height = 240
dim = (width, height)
while(True):
gray = cv2.medianBlur(cv2.cvtColor(cap.read()[1], cv2.COLOR_BGR2GRAY),5)
resized = cv2.resize(gray,dim,interpolation = cv2.INTER_AREA)
edges = cv2.Canny(gray,100,200)
circ = cv2.HoughCircles(resized,cv2.HOUGH_GRADIENT,1,30,param1=50,param2=75,
minRadius=0,maxRadius=0)
cv2.imshow('video',resized)
if circ is not None:
circ = np.uint16(np.around(circ))[0,:]
print(circ)
for j in circ:
cv2.circle(resized, (j[0], j[1]), j[2], (0, 255, 0), 2)
cv2.imshow('video',resized)
if cv2.waitKey(1)==27:# esc Key
break
cap.release()
cv2.destroyAllWindows()
Again thanks for any help.
OK I've Figured it out. I had to reduce mess around with the parameters in HoughCircles. I've changed
circ = cv2.HoughCircles(resized,cv2.HOUGH_GRADIENT,1,30,param1=50,param2=75, minRadius=0,maxRadius=0)
to
cv2.HoughCircles(resized,cv2.HOUGH_GRADIENT,1,50,param1=50,param2=35, minRadius=0,maxRadius=0)
This allows the code to display the video stream while detecting circles at a reasonable frame rate. Also thanks #ZdaR for the help.
Here's the code that works
import cv2
import numpy as np
import serial
cap = cv2.VideoCapture(1)
width = 320
height = 240
dim = (width, height)
while(True):
gray = cv2.medianBlur(cv2.cvtColor(cap.read()[1], cv2.COLOR_BGR2GRAY),5)
resized = cv2.resize(gray,dim,interpolation = cv2.INTER_AREA)
circ = cv2.HoughCircles(resized,cv2.HOUGH_GRADIENT,1,50,param1=50,param2=35,
minRadius=0,maxRadius=0)
cv2.imshow('video',resized)
if circ is not None:
circ = np.uint16(np.around(circ))[0,:]
print(circ)
for j in circ:
cv2.circle(resized, (j[0], j[1]), j[2], (0, 255, 0), 2)
cv2.imshow('video',resized)
if cv2.waitKey(1)==27:# esc Key
break
cap.release()
cv2.destroyAllWindows()