猿问

需要为 Python 上的图像处理加速非常慢的循环

我目前正在根据内部要求在 Pyhton (3.6) 中完成一个程序。作为其中的一部分,我必须遍历彩色图像(每像素 3 个字节,R、G 和 B)并逐个像素地扭曲图像。


我在其他语言(C++、C#)中有相同的代码,非优化代码在大约两秒内执行,而优化代码在不到一秒内执行。非优化代码是指矩阵乘法由我实现的 10 行函数执行。优化版本仅使用外部库进行乘法运算。


在 Python 中,这段代码需要接近 300 秒。我想不出一种方法来矢量化这个逻辑或加速它,因为嵌套循环中有几个“if”。任何帮助将不胜感激。


import numpy as np


#for test purposes:

#roi = rect.rect(0, 0, 1200, 1200)

#input = DCImage.DCImage(1200, 1200, 3)

#correctionImage = DCImage.DCImage(1200,1200,3)

#siteToImage= np.zeros((3,3), np.float32)

#worldToSite= np.zeros ((4, 4))

#r11 = r12 = r13 = r21 = r22 = r23 = r31 = r32 = r33 = 0.0

#xMean = yMean = zMean = 0 

#tx = ty = tz = 0

#epsilon = np.finfo(float).eps

#fx = fy = cx = cy = k1 = k2 = p1 = p2 = 0



for i in range (roi.x, roi.x + roi.width):

    for j in range (roi.y , roi.y + roi.height):

        if ( (input.pixels [i] [j] == [255, 0, 0]).all()):

            #Coordinates conversion

            siteMat = np.matmul(siteToImage, [i, j, 1])

            world =np.matmul(worldToSite, [siteMat[0], siteMat[1], 0.0, 1.0])


            xLocal = world[0] - xMean

            yLocal = world[1] - yMean

            zLocal = z_ortho - zMean

            #From World to camera

            xCam = r11*xLocal + r12*yLocal + r13*zLocal + tx

            yCam = r21*xLocal + r22*yLocal + r23*zLocal + ty

            zCam = r31*xLocal + r32*yLocal + r33*zLocal + tz

            if (zCam > epsilon or zCam < -epsilon):

                xCam = xCam / zCam

                yCam = yCam / zCam


            #// DISTORTIONS                           

            r2 = xCam*xCam + yCam*yCam

            a1 = 2*xCam*yCam

            a2 = r2 + 2*xCam*xCam

            a3 = r2 + 2*yCam*yCam

            cdist = 1 + k1*r2 + k2*r2*r2

            u = int((xCam * cdist + p1 * a1 + p2 * a2) * fx + cx + 0.5)

            v = int((yCam * cdist + p1 * a3 + p2 * a1) * fy + cy + 0.5)


            if (u>=0 and u<correctionImage.width and v>=0 and v < correctionImage.height):

                input.pixels [i] [j] =  correctionImage.pixels [u][v]


鸿蒙传说
浏览 428回答 2
2回答

互换的青春

经过大量测试,无需用 C++ 编写即可加速该函数的唯一方法是对其进行反汇编和矢量化。在此特定实例中执行此操作的方法是在函数的开头创建一个具有有效索引的数组,并将它们用作元组来索引最终解决方案。subArray[roi.y:roi.y+roi.height,roi.x:roi.x+roi.width,] = input.pixels[roi.y:roi.y+roi.height,roi.x:roi.x+roi.width,]#Calculate valid XY indexesy_index, x_index = np.where(np.all(subArray== np.array([255,0,0]), axis=-1))#....#do stuff#....#Join result values with XY indexesij_xy = np.column_stack((i, j, y_index, x_index))#Only keep valid ij valuesvalids_ij_xy = ij_xy [(ij_xy [:,0] >= 0) & (ij_xy [:,0] < correctionImage.height) & (ij_xy [:,1] >= 0) & (ij_xy [:,1] < correctionImage.width)]#Assign valuesinput.pixels [tuple(np.array(valids_ij_xy [:,2:]).T)] = correctionImage.pixels[tuple(np.array(valids_ij_xy [:,:2]).T)]

潇湘沐

您通常通过制作置换贴图来矢量化这种东西。制作一个复杂的图像,其中每个像素都有自己的坐标值,应用通常的数学运算来计算你想要的任何变换,然后将地图应用到你的源图像。例如,在pyvips 中你可以这样写:import sysimport pyvipsimage = pyvips.Image.new_from_file(sys.argv[1])# this makes an image where pixel (0, 0) (at the top-left) has value [0, 0],# and pixel (image.width, image.height) at the bottom-right has value# [image.width, image.height]index = pyvips.Image.xyz(image.width, image.height)# make a version with (0, 0) at the centre, negative values up and left,# positive down and rightcentre = index - [image.width / 2, image.height / 2]# to polar space, so each pixel is now distance and angle in degreespolar = centre.polar()# scale sin(distance) by 1/distance to make a wavey patternd = 10000 * (polar[0] * 3).sin() / (1 + polar[0])# and back to rectangular coordinates again to make a set of vectors we can# apply to the original index imagedistort = index + d.bandjoin(polar[1]).rect()# distort the imagedistorted = image.mapim(distort)# pick pixels from either the distorted image or the original, depending on some# conditionresult = (d.abs() > 10 or image[2] > 100).ifthenelse(distorted, image)result.write_to_file(sys.argv[2])这只是一个愚蠢的摆动模式,但您可以将其换成您想要的任何失真。然后运行为:$ /usr/bin/time -f %M:%e ./wobble.py ~/pics/horse1920x1080.jpg x.jpg54572:0.31这款 2015 年的两核笔记本电脑具有 300 毫秒和 55MB 的内存,可用于:
随时随地看视频慕课网APP

相关分类

Python
我要回答