繁体   English   中英

有没有更快的方法将 (BGR) OpenCV 图像转换为 CMYK?

[英]Is there no faster way to convert (BGR) OpenCV image to CMYK?

我有一个 OpenCV 图像,像往常一样在 BGR 颜色空间中,我需要将其转换为 CMYK。 我在网上搜索但基本上只发现(略有变化)以下方法:

def bgr2cmyk(cv2_bgr_image):
    bgrdash = cv2_bgr_image.astype(float) / 255.0

    # Calculate K as (1 - whatever is biggest out of Rdash, Gdash, Bdash)
    K = 1 - numpy.max(bgrdash, axis=2)

    with numpy.errstate(divide="ignore", invalid="ignore"):
        # Calculate C
        C = (1 - bgrdash[..., 2] - K) / (1 - K)
        C = 255 * C
        C = C.astype(numpy.uint8)

        # Calculate M
        M = (1 - bgrdash[..., 1] - K) / (1 - K)
        M = 255 * M
        M = M.astype(numpy.uint8)

        # Calculate Y
        Y = (1 - bgrdash[..., 0] - K) / (1 - K)
        Y = 255 * Y
        Y = Y.astype(numpy.uint8)

    return (C, M, Y, K)

这很好用,但是感觉很慢 - 对于 800 x 600 像素的图像,在我的 i7 CPU 上大约需要 30 毫秒。 使用cv2的典型操作(如阈值处理等)只需要几毫秒即可处理同一张图像,所以因为这都是numpy我期待这个 CMYK 转换更快。

但是,我还没有发现任何使这显着变胖的东西。 通过PIL.Image转换为 CMYK,但生成的通道看起来与上面列出的算法不同。

还有其他想法吗?

我将首先分析哪个部分是瓶颈。

例如,如果没有/ (1 - K)计算,它有多快?
-> 预先计算1/(1-K)可能会有所帮助。 甚至可以预先计算255/(1-K)

K = 1 - numpy.max(bgrdash, axis=2)
kRez255=255/(1 - K)

with numpy.errstate(divide="ignore", invalid="ignore"):
    # Calculate C
    C = (1 - bgrdash[..., 2] - K) * kRez255
    C = C.astype(numpy.uint8)

    # Calculate M
    M = (1 - bgrdash[..., 1] - K) * kRez255
    M = M.astype(numpy.uint8)

    # Calculate Y
    Y = (1 - bgrdash[..., 0] - K) * kRez255
    Y = Y.astype(numpy.uint8)

return (C, M, Y, K)

但只有分析才能显示是否是计算减慢了转换速度。

您应该做几件事:

  • 动摇数学
  • 尽可能使用 integer 数学
  • 超出 numpy 可以做的优化
摇晃数学

给定

RGB' = RGB / 255
K = 1 - max(RGB')
C = (1-K - R') / (1-K)
M = (1-K - G') / (1-K)
Y = (1-K - B') / (1-K)

你看看你能排除什么。

RGB' = RGB / 255
J = max(RGB')
K = 1 - J
C = (J - R') / J
M = (J - G') / J
Y = (J - B') / J
Integer 数学

对于这些计算,不要标准化为[0,1] max()可以在整数上完成。 差异也可以。 K可以完全用 integer 数学计算。

J = max(RGB)
K = 255 - J
C = 255 * (J - R) / J
M = 255 * (J - G) / J
Y = 255 * (J - B) / J
努巴
import numba

@numba.njit(parallel=True, error_model="numpy", fastmath=True)
def bgr2cmyk_v4(bgr_img):
    bgr_img = np.ascontiguousarray(bgr_img)
    (height, width) = bgr_img.shape[:2]
    CMYK = np.empty((height, width, 4), dtype=np.uint8)
    for i in numba.prange(height):
        for j in range(width):
            B,G,R = bgr_img[i,j] 
            J = max(R, G, B)
            K = np.uint8(255 - J)
            C = np.uint8(255 * (J - R) / J)
            M = np.uint8(255 * (J - G) / J)
            Y = np.uint8(255 * (J - B) / J)
            CMYK[i,j] = (C,M,Y,K)
    return CMYK

Numba 将优化该代码,而不仅仅是使用 numpy 库例程。 它还将按照指示进行并行化。 选择numpy错误 model 并允许fastmath将导致除以零不会引发异常或警告,但也会使数学运算更快一点。

在我的计算机上,这比您在问题中显示的代码(90 ms -> 2 ms快大约 40 倍

还有什么?

我不确定 numba 是否在其中留下任何浮点操作。 从技术上讲,除法是 python 语义,一个浮点除法,但是用// (整数除法)替换它会使其变慢。

我认为 numba/LLVM 在这里没有应用 SIMD。 一些调查显示 Loop Vectorizer 不喜欢它被要求考虑的任何实例。

OpenCL kernel 可能会更快。 OpenCL 可以在 CPU 上运行。

Numba 也可以使用CUDA

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM