문제

좋아, 그래서 나는 최적화가 필요한 파이썬 코드를 가지고있다.

  • 작은 (80x60-pixel) 이미지에 대한 게임 반복이며 RGB 값을 추출합니다.
  • 현재 중첩 된 루프를 사용하고 있습니다. 차라리 더 빨리 루프를 위해 교체하고 싶습니다. map() C 함수이지만 그렇게하면 x, y 값을 얻을 수있는 방법이나 정의해야 할 함수의 범위에서 정의 된 로컬 값을 어떻게 얻을 수 있는지 알 수 없습니다.
  • 사용합니다 map() 루프에 대한이 현재 세트보다 빠릅니까? 어떻게 사용하고 여전히 x를 얻을 수 있습니까?
  • 나는 현재 Pygame 표면을 사용하고 있으며 surfarray/pixelarray 모듈이지만 모든 픽셀을 변경/받기 때문에 Surface.get_at()/set_at().
  • 또한 약간 관련이 없습니다 ... Python이 숫자 목록을 가로 지르지 않고 다른 언어와 같이 숫자를 증가시키는 경우 더 빨리 만들 수 있다고 생각하십니까? Python에 Python이 ()와 oreach ()를 위해 정상을 포함하지 않는 이유는 무엇입니까?
  • 조건부의 양은 아마도 일을 느리게 만들 것입니다. 가장 느린 부분은 이웃을 확인하는 것입니다 (목록 N을 작성하는 곳) ... 2D 배열에서 슬라이스 액세스로 전체 비트를 교체했지만 제대로 작동하지 않습니다.

수정 된 버전의 코드 :

xr = xrange(80)
yr = xrange(60)
# surface is an instance of pygame.Surface
get_at = surface.get_at()
set_at = surface.set_at()

for x in xr:
    # ....
    for y in yr:
        # ...
        pixelR = get_at((x,y))[0]
        pixelG = get_at((x,y))[1]
        pixelB = get_at((x,y))[2]
        # ... more complex stuff here which changes R,G,B values independently of each other
        set_at((x,y),(pixelR,pixelG,pixelB))

기능의 정식 버전 :

# xr, yr = xrange(80), xrange(60)
def live(surface,xr,yr):
    randint = random.randint
    set_at = surface.set_at
    get_at = surface.get_at
    perfect = perfectNeighbours #
    minN = minNeighbours        # All global variables that're defined in a config file.
    maxN = maxNeighbours        #
    pos = actual                # actual = (80,60)
    n = []
    append = n.append
    NEIGHBOURS = 0

    for y in yr: # going height-first for aesthetic reasons.
        decay = randint(1,maxDecay)
        growth = randint(1,maxGrowth)

        for x in xr:
            r, g, b, a = get_at((x,y))

            del n[:]
            NEIGHBOURS = 0

            if x>0 and y>0 and x<pos[0]-1 and y<pos[1]-1:
                append(get_at((x-1,y-1))[1])
                append(get_at((x+1,y-1))[1])
                append(get_at((x,y-1))[1])
                append(get_at((x-1,y))[1])
                append(get_at((x+1,y))[1])
                append(get_at((x-1,y+1))[1])
                append(get_at((x+1,y+1))[1])
                append(get_at((x,y+1))[1])
                for a in n:
                    if a > 63:
                        NEIGHBOURS += 1

            if NEIGHBOURS == 0 and (r,g,b) == (0,0,0): pass
            else:

                if NEIGHBOURS < minN or NEIGHBOURS > maxN:
                    g = 0
                    b = 0
                elif NEIGHBOURS==perfect:
                    g += growth
                    if g > 255:
                        g = 255
                        b += growth
                        if b > growth: b = growth
                else:
                    if g > 10: r = g-10
                    if g > 200: b = g-100
                    if r > growth: g = r
                    g -= decay
                    if g < 0:
                        g = 0
                        b = 0
                r -= 1
                if r < 0:
                    r = 0
                set_at((x,y),(r,g,b))
도움이 되었습니까?

해결책

당신이 읽고 다시 쓰고 있기 때문에 모든 픽셀, 나는 당신이 Surface.

먼저 80x60 이미지를 촬영하여 32 비트 픽셀의 일반 비트 맵 파일로 변환하는 것이 좋습니다. 그런 다음 픽셀 데이터를 파이썬으로 읽으십시오 array 물체. 이제 당신은 걸을 수 있습니다 array 객체, 값을 읽고, 새로운 값을 계산하고, 새로운 값을 최대 속도로 제자리에 찔렀습니다. 완료되면 새 비트 맵 이미지를 저장 한 다음 Surface.

