使用Boost Python的Python性能没有提高

时间:2014-01-21 05:28:07

标签: python c++ performance boost numpy

我正在开发一个大型计算机视觉项目,我需要对来自多个摄像头的每个帧进行一些处理。它很重,我想提高速度。所以我想用boost python在c ++中包装一个python函数。

这里我要用c ++包装的函数:

def computeSumInboundingbox(self, cameraTable, integral):   
   for line in cameraTable:
        minX, minY, maxX, maxY = line[2], line[3], line[4], line[5]
        # sum of the pixel in the bounding box according to integral image
        sumBox = integral[(minY,minX)] + integral[(maxY, maxX)] - integral[(maxY,minX)] - integral[(minY,maxX)]
        # we scale the sumBox
        if sumBox != 0: 
            self.bitmap[line[0],line[1]] = \
                float(sumBox) / ((maxX - minX) * (maxY - minY))

此功能正在从2D列表 cameraTable (查找表)中读取一些坐标。该表已在我的课程初始化期间加载。 Integral 位图 是2d numpy数组。 我有很多坐标所以这样做每一帧都有点慢。

然后我用c ++包装函数。

boost::python::numeric::array computeSumInboundingbox(boost::python::numeric::array integral, list cameraTable, boost::python::numeric::array bitmap)
{
 list currCameraTable;
 float sumBox;
 for (int i = 0 ; i < len(cameraTable) ; i++)
 {   
    int x = extract<float>(cameraTable[i][0]);
    int y = extract<float>(cameraTable[i][1]);
    float minX = extract<float>(cameraTable[i][2]);
    float minY = extract<float>(cameraTable[i][3]);
    float maxX = extract<float>(cameraTable[i][4]);
    float maxY = extract<float>(cameraTable[i][5]);

    // // sum of the pixel in the bounding box according of integral image
    sumBox = extract<float>(integral[make_tuple(minY, minX)] + integral[make_tuple(maxY, maxX)] - 
            integral[make_tuple(maxY, minX)] - integral[make_tuple(minY, maxX)]);
    // we scale the sumBox 
    if (sumBox != 0)
        bitmap[make_tuple(y,x)] = sumBox / ((maxX - minX) * (maxY - minY));
 }

return bitmap;
}

但是我的表现非常糟糕,2000帧的视频又跑了45秒!

然后我认为提取函数可能需要一段时间来处理,所以首先我在python中的1D std :: vector中转换了我的2D列表(我真的没有找到创建2D矢量的方法)

boost::python::numeric::array computeSumInboundingbox(boost::python::numeric::array integral, std::vector<float> cameraTable, boost::python::numeric::array bitmap)
{
 list currCameraTable;
 float sumBox;
 int x;
 int y;
 float minX, minY, maxX, maxY;

 for (int i = 0 ; i < cameraTable.size() ; i+=6)
 {   
    int x = cameraTable[i];
    int y = cameraTable[i+1];
    float minX = cameraTable[i+2];
    float minY = cameraTable[i+3];
    float maxX = cameraTable[i+4];
    float maxY = cameraTable[i+5];

    // // sum of the pixel in the bounding box according of integral image
    sumBox = extract<float>(integral[make_tuple(minY, minX)] + integral[make_tuple(maxY, maxX)] - 
            integral[make_tuple(maxY, minX)] - integral[make_tuple(minY, maxX)]);
    // we scale the sumBox
    if (sumBox != 0)
        bitmap[make_tuple(y,x)] = sumBox / ((maxX - minX) * (maxY - minY));
 }

return bitmap;
}

仅供参考:

BOOST_PYTHON_MODULE(Mapper_ext)
{
    using namespace boost::python;
    using namespace std;

    boost::python::numeric::array::set_module_and_type("numpy", "ndarray");

    class_<vector<float> >("VectorFloat")
    .def(vector_indexing_suite<vector<float> > ());

    def("computeSumInboundingbox", computeSumInboundingbox);
}

