Win32ui error createcompatibledc failed

I'm trying to capture sceen using win32 for opencv but when i start it gives me an error about the CreateCompatibleDC function. That's the first time i touch this library so i don't really know how...

I’m trying to capture sceen using win32 for opencv but when i start it gives me an error about the CreateCompatibleDC function.

That’s the first time i touch this library so i don’t really know how to fix this.

import numpy as np
import win32gui,win32ui,win32con


class WindowCapture:

    # properties
    w = 0
    h = 0
    hwnd = None
    cropped_x = 0
    cropped_y = 0
    offset_x = 0
    offset_y = 0

    # constructor
    def __init__(self, window_name):
        # find the handle for the window we want to capture
        self.hwnd = win32gui.FindWindow(None, window_name)
        if not self.hwnd:
            raise Exception('Window not found: {}'.format(window_name))

        # get the window size
        window_rect = win32gui.GetWindowRect(self.hwnd)
        self.w = window_rect[2] - window_rect[0]
        self.h = window_rect[3] - window_rect[1]

        # account for the window border and titlebar and cut them off
        border_pixels = 8
        titlebar_pixels = 30
        self.w = self.w - (border_pixels * 2)
        self.h = self.h - titlebar_pixels - border_pixels
        self.cropped_x = border_pixels
        self.cropped_y = titlebar_pixels

        # set the cropped coordinates offset so we can translate screenshot
        # images into actual screen positions
        self.offset_x = window_rect[0] + self.cropped_x
        self.offset_y = window_rect[1] + self.cropped_y

    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, (self.cropped_x, self.cropped_y), win32con.SRCCOPY)

        # convert the raw data into a format opencv can read
        #dataBitMap.SaveBitmapFile(cDC, 'debug.bmp')
        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())

        # drop the alpha channel, or cv.matchTemplate() will throw an error like:
        #   error: (-215:Assertion failed) (depth == CV_8U || depth == CV_32F) && type == _templ.type() 
        #   && _img.dims() <= 2 in function 'cv::matchTemplate'
        img = img[...,:3]

        # make image C_CONTIGUOUS to avoid errors that look like:
        #   File ... in draw_rectangles
        #   TypeError: an integer is required (got type tuple)
        # see the discussion here:
        # https://github.com/opencv/opencv/issues/14866#issuecomment-580207109
        img = np.ascontiguousarray(img)

        return img

    # find the name of the window you're interested in.
    # once you have it, update window_capture()
    # https://stackoverflow.com/questions/55547940/how-to-get-a-list-of-the-name-of-every-open-window
    def list_window_names(self):
        def winEnumHandler(hwnd, ctx):
            if win32gui.IsWindowVisible(hwnd):
                print(hex(hwnd), win32gui.GetWindowText(hwnd))
        win32gui.EnumWindows(winEnumHandler, None)

    # translate a pixel position on a screenshot image to a pixel position on the screen.
    # pos = (x, y)
    # WARNING: if you move the window being captured after execution is started, this will
    # return incorrect coordinates, because the window position is only calculated in
    # the __init__ constructor.
    def get_screen_position(self, pos):
        return (pos[0] + self.offset_x, pos[1] + self.offset_y)

That’s what i wrote, referring to Learn Code By Gaming video

But when start, here’s the error:

File "C:Xwindowcapture.py", line 49, in get_screenshot
        dataBitMap.CreateCompatibleBitmap(dcObj, self.w, self.h)
    win32ui.error: CreateCompatibleDC failed

I think the same error as this thread; Python win32ui.error: CreateCompatibleDC failed

It’s been a few months since I took a look at this code because I couldn’t get past this error.

I’m using source_needle_images as the artefacts I’m trying to find, and haystack as the image I’m trying to find them in. My needles are currently two jpg’s however, in future, this may be dozens of jpg’s and my haystack is an application window named wincap

The eventual intention is to «do something» if anything whatsoever from source_needle_images is found within the application window.

This code is from my main.py, and I’m using two functions search and windowcapture

