如何使用 OpenCV 减少图像中的颜色数量?
我有一组图像文件,我想将它们的颜色数量减少到 64 种。我如何使用 OpenCV 来做到这一点?
我需要这个,以便我可以使用 64 尺寸的图像直方图。 我正在实施 CBIR 技术,
我想要的是 4 位调色板的颜色量化。
I have a set of image files, and I want to reduce the number of colors of them to 64. How can I do this with OpenCV?
I need this so I can work with a 64-sized image histogram.
I'm implementing CBIR techniques
What I want is color quantization to a 4-bit palette.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
OpenCV 2 计算机视觉 很好地介绍了这个主题应用程序编程手册:
第 2 章 演出一些归约操作,其中一个在 C++ 中演示,稍后在 Python 中演示:
下面您可以找到该操作的输入图像(左)和输出(右) :
Python 中的等效代码如下:
(归功于 @eliezer-bernart)
This subject was well covered on OpenCV 2 Computer Vision Application Programming Cookbook:
Chapter 2 shows a few reduction operations, one of them demonstrated here in C++ and later in Python:
Below you can find the input image (left) and the output of this operation (right):
The equivalent code in Python would be the following:
(credits to @eliezer-bernart)
您可能会考虑 K 均值,但在这种情况下它很可能会非常慢。更好的方法可能是您自己“手动”执行此操作。假设您有
CV_8UC3
类型的图像,即每个像素由 0 到 255 之间的 3 个 RGB 值表示的图像 (Vec3b
)。您可以将这 256 个值“映射”为仅 4 个特定值,这将产生4 x 4 x 4
=64
可能的颜色。我有一个数据集,我需要确保深色=黑色,浅色=白色,并减少其间所有颜色的数量。这就是我所做的(C++):
导致
[0,64)
变成0
,[64,128)
->64
和[128,255)
->255
,产生27
颜色:对我来说,这似乎比其他答案中提到的任何其他内容都简洁、完全清晰且更快。
您还可以考虑将这些值减少为某个数字的倍数之一,比方说:
这将产生一组 5 个可能的值:
{0, 64, 128, 192, 255}
,即 125颜色。You might consider K-means, yet in this case it will most likely be extremely slow. A better approach might be doing this "manually" on your own. Let's say you have image of type
CV_8UC3
, i.e. an image where each pixel is represented by 3 RGB values from 0 to 255 (Vec3b
). You might "map" these 256 values to only 4 specific values, which would yield4 x 4 x 4
=64
possible colors.I've had a dataset, where I needed to make sure that dark = black, light = white and reduce the amount of colors of everything between. This is what I did (C++):
causing
[0,64)
to become0
,[64,128)
->64
and[128,255)
->255
, yielding27
colors:To me this seems to be neat, perfectly clear and faster than anything else mentioned in other answers.
You might also consider reducing these values to one of the multiples of some number, let's say:
which would yield a set of 5 possible values:
{0, 64, 128, 192, 255}
, i.e. 125 colors.这是使用 K-Means 聚类的 Python 实现颜色量化
cv2.kmeans
。其想法是减少图像中不同颜色的数量,同时尽可能保留图像的颜色外观。结果如下:输入
->
输出代码
Here's a Python implementation of color quantization using K-Means Clustering with
cv2.kmeans
. The idea is to reduce the number of distinct colors in an image while preserving the color appearance of the image as much as possible. Here's the result:Input
->
OutputCode
有很多方法可以做到这一点。 jeff7建议的方法还可以,但有一些缺点:
我喜欢使用基于最高有效位的算法使用 RGB 颜色并将其转换为 64 色图像。如果您使用的是 C/OpenCV,则可以使用类似下面的函数。
如果您正在处理灰度图像,我建议使用 OpenCV 2.3 的 LUT() 函数,因为它更快。有一个关于如何使用LUT来减少颜色数量的教程。请参阅:教程:如何扫描图像、查找表...但是我找到了它如果您使用 RGB 图像,情况会更复杂。
There are many ways to do it. The methods suggested by jeff7 are OK, but some drawbacks are:
I like to use an algorithm based on the Most Significant Bits to use in a RGB color and convert it to a 64 color image. If you're using C/OpenCV, you can use something like the function below.
If you're working with gray-level images I recommed to use the LUT() function of the OpenCV 2.3, since it is faster. There is a tutorial on how to use LUT to reduce the number of colors. See: Tutorial: How to scan images, lookup tables... However I find it more complicated if you're working with RGB images.
这里建议的答案非常好。我想我也应该添加我的想法。我遵循这里许多评论的表述,其中据说 RGB 图像中每个通道的 2 位可以表示 64 种颜色。
下面代码中的函数将图像和量化所需的位数作为输入。它使用位操作来“丢弃”LSB 位并仅保留所需的位数。结果是一种灵活的方法,可以将图像量化为任意位数。
以下是上述函数调用中使用的图像:
每个 RGB 通道量化为 2 位的图像(总共 64 种颜色):
每个通道 3 位:
4 位...
The answers suggested here are really good. I thought I would add my idea as well. I follow the formulation of many comments here, in which it is said that 64 colors can be represented by 2 bits of each channel in an RGB image.
The function in code below takes as input an image and the number of bits required for quantization. It uses bit manipulation to 'drop' the LSB bits and keep only the required number of bits. The result is a flexible method that can quantize the image to any number of bits.
Here is an image that is used in the above function call:
Image quantized to 2 bits for each RGB channel (Total 64 Colors):
3 bits for each channel:
4 bits ...
OpenCV 库中已经提供了 K 均值聚类算法。简而言之,它确定围绕用户定义的 k 值(= 簇数)对数据进行聚类的最佳质心。因此,在您的情况下,您可以找到围绕给定 k=64 值对像素值进行聚类的质心。如果你谷歌一下,详细信息就在那里。 这里是 k-means 的简短介绍。
SO 使用 k-means,希望有帮助。
另一种方法是使用金字塔均值偏移OpenCV 中的过滤器 函数。它产生的图像有些“扁平化”,即颜色数量较少,因此它可能会对您有所帮助。
There is the K-means clustering algorithm which is already available in the OpenCV library. In short it determines which are the best centroids around which to cluster your data for a user-defined value of k ( = no of clusters). So in your case you could find the centroids around which to cluster your pixel values for a given value of k=64. The details are there if you google around. Here's a short intro to k-means.
Something similar to what you are probably trying was asked here on SO using k-means, hope it helps.
Another approach would be to use the pyramid mean shift filter function in OpenCV. It yields somewhat "flattened" images, i.e. the number of colors are less so it might be able to help you.
如果您想要 C++ 中的快速而肮脏的方法,请在 1 行中:
因此,它所做的就是保留每个 R、G、B 分量的高 2 位,并丢弃低 6 位,即 0b11000000。
由于 RGB 有 3 个通道,因此您最多可以获得 4 R x 4 B x 4 B = 最多 64 种颜色。这样做的优点是您可以在任意数量的图像上运行它,并且将映射相同的颜色。
请注意,这可能会使您的图像变得更暗,因为它会丢弃一些位。
对于灰度图像,您可以这样做:
这将保留高 6 位,这意味着您将获得 256 个灰度中的 64 个灰度,并且图像也会变得更暗一些。
这是一个例子,原始图像 = 251424 种独特的颜色。
生成的图像有 46 种颜色:
If you want a quick and dirty method in C++, in 1 line:
So, what it does is keep the upper 2 bits of each R, G, B component, and discards the lower 6 bits, hence the 0b11000000.
Because of the 3 channels in RGB, you get maximum 4 R x 4 B x 4 B = max 64 colors. The advantage of doing this is that you can run this on any number of images and the same colors will be mapped.
Note that this can make your image a bit darker since it discards some bits.
For a greyscale image, you can do:
This will keep the upper 6 bits, which means you get 64 grays out of 256, and again the image can become a bit darker.
Here's an example, original image = 251424 unique colors.
And the resulting image has 46 colors:
假设您想对所有图像使用相同的 64 种颜色(即调色板未针对每个图像进行优化),我至少可以想到几个选择:
1) 转换为 Lab 或 YCrCb 色彩空间并使用 N 位进行亮度量化每个颜色通道为 M 位,N 应大于 M。
2) 计算所有训练图像的颜色值的 3D 直方图,然后选择具有最大 bin 值的 64 种颜色。通过为每个像素分配训练集中最接近的 bin 的颜色来量化图像。
方法 1 是最通用且最容易实现的,而方法 2 可以更好地适合您的特定数据集。
更新:
例如,32 种颜色为 5 位,因此将 3 位分配给亮度通道,将 1 位分配给每个颜色通道。要进行此量化,请将亮度通道除以 2^8/2^3 = 32,将每个颜色通道除以 2^8/2^1 = 128。现在只有 8 个不同的亮度值和 2 个不同的颜色通道每个。通过位移或数学运算将这些值重新组合成单个整数(量化颜色值 = 亮度*4+颜色1*2+颜色2);
Assuming that you want to use the same 64 colors for all images (ie palette not optimized per image), there are a at least a couple choices I can think of:
1) Convert to Lab or YCrCb colorspace and quantize using N bits for luminance and M bits for each color channel, N should be greater than M.
2) Compute a 3D histogram of color values over all your training images, then choose the 64 colors with the largest bin values. Quantize your images by assigning each pixel the color of the closest bin from the training set.
Method 1 is the most generic and easiest to implement, while method 2 can be better tailored to your specific dataset.
Update:
For example, 32 colors is 5 bits so assign 3 bits to the luminance channel and 1 bits to each color channel. To do this quantization, do integer division of the luminance channel by 2^8/2^3 = 32 and each color channel by 2^8/2^1 = 128. Now there are only 8 different luminance values and 2 different color channels each. Recombine these values into a single integer doing bit shifting or math (quantized color value = luminance*4+color1*2+color2);
一个简单的按位和适当的位掩码就可以解决问题。
python,对于 64 种颜色,
RGB 图像的颜色数量应该是一个完美的立方体(3 个通道相同)。
对于此方法,通道的可能值的数量应为 2 的幂。(代码忽略此检查,并采用下一个较低的 2 幂)
A simple bitwise and with a proper bitmask would do the trick.
python, for 64 colors,
The number of colors for an RGB image should be a perfect cube (same across 3 channels).
For this method, the number of possible values for a channel should be a power of 2. (This check is ignored by the code and the next lower power of 2 is taken by it)
img = numpy.multiply(img//32, 32)
img = numpy.multiply(img//32, 32)
nQuantGpp 包括用于 g++ 生成高质量优化图像的前 10 种颜色量化算法。它从 nQuantCpp 移植到 OpenCV,以利用此类流行库的深度学习功能。
通过基于 Fast PNN 的算法减少到 64 色
通过使用 CIELAB 色彩空间的基于快速 PNN 的算法将 64 种颜色减少到 64 种颜色
通过 NeuQuant 神经网络量化算法将 64 种颜色减少到 64 种颜色
通过高效、边缘感知、组合颜色量化和抖动减少至 64 种颜色CIELAB 色彩空间
通过 Xialoin Wu 的快速最佳色彩减少到 64 种颜色量化算法
最后,CBIR技术最本质的方法应该是OTSU方法(OTSU),它是一种全局自适应二值化阈值图像分割算法。然后,通过从图像数据集中有效提取特征向量来将图像分类为有意义的类别一直依赖于特征选择技术。
nQuantGpp includes top 10 color quantization algorithms for g++ producing high quality optimized images. It is ported from nQuantCpp which migrates to OpenCV to leverage the deep learning features of such popular library.
Reduced to 64 colors by Fast PNN based algorithm
Reduced to 64 colors by Fast PNN based algorithm with CIELAB color space
Reduced to 64 colors by NeuQuant Neural-Net Quantization Algorithm
Reduced to 64 colors by Efficient, Edge-Aware, Combined Color Quantization and Dithering with CIELAB color space
Reduced to 64 colors by Xialoin Wu's fast optimal color Quantization Algorithm
Finally, the most essential method for CBIR techniques should be the OTSU method (OTSU) which is a global adaptive binarization threshold image segmentation algorithm. Then categorization of images into meaningful classes by efficient extraction of feature vectors from image datasets has been dependent on feature selection techniques.
为什么不直接进行矩阵乘法/除法呢?值将自动四舍五入。
伪代码:
完成。每个通道现在仅包含 64 种颜色。
Why don't you just do Matrix multiplication/division? Values will be automatically rounded.
Pseudocode:
Done. Each channel now only contains 64 colors.