c++ - 使用 opencv 和 LUT 减少颜色深度

标签 c++ opencv colors depth

我想通过颜色深度缩放来减少颜色。

像这个例子: 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);

最佳答案

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

解决这些限制的最佳方法是跨 channel 拆分彩色图像,分别转换每个 channel ,然后将转换后的 channel 合并为新的彩色图像。请看下面的代码:

/*
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;
}

关于c++ - 使用 opencv 和 LUT 减少颜色深度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14812397/

相关文章:

delphi - 在delphi中更改字段值的DBGRID行颜色

C++ - 在基元上运行析构函数?

c++ - 如何编写一个程序来显示一个数是否为质数,并可以显示文件中从 1 到 100 的质数

python - 在 Mac OS X 上使用 pip 安装 pyopencv

c++ - 如何在 Eclipse 中调试 Android 上 OpenCV 示例的 native 代码?

css - 如何使用 CSS 模糊 div 的一侧

java - 如何使用Java Color制作渐变颜色白-棕-绿

c++ - 如何在 dlib 正面面部检测器中拆分级联级别?

c++ - 从 C++ 中与 C 灵活数组成员互操作的正确方法是什么?

python - 读取两个图像作为一个图像Python