windowcapture captures the application window, search performs the OCR.

from windowcapture import WindowCapture
from search import Search
    
# the window to capture 
wincap = WindowCapture('P')

# load needle images and start the matching process 
source_needle_images = glob.glob(r'C:\\\*.jpg')
search = Search(source_needle_images)

loop_time = time()
while(True):

    # get an updated image of the background
    haystack_img = wincap.get_screenshot()

    # display the processed image
    points = search.find(haystack_img, 0.85, 'rectangles')
   

This is the section of code causing issue;

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, (self.cropped_x, self.cropped_y), win32con.SRCCOPY)

        # convert the raw data into a format opencv can read
        #dataBitMap.SaveBitmapFile(cDC, 'debug.bmp')
        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())

and this is the error in question;

Traceback (most recent call last):
  File "c:\\\main.py", line 23, in <module>
    haystack_img = wincap.get_screenshot()
  File "c:\\\windowcapture.py", line 52, in get_screenshot
    dataBitMap.CreateCompatibleBitmap(dcObj, self.w, self.h)
win32ui.error: CreateCompatibleDC failed

Updated with requested code:

   # constructor
    def __init__(self, window_name=None):
        # find the handle for the window we want to capture.
        # if no window name is given, capture the entire screen
        if window_name is None:
            self.hwnd = win32gui.GetDesktopWindow()
        else:
            self.hwnd = win32gui.FindWindow(None, window_name)
            if not self.hwnd:
                raise Exception('Window not found: {}'.format(window_name))

#python #memory-leaks #pywin32 #win32gui #win32-process

Вопрос:

Я загружаю окно opencv в цикле с помощью этой конкретной процедуры захвата экрана окна ниже.

ПРОБЛЕМА: после сотен циклов в цикле он внезапно выходит из строя в любой из двух ТОЧЕК СБОЯ, отмеченных ниже в коде.

Я подозреваю возможную утечку памяти, но, если я не ошибаюсь, я удаляю и освобождаю то, что требуется, а также (повторно)выбираю объект, прежде чем удалить его.

(Причина, по которой я использую этот метод, заключается в том, что для меня важно иметь возможность захватить конкретное окно, даже если оно неактивно и находится в фоновом режиме, и я не обнаружил, что какой-либо другой модуль/метод действительно работает.)

Что я упускаю из виду?

 import win32gui
import win32ui
from PIL import Image
import numpy as np
import cv2

while True:

        target_window = win32gui.FindWindow(None, ("Analytics dashboard - Google Chrome"))       
        
        hwndDC = win32gui.GetWindowDC(target_window) 
        mfcDC  = win32ui.CreateDCFromHandle(hwndDC)  

        saveDC = mfcDC.CreateCompatibleDC()  #### <-- RANDOM FAIL POINT 1: win32ui.error: CreateCompatibleDC failed
                
        saveBitMap = win32ui.CreateBitmap()
        saveBitMap.CreateCompatibleBitmap(mfcDC, screen_width, screen_height)
        saveDC.SelectObject(saveBitMap)    
        result = windll.user32.PrintWindow(target_window, saveDC.GetSafeHdc(), 3)
        bmpinfo = saveBitMap.GetInfo()
        bmpstr = saveBitMap.GetBitmapBits(True)
        
        screen_image = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpstr, 'raw', 'BGRX', 0, 1)        

        mfcDC.DeleteDC()  #### <-- RANDOM FAIL POINT 2: win32ui.error: DeleteDC failed

        saveDC.DeleteDC()               
        win32gui.DeleteObject(saveBitMap.GetHandle())        
        win32gui.ReleaseDC(target_window, hwndDC) 

        image = cv2.cvtColor(np.array(screen_image), cv2.IMREAD_ANYCOLOR)
 

Комментарии:

