当前位置: 首页 > 知识库问答 >
问题:

如何在python OpenCV中高效地对一幅图像进行逐像素循环?

轩辕弘雅
2023-03-14

it = np.nditer(pixels, flags=['multi_index'])
while not it.finished:
    y, x = it.multi_index
    color = it[0]
    it.iternext()
    center = (x*20 + 10, y*20 + 10) # corresponding circle center
    cv2.circle(circles, center, int(8 * color/255), 255, -1)

这样循环有点慢。我尝试添加numba的@njit decorator,但显然它与opencv有问题。

输入图像为32x32像素。它们映射到32x32圆的输出图像。每个圆绘制在一个20x20像素的正方形内。也就是说,输出图像为640x640像素

一张图像需要大约100毫秒才能转化为圆圈,我希望能将其降低到30毫秒或更低

有什么建议吗?

共有1个答案

凌伟泽
2023-03-14

当:

  • 处理图纸
  • 可能选项的数量不超过常识值(在本例中为256)
  • 速度很重要(我想总是这样)
  • 没有其他限制阻止这种方法

最好的方法是“缓存”绘图(在另一个数组中预先绘制(或根据需要根据所需的开销)),并且当绘图正常发生时,只需从缓存中获取适当的绘图并将其放置在目标区域(如@ChristophRackwitz在其中一条评论中所述),这是一个非常快速的NumPy操作(与绘图相比)。

作为附带说明,这是一种通用方法,不必限于附图。

但你声称得到的结果是:每幅32x32图像约100毫秒(640x640圈图像),对我来说没有任何意义(因为OpenCV也很快,1024圈应该没什么大不了的),所以我创建了一个程序来说服自己。

代码00.py:

#!/usr/bin/env python

import itertools as its
import sys
import time

import cv2
import numpy as np


def draw_img_orig(arr_in, arr_out, *args):
    factor = round(arr_out.shape[0] / arr_in.shape[0])
    factor_2 = factor // 2
    it = np.nditer(arr_in, flags=["multi_index"])
    while not it.finished:
        y, x = it.multi_index
        color = it[0]
        it.iternext()
        center = (x * factor + factor_2, y * factor + factor_2) # corresponding circle center
        cv2.circle(arr_out, center, int(8 * color / 255), 255, -1)


def draw_img_regular_iter(arr_in, arr_out, *args):
    factor = round(arr_out.shape[0] / arr_in.shape[0])
    factor_2 = factor // 2
    for row_idx, row in enumerate(arr_in):
        for col_idx, col in enumerate(row):
            cv2.circle(arr_out, (col_idx * factor + factor_2, row_idx * factor + factor_2), int(8 * col / 255), 255, -1)


def draw_img_cache(arr_in, arr_out, *args):
    factor = round(arr_out.shape[0] / arr_in.shape[0])
    it = np.nditer(arr_in, flags=["multi_index"])
    while not it.finished:
        y, x = it.multi_index
        yf = y * factor
        xf = x *factor
        arr_out[yf: yf + factor, xf: xf + factor] = args[0][it[0]]
        it.iternext()


def generate_input_images(shape, count, dtype=np.uint8):
    return np.random.randint(256, size=(count,) + shape, dtype=dtype)


def generate_circles(shape, dtype=np.uint8, func=lambda x: int(8 * x / 255), color=255):
    ret = np.zeros((256,) + shape, dtype=dtype)
    cy = shape[0] // 2
    cx = shape[1] // 2
    for idx, arr in enumerate(ret):
        cv2.circle(arr, (cx, cy), func(idx), color, -1)
    return ret


def test_draw(imgs_in, img_out, count, draw_func, *draw_func_args):
    print("\nTesting {:s}".format(draw_func.__name__))
    start = time.time()
    for i, e in enumerate(its.cycle(range(imgs_in.shape[0]))):
        draw_func(imgs_in[e], img_out, *draw_func_args)
        if i >= count:
            break
    print("Took {:.3f} seconds ({:d} images)".format(time.time() - start, count))


