2013-02-11 56 views
6

我想通过颜色深度缩放来减少颜色。使用opencv和LUT减少颜色深度

喜欢这个例子: enter image description here

第一图像是CGA分辨率,第二个是EGA,第三是HAM。 我想用cv :: LUT来做,因为我认为这是更好的选择。 我可以做灰度与此代码:

Mat img = imread("test1.jpg", 0); 
uchar* p; 
Mat lookUpTable(1, 256, CV_8U); 
p = lookUpTable.data; 
for(int i = 0; i < 256; ++i) 
    p[i] = 16 * (i/16) 
LUT(img, lookUpTable, reduced); 

原:enter image description here

退色:enter image description here

,但如果我试图用颜色做我得到了奇怪的结果..

enter image description here

与此代码:

imgColor = imread("test1.jpg"); 
Mat reducedColor; 
int n = 16; 
for (int i=0; i<256; i++) { 
    uchar value = floor(i/n) * n; 
    cout << (int)value << endl; 
    lut.at<Vec3b>(i)[2]= (value >> 16) & 0xff; 
    lut.at<Vec3b>(i)[1]= (value >> 8) & 0xff; 
    lut.at<Vec3b>(i)[0]= value & 0xff; 
} 
LUT(imgColor, lut, reducedColor); 

回答

3

您现在可能已经移动了,但问题的根源在于您正在对uchar value(仅8位长)进行16位移位。在这种情况下,即使是8位的移位也太多了,因为您将删除uchar中的所有位。然后有一个事实,cv::LUT documentation明确指出src必须是“8位元素的输入数组”,在您的代码中显然不是这种情况。最终结果是只有彩色图像的第一个通道(蓝色通道)被cv::LUT转换。

解决这些限制的最佳方法是在各个通道上分割彩色图像,分别转换每个通道,然后将转换后的通道合并为一个新的彩色图像。见下面的代码:

/* 
Calculates a table of 256 assignments with the given number of distinct values. 

Values are taken at equal intervals from the ranges [0, 128) and [128, 256), 
such that both 0 and 255 are always included in the range. 
*/ 
cv::Mat lookupTable(int levels) { 
    int factor = 256/levels; 
    cv::Mat table(1, 256, CV_8U); 
    uchar *p = table.data; 

    for(int i = 0; i < 128; ++i) { 
     p[i] = factor * (i/factor); 
    } 

    for(int i = 128; i < 256; ++i) { 
     p[i] = factor * (1 + (i/factor)) - 1; 
    } 

    return table; 
} 

/* 
Truncates channel levels in the given image to the given number of 
equally-spaced values. 

Arguments: 

image 
    Input multi-channel image. The specific color space is not 
    important, as long as all channels are encoded from 0 to 255. 

levels 
    The number of distinct values for the channels of the output 
    image. Output values are drawn from the range [0, 255] from 
    the extremes inwards, resulting in a nearly equally-spaced scale 
    where the smallest and largest values are always 0 and 255. 

Returns: 

Multi-channel images with values truncated to the specified number of 
distinct levels. 
*/ 
cv::Mat colorReduce(const cv::Mat &image, int levels) { 
    cv::Mat table = lookupTable(levels); 

    std::vector<cv::Mat> c; 
    cv::split(image, c); 
    for (std::vector<cv::Mat>::iterator i = c.begin(), n = c.end(); i != n; ++i) { 
     cv::Mat &channel = *i; 
     cv::LUT(channel.clone(), table, channel); 
    } 

    cv::Mat reduced; 
    cv::merge(c, reduced); 
    return reduced; 
} 
+1

从哪里我可以得到LUT的完整理解和使用?我看到了opencv文档,但它对语法非常严格。如果要保存此“LUT图像”的值并想将其应用于其他相同的值,您该做什么 – AHF 2014-05-19 22:06:16

+1

LUT的目的是根据查找表更改图像的颜色。这可能有多种目的,如降低颜色分辨率作为图像分割中的预处理步骤。有关其他信息,请参见此维基百科文章:http://en.wikipedia.org/wiki/Colour_look-up_table – xperroni 2014-05-20 02:02:54

+0

至于对不同的图像应用相同的LUT转换,您可以修改上面的'colorReduce()'函数以接受引用查找表作为参数,然后在单独调用'lookupTable()'或其他您认为合适的方法的情况下计算表。 – xperroni 2014-05-20 02:04:19

0

in都是整数,因此i/n是整数。也许你想在发言之前将它转换成双倍((double)i/n),并乘以n

+0

你的答案如何解释所有蓝色? – nkint 2013-02-11 20:05:10

+0

那个uchar有多少个字节?你至少假设3个字节;即使它是宽字符,它仍然应该是2个字节,而不是3个或更多。 – 2013-02-11 21:30:57