Adobe Photoshop风格的色调分离和OpenCV

14
似乎Adobe Photoshop通过分别对每个颜色通道进行量化来实现分色效果,基于指定的级别数量。例如,如果您指定2个级别,则会取R值,并将其设置为0(如果您的R值小于128)或255(如果值大于等于128)。它也会对G和B执行相同的操作。
除了迭代每个像素并进行比较并单独设置值之外,是否有一种有效的方法在python中使用OpenCV进行此操作?由于OpenCV 2.4中的图像是NumPy ndarray,因此是否有一种可能严格通过NumPy进行这种计算的有效方法?

1
嗨,为所有级别添加了通用答案。 - Abid Rahman K
Python Wand是基于Imagemagick的,具有类似于Photoshop的色调分离命令。请参阅http://docs.wand-py.org/en/0.5.7/wand/image.html以获取海报化效果。 - fmw42
5个回答

18

你的问题似乎特别关注2级。但是,如果要处理超过2级的级别呢?因此,我添加了下面的代码,可以使任何级别的颜色进行色调分离。

import numpy as np
import cv2

im = cv2.imread('messi5.jpg')

n = 2    # Number of levels of quantization

indices = np.arange(0,256)   # List of all colors 

divider = np.linspace(0,255,n+1)[1] # we get a divider

quantiz = np.int0(np.linspace(0,255,n)) # we get quantization colors

color_levels = np.clip(np.int0(indices/divider),0,n-1) # color levels 0,1,2..

palette = quantiz[color_levels] # Creating the palette

im2 = palette[im]  # Applying palette on image

im2 = cv2.convertScaleAbs(im2) # Converting image back to uint8

cv2.imshow('im2',im2)
cv2.waitKey(0)
cv2.destroyAllWindows()

这段代码使用了 Numpy 中的 调色板方法(palette method),比逐个迭代像素点更快。你可以在这里找到更多关于如何使用它来加速代码的详细信息:Numpy 中的快速数组操作

下面是我得到的不同级别的结果:

原始图片:

enter image description here

级别 2 :

enter image description here

级别 4 :

enter image description here

级别 8 :

enter image description here

等等...


我正在尝试将其转换为C++,如何量化颜色? - AHF
1
首先你需要在等级之间找到一个数字。例如,如果有2个等级,则取127来分割颜色。然后所有颜色变为0和1。如果有3个等级,则取85等数字。然后分割就会得到0、1、2。然后你可以将它们扩展到0、127、255等。 - Abid Rahman K

10

我们可以使用numpy非常整洁地完成这个任务,而不必担心通道!

import cv2
im = cv2.imread('1_tree_small.jpg')
im[im >= 128]= 255
im[im < 128] = 0
cv2.imwrite('out.jpg', im)

输出:

在这里输入图像描述

输入:

在这里输入图像描述


哇,太棒了,谢谢!我对numpy完全是个新手,我没想到它这么强大,我得深入研究一下!再次感谢! - steve8918
如果您想将此用作艺术或风格效果,我强烈建议先对图像应用高斯模糊,这将清除锯齿边缘。之后可以再次使用较小的内核应用模糊以进行反走样处理。 - user4674018

2

2

使用cv::LUT()函数。这是最简单和最快的方法。

cv::Mat posterize(const cv::Mat &bgrmat, uint8_t lvls)
{
    cv::Mat lookUpTable(1, 256, CV_8U);
    uchar* p = lookUpTable.ptr();
    float step = 255.0f / lvls;
    for(int i = 0; i < 256; ++i)
        p[i] = static_cast<uchar>(step * std::floor(i / step));
    cv::Mat omat;
    cv::LUT(bgrmat,lookUpTable,omat);
    return omat;
}

1

fraxel的n个答案级别进行泛化

import cv2 as cv
import matplotlib.pyplot as plt

im = cv.imread("Lenna.png") 

n = 5

for i in range(n):
    im[(im >= i*255/n) & (im < (i+1)*255/n)] = i*255/(n-1)

plt.imshow(cv.cvtColor(im, cv.COLOR_BGRA2RGB))
plt.show()

n = 2

enter image description here

n = 5

Output with n=5


嗨,Pierre,欢迎来到“StackOverFlow”社区。感谢您的答案,但最好解释一下为什么您的答案是改进版本的答案。祝一切顺利。 - Behdad Abdollahi Moghadam
更好的方式是提供一些示例。 - Pierre Debaisieux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接