def test_speed(shape_in, shape_out, dtype=np.uint8):
    imgs_in = generate_input_images(shape_in, 50, dtype=dtype)
    #print(imgs_in.shape, imgs_in)
    img_out = np.zeros(shape_out, dtype=dtype)
    circles = generate_circles((shape_out[0] // shape_in[0], shape_out[1] // shape_in[1]))
    count = 250
    test_draw(imgs_in, img_out, count, draw_img_orig)
    test_draw(imgs_in, img_out, count, draw_img_regular_iter)
    test_draw(imgs_in, img_out, count, draw_img_cache, circles)


def test_accuracy(shape_in, shape_out, dtype=np.uint8):
    img_in = np.arange(np.product(shape_in), dtype=dtype).reshape(shape_in)
    circles = generate_circles((shape_out[0] // shape_in[0], shape_out[1] // shape_in[1]))
    data = (
        (draw_img_orig, "orig.png", None),
        (draw_img_regular_iter, "regit.png", None),
        (draw_img_cache, "cache.png", circles),
    )
    imgs_out = [np.zeros(shape_out, dtype=dtype) for _ in range(len(data))]
    for idx, (draw_func, out_name, other_arg) in enumerate(data):
        draw_func(img_in, imgs_out[idx], other_arg)
        cv2.imwrite(out_name, imgs_out[idx])
    for idx, img in enumerate(imgs_out[1:], start=1):
        if not np.array_equal(img, imgs_out[0]):
            print("Image index different: {:d}".format(idx))


def main(*argv):
    dt = np.uint8
    shape_in = (32, 32)
    factor_io = 20
    shape_out = tuple(i * factor_io for i in shape_in)
    test_speed(shape_in, shape_out, dtype=dt)
    test_accuracy(shape_in, shape_out, dtype=dt)


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.")
    sys.exit(rc)

注意事项:

> < li>

除了您使用np.nditer的实现(我将它放在一个名为draw_img_orig的函数中)之外,我还创建了另外两个:

>

  • 迭代输入数组的函数(draw_img_regular_iter)

    一个使用缓存圆圈,并通过np.nditer(draw_img_cache)进行迭代

    就测试而言,共有2种方法-每种方法均在上述3种方法中的每种方法上进行:

    >

  • 速度:测量处理大量图像所需的时间

    精度:测量包含区间[0255](4次)的32x32输入的输出

    输出:

    [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q071818080]> sopr.bat
    ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
    
    [prompt]> dir /b
    code00.py
    
    [prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe" code00.py
    Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32
    
    
    Testing draw_img_orig
    Took 0.908 seconds (250 images)
    
    Testing draw_img_regular_iter
    Took 1.061 seconds (250 images)
    
    Testing draw_img_cache
    Took 0.426 seconds (250 images)
    
    Done.
    
    [prompt]>
    [prompt]> dir /b
    cache.png
    code00.py
    orig.png
    regit.png
    

    上面是速度测试结果:如你所见,你的方法用了不到一秒的时间处理了250张图片!!!所以我是对的,我不知道你的慢是从哪里来的,但不是从这里来的(也许你把测量结果弄错了?).< br >常规方法稍慢,而缓存方法快2倍。< br >我在笔记本电脑上运行了代码:

    • 赢得10 pc064
    • CPU:Intel i7 6820HQ@2.70GHz(相当旧)
    • GPU:不相关,因为我在执行期间没有注意到任何尖峰

    关于准确性测试,所有(3)个输出数组都是相同的(没有消息表明不是这样),这里有一个保存的图像:

  •  类似资料:
    • 片段类: 包com.syedabdullah.syed.qran_memorization_application; /***由syed于2014年25日创建。*/ 导入Android.os.bundle;导入android.support.v4.app.fragment;导入Android.View.LayoutInflater;导入Android.view.view;导入Android.Vie

    • 我正在使用GridLayoutManager的回收器视图。我还使用以下代码使第一个项目变大 除了一个以外,其他一切都正常:位置1处的物品(即大图中的下一个物品)被垂直拉长,以匹配大件物品的高度。从第3行开始,所有图像如图所示。 我怎么才能摆脱这个? 编辑:经过一些分析 所以问题似乎是,大图像是水平的两个跨度,但垂直的单个跨度,因为我已经强制我的ImageView是方形的,它看起来像是也取了两行,而

    • 本文向大家介绍python 对一幅灰度图像进行直方图均衡化,包括了python 对一幅灰度图像进行直方图均衡化的使用技巧和注意事项,需要的朋友参考一下 图1:原图的灰度图 图2:进行直方图均衡化后的图像 图3:原图灰度图的直方图 图4:进行直方图均衡化后的直方图 图5:灰度变换函数 以上就是python 对一幅灰度图像进行直方图均衡化的详细内容,更多关于python 直方图均衡化的资料请关注呐喊教

    • 我想知道他们的AndEngine的任何子库可以变形两个不同的图像吗?或者在Android系统中?我一直在找它,但我没有找到任何东西。帮帮我...

    • 目前,我有一个预先训练过的模型,它使用数据加载器读取一批图像来训练模型。 我想对图像进行处理(预测),因为它们是从队列中到达的。它应该类似于读取单个图像并运行模型对其进行预测的代码。大致如下: 我想知道您是否可以指导我如何做到这一点,并在DataLoader中应用相同的转换。

    • 我正在学习JavaFX。我想在几秒钟后一个接一个地显示一些图标。我的代码不起作用。我写了一些代码。和图标存储在一个单独的文件夹称为图像。 我在网上找不到合适的答案。我想知道它是如何完成的逻辑,我还需要知道什么。因为单个图像I可以容易地显示。但是我不知道如何一个接一个地显示多个图像。