以下是2000帧的三个函数的处理时间

  • python function = 100s
  • 第一个c ++函数= 145s
  • 第二个c ++函数= 121s

即使第二个c ++函数比第一个更好,它仍然比仅使用python慢​​。为什么?我认为使用C ++会更快,特别是使用for循环。无论如何我可以让c ++比python表现得更快,还是我在这里浪费时间?

这是我的numba版本。一开始我的createFloorBitmap方法在我的类中,我将numba装饰器添加到类中,但我无法工作,所以我将方法移出了类。 setup()和execute()继承自对象Node。

class Mapper(Node):
 def setup(self):
 # initialise some parameters self.bitmap, self.coordTable
 def execute(self,data):
 # main function
  integral = data['image']
  self.bitmap[:] = 0
  self.bitmap = createFloorBitmap(self.bitmap, self.coordTable, integral)
  return self.bitmap

@jit(f8[:,::1](f8[:,::1], f8[:,::1], f8[:,::1]))       
def createFloorBitmap(bitmap, lines, integral):
 for row in range(lines.shape[0]):
    minX, minY, maxX, maxY = lines[row, 2], lines[row, 3], lines[row, 4], lines[row, 5]
    sumBox = integral[minY,minX] + integral[maxY, maxX] - integral[maxY,minX] - integral[minY,maxX]
    if sumBox != 0:
        bitmap[lines[row, 1],lines[row, 0]] = float(sumBox) / ((maxX - minX) * (maxY - minY))   
return bitmap 

感谢您的帮助

1 个答案:

答案 0 :(得分:3)

您可以使用数组作为索引来提高速度,下面是代码:

w = 600

integral = np.random.randint(0, 255, (w, w))
bitmap = np.zeros_like(integral)

lines = np.random.randint(0, w, (10000, 6))

def computeSumInboundingbox(bitmap, cameraTable, integral):   
   for line in cameraTable:
        minX, minY, maxX, maxY = line[2], line[3], line[4], line[5]
        sumBox = integral[(minY,minX)] + integral[(maxY, maxX)] - integral[(maxY,minX)] - integral[(minY,maxX)]
        if sumBox != 0: 
            bitmap[line[0],line[1]] = float(sumBox) / ((maxX - minX) * (maxY - minY))

def computeSumInboundingbox2(bitmap, line, integral):
    tx, ty, minx, miny, maxx, maxy = line.T
    sumBox = integral[miny, minx] + integral[maxy, maxx] - integral[maxy, minx] - integral[miny, maxx]
    mask = sumBox != 0
    bitmap[tx[mask], ty[mask]] = (sumBox.astype(float)[mask] / ((maxx - minx) * (maxy - miny))[mask])    

bitmap1 = np.zeros_like(integral)
bitmap2 = np.zeros_like(integral)
computeSumInboundingbox(bitmap1, lines, integral)
computeSumInboundingbox2(bitmap2, lines, integral)
print np.allclose(bitmap1, bitmap2)

现在是时间:

computeSumInboundingbox: 10 loops, best of 3: 42.4 ms per loop
computeSumInboundingbox2: 100 loops, best of 3: 2.36 ms per loop

为什么c ++很慢,因为你使用python对象级方法来进行数组索引。您可以使用cython,它知道如何访问c级数据。

修改

这是一个numba版本:

import numba
@numba.jit("void(i4[:,::1], i4[:,::1], i4[:,::1])")
def computeSumInboundingbox3(bitmap, lines, integral):
    for row in range(lines.shape[0]):
        minX, minY, maxX, maxY = lines[row, 2], lines[row, 3], lines[row, 4], lines[row, 5]
        sumBox = integral[minY,minX] + integral[maxY, maxX] - integral[maxY,minX] - integral[minY,maxX]
        if sumBox != 0:
            bitmap[lines[row, 0],lines[row, 1]] = float(sumBox) / ((maxX - minX) * (maxY - minY))

和速度:

10000 loops, best of 3: 119 µs per loop