24 비트 픽셀을 사용할 수도 있지만 느려져야합니다. 32 비트 픽셀은 하나의 픽셀이 하나의 32 비트 정수 값으로 픽셀 배열을 훨씬 쉽게 색인 할 수 있습니다. 24 비트 포장 픽셀은 각 픽셀이 3 바이트이며, 이는 색인에 훨씬 성가시다는 것을 의미합니다.

나는 당신이 사용을 피하는 것 보다이 접근법에서 훨씬 더 빠른 속도를 얻을 것이라고 생각합니다. for. 이것을 시도하면 여기에 무언가를 게시하여 얼마나 잘 작동했는지 알려주십시오. 행운을 빕니다.

편집 : 나는 그 생각을 생각했다 array 단일 색인 만 있습니다. 어떻게 두 가지 인덱스를 얻을 수 있는지 잘 모르겠습니다. 나는 당신이 다음과 같은 일을하기를 기대하고있었습니다.

def __i(x, y):
    assert(0 <= x < 80)
    assert(0 <= y < 60)
    i = (y*80 + x) * 4
    return i
def red(x, y):
    return __a[__i(x, y)]
def green(x, y):
    return __a[__i(x, y) + 1]
def blue(x, y):
    return __a[__i(x, y) + 2]
def rgb(x, y):
    i = __i(x, y)
    return __a[i], __a[i + 1], __a[i + 2]
def set_rgb(x, y, r, g, b):
    i = __i(x, y)
    _a[i] = r
    _a[i + 1] = g
    _a[i + 2] = b

# example:
r, g, b = rgb(23, 33)

파이썬 이후 array 단일 유형 만 보유 할 수 있으면 유형을 "부호없는 바이트"로 설정 한 다음 내가 보여준 것처럼 색인을 설정하려고합니다.

물론 어디서 __a 실제입니다 array 변하기 쉬운.

이 중 어느 것도 도움이되지 않으면 비트 맵을 목록 또는 세 개의 목록으로 변환하십시오. 중첩 목록을 사용하여 2D 주소를 얻을 수 있습니다.

이게 도움이 되길 바란다. 그것이 도움이되지 않는다면, 나는 당신이하고있는 일을 이해하지 못합니다. 더 설명하면 답을 향상 시키려고 노력할 것입니다.

다른 팁

코드를 느리게 만드는 것은 아마도 루프가 아니며 엄청나게 빠릅니다.

코드 속도가 느리게 진행되는 것은 기능 호출 수입니다. 예를 들어

pixelR = get_at((x,y))[0]
pixelG = get_at((x,y))[1]
pixelB = get_at((x,y))[2]

~이다 많이 느린 것보다 느린 (약 3 배 추측)

r, g, b, a = get_at((x,y))

모든 get_at, set_at Call은 표면을 잠금하므로 사용 가능한 방법을 사용하여 픽셀에 직접 액세스하는 것이 더 빠릅니다. 가장 합리적으로 보이는 것은입니다 Surface.get_buffer.

사용 map 인덱스가 필요하기 때문에 예에서는 작동하지 않습니다. 80 ~ 60 숫자로 사용하기가 더 빠를 수도 있습니다. range() 대신에 xrange().

map(do_stuff, ((x, y) for x in xrange(80) for y in xrange(60)))

어디 do_stuff 아마도 그렇게 정의 될 것입니다.

def do_stuff(coords):
    r, g, b, a = get_at(coords)
    # ... whatever you need to do with those ...
    set_at(coords, (r, g, b))

대안 적으로 생성기 표현식 대신 목록 이해력을 두 번째 인수로 사용할 수 있습니다. map (바꾸다 ((x, y) ...) ~와 함께 [(x, y) ...]) 및 사용 range 대신에 xrange. 그래도 성능에 큰 영향을 미치지 않을 것이라고 말하고 싶습니다.

편집하다: GS는 확실히 옳습니다 for 루프는 코드에서 최적화를 필요로하는 주요한 것이 아닙니다 ... 불필요한 호출을 줄입니다. get_at 더 중요합니다. 사실, 루프를 map 실제로 여기서 성능을 향상시킬 것입니다 ... map 더 읽기 쉬운 버전 (아마도 내 FP 배경 때문에 ...). ;-)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top