【OpenCV】OpenCV/Python遍历像素点操作运行效率低的解决方法

1. 背景

        该问题源于实验室项目,里面涉及图像处理的相关操作。在其中利用重心法检测二值化目标的圆心时,发现运行效率很低,给图像的精度测试带来了很大的麻烦。因此,考虑将该部分改进,以提高重心法检测的速度。

2. 传统重心法检测

# --重心法检测圆心--
sum_x = 0
sum_y = 0
cnt_x = 0
cnt_y = 0
for i in range(blank_bg.shape[0]):
    for j in range(blank_bg.shape[1]):
        if blank_bg[i,j] < 10:
            sum_x += j
            cnt_x += 1
            sum_y += i
            cnt_y += 1
point_x = sum_x/cnt_x
point_y = sum_y/cnt_y

        可以看到,这里使用for循环对图像进行逐像素遍历。对1000×1000的单通道图像,运行时间是1.264秒(电脑处理器i7-11800H 8核心16线程,内存32G)。可以说在这个硬件条件下,这个速度不快,甚至可以说是相当慢。

        分析了一下原因。这是因为在Python中,for循环是特别低效的。然而在这里for循环里面套了给for循环,这一部分会被执行1000000(100万)次,大幅降低了程序的运行效率。因此,需要考虑用别的函数来替换掉这两个for循环。

3. 利用np.where改进重心法检测

# --重心法检测圆心--
xy=np.where(blank_bg < 10)
listx=list(xy)[0]   #行
listy=list(xy)[1]   #列
point_x = np.sum(listy)/len(listy)
point_y = np.sum(listx)/len(listx)

        使用np的内置函数可以大幅提高程序的运行效率。这里使用np.where来替换掉两个for循环。

        np.where返回的是一个元组,n维数组的输入会返回n维元组。对图像来说,输入为二维数组(像素坐标为二维),因此返回值为2维元组,如下所示:

(array([509, 509, 509, ..., 766, 766, 766], dtype=int64), array([337, 338, 339, ..., 380, 381, 382], dtype=int64))

        这个2维元组的第一个数表示满足条件的坐标,第二个数表示满足条件的坐标。这样就通过np.where替代了两层for循环。之后便可以根据返回的结果对像素进行操作。实测下来,该部分运行时间是0.003秒,运行效率提高了421倍

4. 利用numba改进重心法检测

        将该部分(有大量数值计算的部分)封装为一个函数(注意第一行的@jit!!!):

@jit
def centroid(blank_bg):
    sum_x = 0
    sum_y = 0
    cnt_x = 0
    cnt_y = 0
    for i in range(blank_bg.shape[0]):
        for j in range(blank_bg.shape[1]):
            if blank_bg[i,j] < 10:
                sum_x += j
                cnt_x += 1
                sum_y += i
                cnt_y += 1
    point_x = sum_x/cnt_x
    point_y = sum_y/cnt_y
    return point_x,point_y

        在头文件中加入:

from numba import jit

注意:@jit标注的函数内不能存在非数值运算语句。因此,类似于time.time()这样的函数需要放在函数外面,函数内只放大量数值运算的语句。

        Python通常只调用了CPU来进行运算,而numba模块可以调用GPU来分担CPU的工作。加速后的时间为0.23秒

        numba往往对大循环效果更好。如果将该循环重复100次,运行时间仅为0.28秒,增幅不大。而不使用numba模块加速则需要127.03秒

5. 总结

        对于运算量中等的遍历像素操作,使用np.where来替代for循环是最佳的选择,可以达到最快的运算速度。然而对于更复杂的数值运算过程,使用numba加速效率更高。但是在图像处理中像素的数量级还远没有达到需要numba加速的程度,使用np.where即可。

  • 11
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Quentin_HIT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值