

画像内で指定した領域に平均フィルタをかけて、フィルタをかける前の画像との誤差を画素ごとの画素値の差で求め、それが最大になる場合と最小になる場合の領域の位置と処理後の画像を求めようとしています。  
誤差は処理前後の画像のrgb値の差の二乗を求め、それらの合計によって定義します。

以下のように誤差計算の動作確認を行ったところ、動作が非常に重く作業が進行しません。  
問題点や解決法をご教示いただけると幸いです。

[code]

    from PIL import Image
    import numpy as np
    import cv2
    import matplotlib.pyplot as plt
    import math
    
    
    def main():
        F = cv2.imread("gazou.jpg")
        m, n, c = F.shape
        h = 30
        M = math.floor(m/h)
        N = math.floor(n/h)
        im = F[1:M*h, 1:N*h]
        list = []
        for i in range(h):
            for j in range(h):
                D = im[i:(i+(M-1)*h-1), j:(j+(N-1)*h-1)]
                P = cv2.blur(D, (h, h))
                List = []
                for x in range((M-1)*h-1):
                    for y in range((N-1)*h-1):
                        Db,Dg,Dr = D[x,y]
                        Pb,Pg,Pr = P[x,y]
                        e = pow(int(Dr)-int(Pr), 2)+pow(int(Dg)-int(Pg), 2)+pow(int(Db)-int(Pb), 2)
                        List.append(e)
                E = sum(List)
                list.append(E)
        Emin = min(list)
        Emax = max(list)
        print(Emin)
        print(Emax)
    
    
    if __name__ == '__main__':
        main()
    
[/code]


CC BY-SA 4.0
2019-12-09T10:32:18.033
61268
2019-12-10T01:06:50.553
2019-12-09T11:28:58.063
19110
36996
question
python python3
python 2枚の画像の誤差計算について


やはり四重ループが気になりますね．NumPy自体はC言語等で実装されているため，ある程度速いはずなのですが，for文を書いてしまうとその性能を発揮できず，どうして遅くなってしまいます．

とりあえず，内側のfor文2つは簡単に無くせるので書き換えると以下のようになりました．

[code]

    def main2():
        F = cv2.imread("gazou.jpg")
        m, n, c = F.shape
        h = 30
        M = math.floor(m/h)
        N = math.floor(n/h)
        im = F[1:M*h, 1:N*h]
        list = []
        for i in range(h):
            for j in range(h):
                D = im[i:(i+(M-1)*h-1), j:(j+(N-1)*h-1)]
                P = cv2.blur(D, (h, h))
                E = ((D.astype(np.int) - P.astype(np.int))**2).sum()
                list.append(E)
        Emin = min(list)
        Emax = max(list)
        print(Emin)
        print(Emax)
    
[/code]

手元で256x256の画像を入力に `%time` で速度を測ったところ，元コードが

[code]

    CPU times: user 1min 26s, sys: 56 ms, total: 1min 27s
    Wall time: 1min 27s
    
[/code]

であったところ，`main2`への変更で

[code]

    CPU times: user 346 ms, sys: 4 µs, total: 346 ms
    Wall time: 345 ms
    
[/code]

になりました（出力の一致は1ケースだけですが確認しています）．

* * *

思考の流れとしては，

[code]

    for x in range((M-1)*h-1):
        for y in range((N-1)*h-1):
            Db,Dg,Dr = D[x,y]
            Pb,Pg,Pr = P[x,y]
            e = pow(int(Dr)-int(Pr), 2)+pow(int(Dg)-int(Pg), 2)+pow(int(Db)-int(Pb), 2)
            List.append(e)
    E = sum(List)
    
[/code]

を一旦

[code]

    for x in range((M-1)*h-1):
        for y in range((N-1)*h-1):
            for c in range(3):
                e = pow(int(D[x, y, c])-int(P[x, y, c]), 2)
                List.append(e)
    E = sum(List)  # sumを取るので辻褄は合う 
    
[/code]

の様に思うと，`List`を `(D.astype(np.int) - P.astype(np.int))**2`
に置き換えれば，for文を無くせることに気がつくという感じですね．

* * *

NumPyを使っているときは，NumPy配列に対するfor文をいかに減らせるかが，速いコードを書くための一つの大きな指標になるはずです．


CC BY-SA 4.0
2019-12-09T14:24:23.383
61274
2019-12-10T01:06:50.553
2019-12-10T01:06:50.553
36544
36544
61268
answer