Fel*_*mel 21 opencv colors image-processing cbir
我有一组图像文件,我想将它们的颜色数减少到64.我怎么能用OpenCV做到这一点?
我需要这个,所以我可以使用64大小的图像直方图.我正在实施CBIR技术
我想要的是4位调色板的颜色量化.
kar*_*lip 12
这个主题在OpenCV 2计算机视觉应用程序设计指南中得到了很好的介绍:

第2章展示了一些简化操作,其中一个在C++中演示:
#include <iostream>
#include <vector>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
void colorReduce(cv::Mat& image, int div=64)
{
int nl = image.rows; // number of lines
int nc = image.cols * image.channels(); // number of elements per line
for (int j = 0; j < nl; j++)
{
// get the address of row j
uchar* data = image.ptr<uchar>(j);
for (int i = 0; i < nc; i++)
{
// process each pixel
data[i] = data[i] / div * div + div / 2;
}
}
}
int main(int argc, char* argv[])
{
// Load input image (colored, 3-channel, BGR)
cv::Mat input = cv::imread(argv[1]);
if (input.empty())
{
std::cout << "!!! Failed imread()" << std::endl;
return -1;
}
colorReduce(input);
cv::imshow("Color Reduction", input);
cv::imwrite("output.jpg", input);
cv::waitKey(0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
您可以在下面找到输入图像(左)和此操作的输出(右):

Lih*_*ihO 11
您可能会考虑K-means,但在这种情况下,它很可能会非常慢.更好的方法可能是自己"手动"执行此操作.假设您有类型CV_8UC3的图像,即每个像素由0到255(Vec3b)的3个RGB值表示的图像.您可以将这256个值"映射"为仅4个特定值,这将产生4 x 4 x 4= 64可能的颜色.
我有一个数据集,我需要确保暗=黑,亮=白,并减少之间的所有颜色的数量.这就是我做的(C++):
inline uchar reduceVal(const uchar val)
{
if (val < 64) return 0;
if (val < 128) return 64;
return 255;
}
void processColors(Mat& img)
{
uchar* pixelPtr = img.data;
for (int i = 0; i < img.rows; i++)
{
for (int j = 0; j < img.cols; j++)
{
const int pi = i*img.cols*3 + j*3;
pixelPtr[pi + 0] = reduceVal(pixelPtr[pi + 0]); // B
pixelPtr[pi + 1] = reduceVal(pixelPtr[pi + 1]); // G
pixelPtr[pi + 2] = reduceVal(pixelPtr[pi + 2]); // R
}
}
}
Run Code Online (Sandbox Code Playgroud)
导致[0,64)变成0,[64,128)- > 64和[128,255)- > 255,产生27颜色:

对我而言,这似乎比其他答案中提到的任何其他内容更整洁,更清晰,更快速.
您也可以考虑将这些值减少到某个数字的倍数之一,让我们说:
inline uchar reduceVal(const uchar val)
{
if (val < 192) return uchar(val / 64.0 + 0.5) * 64;
return 255;
}
Run Code Online (Sandbox Code Playgroud)
这将产生一组5个可能的值:{0, 64, 128, 192, 255},即125种颜色.
Moa*_*nti 10
有很多方法可以做到这一点.jeff7建议的方法没问题,但有些缺点是:
我喜欢使用基于最高有效位的算法来使用RGB颜色并将其转换为64色图像.如果您正在使用C/OpenCV,您可以使用类似下面的功能.
如果您正在使用灰度图像,我建议使用OpenCV 2.3的LUT()函数,因为它更快.有一个关于如何使用LUT减少颜色数量的教程.请参阅:教程:如何扫描图像,查找表...但是,如果您使用的是RGB图像,我会发现它更复杂.
void reduceTo64Colors(IplImage *img, IplImage *img_quant) {
int i,j;
int height = img->height;
int width = img->width;
int step = img->widthStep;
uchar *data = (uchar *)img->imageData;
int step2 = img_quant->widthStep;
uchar *data2 = (uchar *)img_quant->imageData;
for (i = 0; i < height ; i++) {
for (j = 0; j < width; j++) {
// operator XXXXXXXX & 11000000 equivalent to XXXXXXXX AND 11000000 (=192)
// operator 01000000 >> 2 is a 2-bit shift to the right = 00010000
uchar C1 = (data[i*step+j*3+0] & 192)>>2;
uchar C2 = (data[i*step+j*3+1] & 192)>>4;
uchar C3 = (data[i*step+j*3+2] & 192)>>6;
data2[i*step2+j] = C1 | C2 | C3; // merges the 2 MSB of each channel
}
}
}
Run Code Online (Sandbox Code Playgroud)
这里建议的答案确实很好。我以为我也会补充我的想法。在这里,我遵循许多评论的提法,据说可以用RGB图像中每个通道的2位来表示64种颜色。
下面代码中的函数将图像和量化所需的位数作为输入。它使用位操作来“丢弃” LSB位,并仅保留所需数量的位。结果是一种灵活的方法,可以将图像量化为任意数量的位。
#include "include\opencv\cv.h"
#include "include\opencv\highgui.h"
// quantize the image to numBits
cv::Mat quantizeImage(const cv::Mat& inImage, int numBits)
{
cv::Mat retImage = inImage.clone();
uchar maskBit = 0xFF;
// keep numBits as 1 and (8 - numBits) would be all 0 towards the right
maskBit = maskBit << (8 - numBits);
for(int j = 0; j < retImage.rows; j++)
for(int i = 0; i < retImage.cols; i++)
{
cv::Vec3b valVec = retImage.at<cv::Vec3b>(j, i);
valVec[0] = valVec[0] & maskBit;
valVec[1] = valVec[1] & maskBit;
valVec[2] = valVec[2] & maskBit;
retImage.at<cv::Vec3b>(j, i) = valVec;
}
return retImage;
}
int main ()
{
cv::Mat inImage;
inImage = cv::imread("testImage.jpg");
char buffer[30];
for(int i = 1; i <= 8; i++)
{
cv::Mat quantizedImage = quantizeImage(inImage, i);
sprintf(buffer, "%d Bit Image", i);
cv::imshow(buffer, quantizedImage);
sprintf(buffer, "%d Bit Image.png", i);
cv::imwrite(buffer, quantizedImage);
}
cv::waitKey(0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是上述函数调用中使用的图像:
每个RGB通道量化为2位的图像(总共64种颜色):
每个通道3位:
4位...
这是使用 K-Means Clustering 和cv2.kmeans. 这个想法是减少图像中不同颜色的数量,同时尽可能地保留图像的颜色外观。结果如下:
输入->输出

代码
import cv2
import numpy as np
def kmeans_color_quantization(image, clusters=8, rounds=1):
h, w = image.shape[:2]
samples = np.zeros([h*w,3], dtype=np.float32)
count = 0
for x in range(h):
for y in range(w):
samples[count] = image[x][y]
count += 1
compactness, labels, centers = cv2.kmeans(samples,
clusters,
None,
(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10000, 0.0001),
rounds,
cv2.KMEANS_RANDOM_CENTERS)
centers = np.uint8(centers)
res = centers[labels.flatten()]
return res.reshape((image.shape))
image = cv2.imread('1.jpg')
result = kmeans_color_quantization(image, clusters=8)
cv2.imshow('result', result)
cv2.waitKey()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
28639 次 |
| 最近记录: |