1. Убедитесь target_window , что это не 0 так . Перейдите в диспетчер задач и следите за «использованием GDI» (по умолчанию он не отображается, вам нужно перейти в раздел «Сведения» и выбрать GDI. Посмотрите, увеличиваются ли объекты GDI. Это проблема, если она превышает 1000 или 2000 дескрипторов.

2. @Barmak Shemirani : спасибо за ваш быстрый ответ! Проверено, target_window никогда не равен 0, всегда правильно его получает., также при сбое. Я также проверил объекты GDI и действительно увеличил, как вы указали, запустив приведенный выше код. Вопрос, почему, так как, на мой взгляд, я удаляю, освобождаю и выбираю объект правильно. Могу я спросить, не могли бы вы взять код и любезно протестировать его рядом с собой, чтобы убедиться, что вы можете обнаружить проблему ?

3. У меня нет windll cv2 расширения и, я прокомментировал их и запустил ваш код, не смог увидеть утечку GDI. Это не превышает 3. Возможно, у вас есть утечки GDI в другом месте.

4. @Barmak Shemirani : ЕЩЕ раз большое спасибо за ваш ответ. Следуя вашему комментарию, я тоже провел дополнительный тест на своей стороне, и я могу подтвердить, что CreateCompatibleDC или DeleteDC завершаются неудачей ТОЛЬКО при добавлении строки PrintWindow. Итак, нет, мы могли бы сузить проблему до окна печати. Я пытался найти здесь какое-либо решение, но ничего не смог найти. Могу я спросить, есть ли у вас какие-либо идеи, как это решить ?

Ответ №1:

Я попробовал использовать приведенный выше код, ctypes.windll.user32.PrintWindow и утечек GDI не было. PrintWindow третьим аргументом должно быть PW_CLIENTONLY (1), или есть вариант без документов PW_RENDERFULLCONTENT (2). Недокументированный код ненадежен. Я не знаю, к чему относится константа (3).

Если Chrome является верхним окном, вам следует просто сделать снимок экрана рабочего стола. Это было бы совместимо.

Это может помочь, если вы удалите часть кода вне цикла, по крайней мере, это будет более эффективно.

 import ctypes
import win32gui 
import win32ui
import win32con
from PIL import Image

hdesktop = win32gui.GetDesktopWindow()
(l, r, width, height) = win32gui.GetClientRect(hdesktop)
hdc = win32gui.GetWindowDC(hdesktop)
dc  = win32ui.CreateDCFromHandle(hdc)
memdc = dc.CreateCompatibleDC()
bitmap = win32ui.CreateBitmap()
bitmap.CreateCompatibleBitmap(dc, width, height)
memdc.SelectObject(bitmap)

while True:
    hwnd = win32gui.FindWindow("Chrome_WidgetWin_1", None)
    if hwnd == 0:
        break
    result = ctypes.windll.user32.PrintWindow(hwnd, memdc.GetSafeHdc(), 2)
    if result == 1:
        bytes = bitmap.GetBitmapBits(True)
        img = Image.frombuffer('RGB', (width, height), bytes, 'raw', 'BGRX', 0, 1)
        img.save("file.bmp")
    #break
    
dc.DeleteDC()
memdc.DeleteDC()
win32gui.DeleteObject(bitmap.GetHandle())
win32gui.ReleaseDC(hwnd, hdc)
 

Вы также можете добавить ctypes.windll.shcore.SetProcessDpiAwareness(2) сверху

Комментарии:

1. Большое вам спасибо, что уделили мне время. Я полностью понимаю ваши предложения, но, к сожалению, это приводит к черному экрану. Ранее я тоже столкнулся с этой проблемой с моим кодом, поэтому я использовал только целевое окно hwnd, не получая сначала рабочий стол, а также 3-ю константу, которую вы упомянули, ДОЛЖНО быть 3 (хотя я не знаю, почему), иначе по какой-то причине она всегда дает черный экран. Тем не менее, я стараюсь принять предложенные вами изменения и вернуться к вам с результатом.

2. Chrome иногда реагирует на PW_RENDERFULLCONTENT ( 2 ), иногда нет. Я думаю , что если вы поставите 3 или 3000000 , код изменит его на 2 . Другая программа может изменить его 0 или вернуть значение false. Не существует стандарта для обработки недокументированных констант.

3. Это заняло некоторое время, но я рад подтвердить, что ваше предложение вывести из цикла большую часть кода сработало как нельзя лучше ! БОЛЬШОЕ спасибо вам за ваше время и помощь!! Я принял ответ и тоже проголосовал.

Recommend Projects

  • React photo

    React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo

    Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo

    Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo

    TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo

    Django

    The Web framework for perfectionists with deadlines.

  • Laravel photo

    Laravel

    A PHP framework for web artisans

  • D3 photo

    D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Visualization

    Some thing interesting about visualization, use data art

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo

    Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo

    Microsoft

    Open source projects and samples from Microsoft.

  • Google photo

    Google

    Google ❤️ Open Source for everyone.

  • Alibaba photo

    Alibaba

    Alibaba Open Source for everyone

  • D3 photo

    D3

    Data-Driven Documents codes.

  • Tencent photo

    Tencent

    China tencent open source team.

hey there, I’m having difficulty figuring out how to get my template to match the game recording for my code. This is the test code that I’m trying to run, and it just doesn’t seem to work. I do realize I haven’t run the exact code that you put on your videos, but that is because I can’t seem to get it to window/video capture for the game I’m playing, (which is a little frustrating).
Nevertheless, it works for still image and it works fine videocapturing when I don’t try to matchTemplate but the two don’t seem to want to merge.

import numpy as np
from PIL import ImageGrab
import cv2
import time
import threading

def screen_record(): 
     last_time = time.time()
     while(True):
         # 800x600 windowed mode for GTA 5, at the top left position of your main screen.
         # 40 px accounts for title bar. 
         printscreen = np.array(ImageGrab.grab(bbox=(0,40,800,640)))
         print('loop took {} seconds'.format(time.time()-last_time))
         last_time = time.time()
         img_gray = cv2.imshow('window',cv2.cvtColor(printscreen, cv2.COLOR_BGR2GRAY))
         if cv2.waitKey(25) & 0xFF == ord('q'):
             cv2.destroyAllWindows()
             break

    eyes_hungry = cv2.imshow('hungry2.jpg',0)
    last_time = time.time()
    res = cv2.matchTemplate(img_gray, eyes_hungry, cv2.TM_CCOEFF_NORMED)       
    threshhold = 0.8
    loc = np.where(res >= threshhold)
    for pt in zip(*loc[::-1]):
        w, h = template.shape[::-1]
        cv2.rectangle(img_gray, pt, (pt[0]+w, pt[1]+h), (0,255,255), 1)


screen_record()

this is the error or a variation on the same error I get when I try running it:

  F:DesktopNeneat-python>grabscreen.py                                                    
loop took 0.0657804012298584 seconds                                                       
Traceback (most recent call last):                                                         
  File "F:DesktopNeneat-pythongrabscreen.py", line 29, in <module>                     
    screen_record()                                                                        
  File "F:DesktopNeneat-pythongrabscreen.py", line 22, in screen_record                
    res = cv2.matchTemplate(img_gray, eyes_hungry, cv2.TM_CCOEFF_NORMED)                   
cv2.error: OpenCV(4.5.3) C:UsersrunneradminAppDataLocalTemppip-req-build-sn_xpupmopencvmodulesimgprocsrctemplmatch.cpp:588: error: (-215:Assertion failed) corr.rows <= img.rows + templ.rows - 1 && corr.cols <= img.cols + templ.cols - 1 in function 'cv::crossCorr'

if you or anyone might be able to help, I’d really appreciate it, I’ve been banging my head on the wall for a few days now.

Thank you for reading.

Понравилась статья? Поделить с друзьями:
  • Win32kbase sys ошибка синий экран
  • Win32kbase sys windows 10 как исправить ошибку
  • Win32full sys ошибка
  • Win32diskimager error 1117
  • Win32bridge server exe параметр задан неверно ошибка