уменьшение глубины цвета с помощью opencv и LUT

Я хотел бы выполнить уменьшение цвета с помощью масштабирования глубины цвета.

Как этот пример:
введите описание изображения здесь

первое изображение — разрешение 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);

оригинал:введите описание изображения здесь

цвет уменьшен: введите описание изображения здесь

но если я пытаюсь сделать это с цветом, я получаю странный результат ..

введите описание изображения здесь

с этим кодом:

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);

6

Решение

Вы, вероятно, уже продвинулись, но корень проблемы в том, что вы делаете 16-битный переход на uchar valueдлиной всего 8 бит. Даже 8-битное смещение в этом случае слишком много, так как вы сотрете все биты в uchar, Тогда есть тот факт, что cv::LUT документация прямо заявляет, что 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;
}
3

Другие решения

И то и другое i а также n являются целыми числами, поэтому i/n является целым числом Возможно, вы хотите, чтобы он был преобразован в двойной ((double)i/n) перед тем как взять слово и умножить на n?

0

По вопросам рекламы [email protected]