2014-04-08 11 views
0

내 화면에서 패턴 인식을하고 Quartz/PyObjc 라이브러리를 사용하여 스크린 샷을 가져옵니다.CGImage를 파이썬 이미지로 변환 (pil/opencv)

나는 스크린 샷을 CGImage로 얻습니다. openCV 라이브러리를 사용하여 패턴을 검색하려고하지만 opencv가 읽을 수 있도록 데이터를 변환하는 방법을 찾지 못하는 것 같습니다.

는 그래서 내가하고 싶은 것은 이것이다 :

#get screenshot and reference pattern 
img = getScreenshot() # returns CGImage instance, custom function, using Quartz 
reference = cv2.imread('ref/reference_start.png') #get the reference pattern 

#search for the pattern using the opencv library 
result = cv2.matchTemplate(screen, reference, cv2.TM_CCOEFF_NORMED) 

#this is what I need 
minVal,maxVal,minLoc,maxLoc = cv2.minMaxLoc(result) 

내가 어떻게이 일을 아무 생각이없고 구글을 통해 정보를 찾을 수 없습니다.

답변

0

다음은 스크린 샷을 찍어 파일로 저장하는 코드입니다. 이를 PIL로 읽으려면 표준 Image(path)을 사용하십시오. 이 코드는 지역 크기를 작게 유지하면 놀라 울 정도로 빠릅니다. 800x800 픽셀 영역의 경우 각 i1에서 i1이 50ms 미만입니다. 듀얼 모니터 설정 (2880x1800 + 2560x1440)의 전체 해상도의 경우 각 촬영에는 약 1.9 초가 소요됩니다.

출처 : https://github.com/troq/flappy-bird-player/blob/master/screenshot.py

import Quartz 
import LaunchServices 
from Cocoa import NSURL 
import Quartz.CoreGraphics as CG 

def screenshot(path, region=None): 
    """saves screenshot of given region to path 
    :path: string path to save to 
    :region: tuple of (x, y, width, height) 
    :returns: nothing 
    """ 
    if region is None: 
     region = CG.CGRectInfinite 

    # Create screenshot as CGImage 
    image = CG.CGWindowListCreateImage(
     region, 
     CG.kCGWindowListOptionOnScreenOnly, 
     CG.kCGNullWindowID, 
     CG.kCGWindowImageDefault) 

    dpi = 72 # FIXME: Should query this from somewhere, e.g for retina displays 

    url = NSURL.fileURLWithPath_(path) 

    dest = Quartz.CGImageDestinationCreateWithURL(
     url, 
     LaunchServices.kUTTypePNG, # file type 
     1, # 1 image in file 
     None 
     ) 

    properties = { 
     Quartz.kCGImagePropertyDPIWidth: dpi, 
     Quartz.kCGImagePropertyDPIHeight: dpi, 
     } 

    # Add the image to the destination, characterizing the image with 
    # the properties dictionary. 
    Quartz.CGImageDestinationAddImage(dest, image, properties) 

    # When all the images (only 1 in this example) are added to the destination, 
    # finalize the CGImageDestination object. 
    Quartz.CGImageDestinationFinalize(dest) 


if __name__ == '__main__': 
    # Capture full screen 
    screenshot("testscreenshot_full.png") 

    # Capture region (100x100 box from top-left) 
    region = CG.CGRectMake(0, 0, 100, 100) 
    screenshot("testscreenshot_partial.png", region=region) 
1

나는 다시 조금 너무 느렸다에서 읽기 나는 좀 더 성능을 필요도 있지만이와 놀아, 그래서 파일에 저장하고 있었어요. 검색 및 손보는 주위의 많은 후 결국 나는이 함께했다 : 내가했다, 그래서

#get_pixels returns a image reference from CG.CGWindowListCreateImage 
imageRef = self.get_pixels() 
pixeldata = CG.CGDataProviderCopyData(CG.CGImageGetDataProvider(imageRef)) 
image = Image.frombuffer("RGBA", (self.width, self.height), pixeldata, "raw", "RGBA", self.stride, 1) 
#Color correction from BGRA to RGBA 
b, g, r, a = image.split() 
image = Image.merge("RGBA", (r, g, b, a)) 

이 또한 내 이미지는 표준 크기의이 아니었다 이후 (패딩해야했다)주의

그것은 몇 가지 이상한 행동을했다 버퍼의 보폭을 적용하기 위해 표준 화면 너비에서 전체 스크린 샷을 찍는 경우 0의 보폭을 사용하면 자동으로 계산됩니다.

이제 쉽게와 OpenCV의에서 작동하도록 만들기 위해 NumPy와 배열에 PIL 형식에서 변환 할 수 있습니다

image = np.array(image) 
+0

게시 할 수있는 보폭 계산을 원하십니까? 나는 비표준 해상도에 관한 문제에 직면 해 있으며 실제로 어떻게했는지보고 싶습니다. :) – Kush131

+0

TBH, 더 이상 코드가 없지만 흔적과 오류로 많은 작업을 수행 한 것을 기억합니다. 화면에 이미지를 렌더링하고 문서가 불량/부족하여 괜찮 았을 때까지 정렬을 계속 변경했습니다. . – Arqu

3

이 Arqu의 대답에 추가하려면, 당신이 빠른 대신 np.frombuffer 사용하여 찾을 수 있습니다 np.frombuffer가 Image.frombuffer와 거의 같은 시간이 걸리기 때문에 opencv 또는 numpy를 사용하는 것이 궁극적 인 목표라면 PIL 이미지를 만드는 것이지만 이미지에서 numpy 배열로 변환하는 단계는 생략됩니다 (약 100ms가 걸림). 내 컴퓨터에서 (그 밖의 모든 것은 ~ 50ms 걸립니다)).

import Quartz.CoreGraphics as CG 
from PIL import Image 
import time 
import numpy as np 

ct = time.time() 
region = CG.CGRectInfinite 

# Create screenshot as CGImage 
image = CG.CGWindowListCreateImage(
    region, 
    CG.kCGWindowListOptionOnScreenOnly, 
    CG.kCGNullWindowID, 
    CG.kCGWindowImageDefault) 

width = CG.CGImageGetWidth(image) 
height = CG.CGImageGetHeight(image) 
bytesperrow = CG.CGImageGetBytesPerRow(image) 

pixeldata = CG.CGDataProviderCopyData(CG.CGImageGetDataProvider(image)) 
image = np.frombuffer(pixeldata, dtype=np.uint8) 
image = image.reshape((height, bytesperrow//4, 4)) 
image = image[:,:width,:] 

print('elapsed:', time.time() - ct) 
+0

너비가 64의 배수가 아닌 너비가있을 때 행 당 바이트가 패딩을 포함 할 때 [이 SO 응답] (http://stackoverflow.com/a/25706554/984112)을 참조하십시오. . 'CGImageGetBytesPerRow'에서 행 당 바이트 수를 얻어야하고'width' 대신에'bytes_per_row/4'를 재 형성해야합니다. '[:, : width]'를 사용하여 결과 배열을 조각 낼 수 있습니다. –

+0

좋은 지적, 나중에이 문제를 해결하고 답변을 업데이트하지 않았습니다. – Scrub