我有一个OpenCV图像,像往常一样在BGR colored颜色 空间中,我需要将它转换为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)

这很好用,但感觉相当慢--对于800x600px的图像,在我的i7CPU上大约需要30毫秒.对于相同的图像,典型的cv2操作(如阈值处理和类似操作)只需要几毫秒,所以由于这是所有的numpy,所以我预计这个CMYK转换会更快.

然而,我还没有发现任何能让这一点显著增加的因素.可以通过PIL.Image转换为CMYK,但得到的通道看起来与上面列出的算法不同.

还有别的主意吗?

推荐答案

您应该做几件事:

  • 动摇数学
  • 尽可能使用整数数学
  • 超越NumPy所能做的优化
Shaking the math

vt.给出

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 math

对于这些计算,不要将其正常化为[0,1].max()可以在整数上完成.这种差异也可能存在.K可以用整数数学来计算entirely.

J = max(RGB)
K = 255 - J
C = 255 * (J - R) / J
M = 255 * (J - G) / J
Y = 255 * (J - B) / J
Numba
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库 routine .它还将执行指定的并行化. Select numpy错误模型并允许fastmath将导致被零除,从而不会引发异常或警告,但也会使计算速度更快.

在我的电脑上,这比您在问题中显示的代码(90ms->;2 ms)执行了大约40x faster倍.

What else?

我不确定Numba是否在其中保留了任何浮点运算.从技术上讲,按照Python语义,除法是一个浮点数除法,但是用//(整数除法)代替它会使除法速度变慢.

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

一个OpenCL的内核可能会更快.OpenCL可以在CPU上运行.

Numba can also use CUDA.

Python相关问答推荐

线性模型PanelOLS和statmodels OLS之间的区别

如何在具有重复数据的pandas中对groupby进行总和,同时保留其他列

非常奇怪:tzLocal.get_Localzone()基于python3别名的不同输出?

可变参数数量的重载类型(args或kwargs)

管道冻结和管道卸载

如何在给定的条件下使numpy数组的计算速度最快?

删除marplotlib条形图上的底边

需要帮助重新调整python fill_between与数据点

判断solve_ivp中的事件

Geopandas未返回正确的缓冲区(单位:米)

通过追加列表以极向聚合

如何重新组织我的Pandas DataFrame,使列名成为列值?

按条件添加小计列

裁剪数字.nd数组引发-ValueError:无法将空图像写入JPEG

极柱内丢失类型信息""

Pandas:将值从一列移动到适当的列

我怎么才能用拉夫分拣呢?

将字节序列解码为Unicode字符串

PYTHON中的selenium不会打开 chromium URL

pyspark where子句可以在不存在的列上工作