Oto jedno podejście, które jest znacznie szybsze niż V2
: weź img1-img2
i pomnóż przez 1 lub -1 w zależności od img1>img2
. Oto jak to jest realizowane:
def differenceImageV6(img1, img2):
a = img1-img2
b = np.uint8(img1<img2) * 254 + 1
return a * b
Uprząż testy do wykonania badania:
import numpy as np
img1=np.uint8(np.random.randint(0, 255, (480, 640)))
img2=np.uint8(np.random.randint(0, 255, (480, 640)))
def differenceImageV1(img1, img2):
diff=np.empty_like(img1)
h, w=img1.shape
for y in range(h):
for x in range(w):
if img1[y, x]<img2[y, x]: diff[y, x]=img2[y, x]-img1[y, x]
else: diff[y, x]=img1[y, x]-img2[y, x]
return(diff)
def differenceImageV2(img1, img2):
return(np.uint8(np.abs(np.int16(img1)-img2)))
def differenceImageV3(img1, img2): # fast - but wrong result
return(img1-img2)
def differenceImageV4(img1, img2):
return np.where(img1>img2, img1-img2, img2-img1)
def differenceImageV5(img1, img2):
a = img1-img2
b = img2-img1
c = img1>img2
return a*c + b*(~c)
def differenceImageV6(img1, img2):
a = img1-img2
b = np.uint8(img1<img2) * 254 + 1
return a * b
import timeit
def testit():
for fn in [differenceImageV2, differenceImageV3, differenceImageV4, differenceImageV5, differenceImageV6]:
print fn.__name__, np.sum(fn(img1, img2).astype('int64')),
print timeit.timeit("%s(img1, img2)" % fn.__name__, "from test import img1, img2, %s" % fn.__name__, number=1000)
if __name__ == '__main__':
testit()
i wynikające skuteczności liczbach:
differenceImageV2 26071358 0.982538938522
differenceImageV3 39207702 0.0261280536652
differenceImageV4 26071358 1.36270809174
differenceImageV5 26071358 0.220561981201
differenceImageV6 26071358 0.154536962509
differenceImageV6
wynosi około 6x wolniej niż nieprawidłowej differenceImageV3
, ale wciąż około 6 razy szybszy niż poprzedni najlepszy differenceImageV2
. differenceImageV1
nie jest testowany, ponieważ łatwo jest go o kilka rzędów wielkości wolniej niż pozostałe.
Uwaga: Do porównania użyto metody np.where
; Pomyślałem, że może to być dobre wykonanie, ale okazuje się dość słabe. Wygląda na to, że wykonywanie skrawania przez tablicę boolowską jest dość powolne w NumPy.
Nie jestem pewien, czy naprawdę by to pomogło, ale prawdopodobnie nie potrzebujesz 'np.int16 (img2)' w 'differenceImageV2', i możesz po prostu użyć' img2'. Czy używasz biblioteki ['timeit'] (https://docs.python.org/2/library/timeit.html) do dokładnego pomiaru czasu? – Kupiakos
Jestem świadomy przepełnienia (niedopełnienie jest wtedy, gdy różnica między dwoma liczbami zmiennoprzecinkowymi jest zbyt mała, aby można było je odróżnić). Mam na myśli pełne wyrażenie byłoby 'return (np.uint8 (np.absolute (np.int16 (img1) -img2)))). 'img1' jest nadal rzutowany na' int16', więc wynik będzie "int16" i może pozwolić na te same liczby ujemne, które wykona wcześniej rzutowanie. 'np.sum' daje taki sam wynik. Po prostu nie bierze najpierw kopii całej tablicy. Zgolę około 70 ms na 1000 pętli. – Kupiakos
masz rację. Otrzymuję taki sam wynik, jeśli wykonuję 'np.int16 (img1) -img2'. Czas wykonania spada do 400.39 ms dla 1000 pętli. I nie, używam 'time.process_time()' tutaj, ponieważ nie dbam o jeden lub dziesięć milisekund. – dede