Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.77/22: Рейтинг темы: голосов - 22, средняя оценка - 4.77
8 / 8 / 1
Регистрация: 11.08.2012
Сообщений: 112

Преобразование bitmap в YCbCr и обратно

09.02.2013, 17:17. Показов 4479. Ответов 9
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток. Нужно преобразовать изображение из формата RGB в YCbCr и обратно.
В принципе все работает, но после преобразования цвета искажены. Коэффициенты проверил не один раз - все правильно, кто может подсказать в чем косяк?
(изображение прилагаются, изменен размер, преобразовано в jpg)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
unsigned char* RGBToYCbCr(BITMAPINFOHEADER* bh, unsigned char* lpSurface)
{
    __int16 Y, Cb, Cr;
    int imgData;
    char lnPixel;
    unsigned char r,g,b;
    unsigned char* lpSurface2;
 
    lpSurface2 = new unsigned char[bh->biHeight * bh->biWidth * (bh->biBitCount/8)];
    lnPixel = bh->biBitCount/8;
 
 
    for(int i = 0; i < bh->biHeight/8; i++)//блоки по вертикале
    {
        for(int j = 0; j < bh->biWidth/8; j++)//блоки по горизонтале
        {
            imgData = ((i*8)*bh->biWidth + j*8)*lnPixel; //начальная координата блока
            for(int k = 0; k < 8; k++)//пиксели по вертикале
            {
                for(int l = 0; l < 8; l++)//пиксели по горизонтале
                {
                    r = lpSurface[imgData + k*bh->biWidth*lnPixel + l*lnPixel];
                    g = lpSurface[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 1];
                    b = lpSurface[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 2];
 
                    Y = 0.299*r + 0.587*g + 0.114*b;
                    Cb = 128 - 0.168736*r - 0.331264*g + 0.5*b;
                    Cr = 128 + 0.5*r - 0.418688*g + 0.081312*b;
 
                    if(Y>255) Y=255;
                    else if(Y<0) Y=0;
                    if(Cb>255) Cb=255;
                    else if(Cb<0) Cb=0;
                    if(Cr>255) Cr=255;
                    else if(Cr<0) Cr=0;
 
                    lpSurface2[imgData + k*bh->biWidth*lnPixel + l*lnPixel] = Y;
                    lpSurface2[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 1] = Cb;
                    lpSurface2[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 2] = Cr;
 
                }
            }
        }
    }
 
    delete[] lpSurface;
 
    return lpSurface2;
}
 
 
unsigned char* YCbCrToRGB(BITMAPINFOHEADER* bh, unsigned char* lpSurface)
{
    unsigned char Y, Cb, Cr;
    int imgData;
    char lnPixel;
    __int16 r,g,b;
    unsigned char* lpSurface2;
 
    lpSurface2 = new unsigned char[bh->biHeight * bh->biWidth * (bh->biBitCount/8)];
    lnPixel = bh->biBitCount/8;
 
 
    for(int i = 0; i < bh->biHeight/8; i++)//блоки по вертикале
    {
        for(int j = 0; j < bh->biWidth/8; j++)//блоки по горизонтале
        {
            imgData = ((i*8)*bh->biWidth + j*8)*lnPixel; //накальная координата блока
            for(int k = 0; k < 8; k++)//пиксели по вертикале
            {
                for(int l = 0; l < 8; l++)//пиксели по горизонтале
                {
                    Y = lpSurface[imgData + k*bh->biWidth*lnPixel + l*lnPixel];
                    Cb = lpSurface[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 1];
                    Cr = lpSurface[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 2];
 
                    r = Y + 1.402*(Cr-128);
                    g = Y - 0.34414*(Cb - 128) - 0.71414*(Cr - 128);
                    b = Y + 1.772*(Cb - 128);
 
                    if(r>255) r=255;
                    else if(r<0) r=0;
                    if(g>255) g=255;
                    else if(g<0) g=0;
                    if(b>255) b=255;
                    else if(b<0) b=0;
 
                    lpSurface2[imgData + k*bh->biWidth*lnPixel + l*lnPixel] = r;
                    lpSurface2[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 1] = g;
                    lpSurface2[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 2] = b;
 
                }
            }
        }
    }
 
    delete[] lpSurface;
    return lpSurface2;
}

Заранее спасибо
Миниатюры
Преобразование bitmap в YCbCr и обратно   Преобразование bitmap в YCbCr и обратно  
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
09.02.2013, 17:17
Ответы с готовыми решениями:

Преобразование из YCbCr в RGB
ЧЯДнТ? Формула? Код? Цветовое пространство? :help: #define BYTE uchar void MainWindow::yuv_rgb(BYTE* array, BYTE Y) { BYTE...

Преобразование даты в строку и обратно
написал два метода для класса, первый преобразует дату в строку, а второй наоборот.. проблема со вторым методом.. подсобите если не трудно....

Преобразование TCHAR в double и обратно
Всем привет! Есть TCHAR массив, допустим со значением &quot;12.5&quot;, как его можно преобразовать в double? Пробовал так: TCHAR str; char...

9
Модератор
Эксперт по электронике
8981 / 6748 / 921
Регистрация: 14.02.2011
Сообщений: 23,870
09.02.2013, 17:25
Цитата Сообщение от Ermak_nk Посмотреть сообщение
__int16 Y, Cb, Cr;
Цитата Сообщение от Ermak_nk Посмотреть сообщение
Y = 0.299*r + 0.587*g + 0.114*b;
потеря точности
или работай с целочисленными константами
или Y делай double

Цитата Сообщение от Ermak_nk Посмотреть сообщение
if(Y>255) Y=255;
* * * * * * * * * * else if(Y<0) Y=0;
при правильном преобразовании Y лежит в диапазоне 0-255
проверка лишняя
0
8 / 8 / 1
Регистрация: 11.08.2012
Сообщений: 112
09.02.2013, 18:47  [ТС]
Цитата Сообщение от ValeryS Посмотреть сообщение
или Y делай double
не помогло, все тот же результат, даже когда все переменные, участвующие в вычислениях сделал double

Добавлено через 1 час 4 минуты
почему то неправильно кодируется или восстанавливается красная компонента...
0
Модератор
Эксперт по электронике
8981 / 6748 / 921
Регистрация: 14.02.2011
Сообщений: 23,870
09.02.2013, 18:54
по моему ты наврал с формулами
вот формулы которые используются в телевидении (на память пишу)коэффициенты более грубые

Y=0.29R+0.6G+0.11B
R-Y= 1.0R-(0.29R+0.6G+0.11B)=0.71R-0.6G-0.11B
B-Y=1.0B-(0.29R+0.6G+0.11B)=-0.29R-0.6G+0.89B

B-Y R-Y сигнал двуполярный ну у тебя смешение используется 128
но почему в одном случае + в другом -

Цитата Сообщение от Ermak_nk Посмотреть сообщение
Cb = 128 - 0.168736*r - 0.331264*g + 0.5*b;
Cr = 128 + 0.5*r - 0.418688*g + 0.081312*b;
оба должны быть плюса
проверка простая при белом
R G B равны 1(здесь 255 ) цветоразностные равны 0
при черном R G B равны 0 цветоразностные равны 0

Добавлено через 3 минуты
восстановление
R=R-Y +Y ;
B= B-Y +Y;
0
8 / 8 / 1
Регистрация: 11.08.2012
Сообщений: 112
09.02.2013, 19:14  [ТС]
Цитата Сообщение от ValeryS Посмотреть сообщение
по моему ты наврал с формулами
вот формулы которые используются в телевидении (на память пишу)коэффициенты более грубые
Формулы брал с википедии. Еще глядел на паре сайтов - вроде теже

Цитата Сообщение от ValeryS Посмотреть сообщение
B-Y R-Y сигнал двуполярный ну у тебя смешение используется 128
но почему в одном случае + в другом -
попробовал в обоих случаях +128 - лажа выходит)))


Цитата Сообщение от ValeryS Посмотреть сообщение
проверка простая при белом
при белом после преобразования выходит R=255, G=225, B=255, т.е. уровень зеленого понизился... Т.е. в данном случае можно сделать вывод что косяк именно в самом преобразовании, а не в записи/чтенни.

Добавлено через 7 минут
Вполне возможно что формулы не верны, но других я не находил
0
Модератор
Эксперт по электронике
8981 / 6748 / 921
Регистрация: 14.02.2011
Сообщений: 23,870
09.02.2013, 19:18
попробуй сначала с моими формулами
смещение выброси (у тебя int так что отрицательные значения пройдут)
выброси вот эти строки
они могут давать искажения


Цитата Сообщение от Ermak_nk Посмотреть сообщение
if(Y>255) Y=255;
else if(Y<0) Y=0;
if(Cb>255) Cb=255;
else if(Cb<0) Cb=0;
if(Cr>255) Cr=255;
else if(Cr<0) Cr=0;
если все будет в порядке то постепенно добавляй функционал

Добавлено через 1 минуту
почитаю статью подскажу конкретней
а я забыл добавить
G=Y-R-B
0
8 / 8 / 1
Регистрация: 11.08.2012
Сообщений: 112
09.02.2013, 19:31  [ТС]
Цитата Сообщение от ValeryS Посмотреть сообщение
попробуй сначала с моими формулами
ок, попробую (затра), тока надо будет выводить формулы для обратного преобразования (может у вас завалялись такие?)
Цитата Сообщение от ValeryS Посмотреть сообщение
выброси вот эти строки
они могут давать искажения
Без этих строк происходило переполнение, в результате чего искажения белого и черного
0
Модератор
Эксперт по электронике
8981 / 6748 / 921
Регистрация: 14.02.2011
Сообщений: 23,870
09.02.2013, 21:07
Цитата Сообщение от Ermak_nk Посмотреть сообщение
Без этих строк происходило переполнение, в результате чего искажения белого и черного
переполнения быть не должно
смотри все значения 255
Цитата Сообщение от Ermak_nk Посмотреть сообщение
Y = 0.299*r + 0.587*g + 0.114*b;
Y=0.299*255 + 0.587*255 + 0.114*255= 255*(0.299 + 0.587 + 0.114)=255*1=255;
тем более что Y __int16

Цитата Сообщение от Ermak_nk Посмотреть сообщение
ка надо будет выводить формулы для обратного преобразования (может у вас завалялись такие?)
я же тебе их привел

Цитата Сообщение от ValeryS Посмотреть сообщение
R=R-Y +Y ;
B= B-Y +Y;
Цитата Сообщение от ValeryS Посмотреть сообщение
G=Y-R-B
Добавлено через 1 минуту
R-Y, B-Y это не выражения это цветоразностный сигнал
0
8 / 8 / 1
Регистрация: 11.08.2012
Сообщений: 112
10.02.2013, 14:04  [ТС]
Цитата Сообщение от ValeryS Посмотреть сообщение
попробуй сначала с моими формулами
переписал вашими формулами
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
unsigned char* RGBToYCbCr(BITMAPINFOHEADER* bh, unsigned char* lpSurface)
{
    double Y, Cb, Cr;
    int imgData;
    char lnPixel;
    double r,g,b;
    unsigned char* lpSurface2;
 
    lpSurface2 = new unsigned char[bh->biHeight * bh->biWidth * (bh->biBitCount/8)];
    lnPixel = bh->biBitCount/8;
 
 
    for(int i = 0; i < bh->biHeight/8; i++)//блоки по вертикале
    {
        for(int j = 0; j < bh->biWidth/8; j++)//блоки по горизонтале
        {
            imgData = ((i*8)*bh->biWidth + j*8)*lnPixel; //начальная координата блока
            for(int k = 0; k < 8; k++)//пиксели по вертикале
            {
                for(int l = 0; l < 8; l++)//пиксели по горизонтале
                {
                    r = lpSurface[imgData + k*bh->biWidth*lnPixel + l*lnPixel];
                    g = lpSurface[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 1];
                    b = lpSurface[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 2];
                    /*
                    Y = 0.299*r + 0.587*g + 0.114*b;
                    Cb = 128 - 0.168736*r - 0.331264*g + 0.5*b; 
                    Cr = 128 + 0.5*r - 0.418688*g + 0.081312*b;*/
 
                    Y = 0.29*r+0.6*g+0.11*b;
                    Cr = 0.71*r-0.6*g-0.11*b +128;
                    Cb = -0.29*r-0.6*g+0.89*b +128;
 
                    if(Y>255) Y=255;
                    else if(Y<0) Y=0;
                    if(Cb>255) Cb=255;
                    else if(Cb<0) Cb=0;
                    if(Cr>255) Cr=255;
                    else if(Cr<0) Cr=0;
 
                    lpSurface2[imgData + k*bh->biWidth*lnPixel + l*lnPixel] = Y;
                    lpSurface2[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 1] = Cb;
                    lpSurface2[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 2] = Cr;
 
                }
            }
        }
    }
 
    delete[] lpSurface;
 
    return lpSurface2;
}
 
 
unsigned char* YCbCrToRGB(BITMAPINFOHEADER* bh, unsigned char* lpSurface)
{
    double Y, Cb, Cr;
    int imgData;
    char lnPixel;
    double r,g,b;
    unsigned char* lpSurface2;
 
    lpSurface2 = new unsigned char[bh->biHeight * bh->biWidth * (bh->biBitCount/8)];
    lnPixel = bh->biBitCount/8;
 
 
    for(int i = 0; i < bh->biHeight/8; i++)//блоки по вертикале
    {
        for(int j = 0; j < bh->biWidth/8; j++)//блоки по горизонтале
        {
            imgData = ((i*8)*bh->biWidth + j*8)*lnPixel; //накальная координата блока
            for(int k = 0; k < 8; k++)//пиксели по вертикале
            {
                for(int l = 0; l < 8; l++)//пиксели по горизонтале
                {
                    Y = lpSurface[imgData + k*bh->biWidth*lnPixel + l*lnPixel];
                    Cb = lpSurface[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 1];
                    Cr = lpSurface[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 2];
                    /*
                    r = Y + 1.402*(Cr-128);
                    g = Y - 0.34414*(Cb - 128) - 0.71414*(Cr - 128);
                    b = Y + 1.772*(Cb - 128);*/
                    r = Y + Cr - 128;
                    b = Y + Cb - 128;
                    g = Y - r - b;
 
                    if(r>255) r=255;
                    else if(r<0) r=0;
                    if(g>255) g=255;
                    else if(g<0) g=0;
                    if(b>255) b=255;
                    else if(b<0) b=0;
 
                    lpSurface2[imgData + k*bh->biWidth*lnPixel + l*lnPixel] = r;
                    lpSurface2[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 1] = g;
                    lpSurface2[imgData + k*bh->biWidth*lnPixel + l*lnPixel + 2] = b;
 
                }
            }
        }
    }
 
    delete[] lpSurface;
    return lpSurface2;
}
результат совсем както далек от исходного...


Цитата Сообщение от ValeryS Посмотреть сообщение
тем более что Y __int16
Y то __int16, но вот lpSurface имеет ячейку типа unsigned char так что отрицательные значения туда не пролезут

ЗЫ Забыл сказать, что формулы желательно использовать из спецификации jpeg, ибо преобразование в YCbCr это только первая часть программы
Миниатюры
Преобразование bitmap в YCbCr и обратно  
0
8 / 8 / 1
Регистрация: 11.08.2012
Сообщений: 112
10.02.2013, 17:51  [ТС]
Спасибо всем, кто откликнулся, косяк я нашел - это косоглазие xDDD
в 28-й строке написано
C++
1
Cr = 128 + 0.5*r - 0.418688*g + 0.081312*b;
а надо
C++
1
Cr = 128 + 0.5*r - 0.418688*g - 0.081312*b;
Все остальное было правильно)))

Добавлено через 36 минут
Хотя уровень цветов всеравно отличается от оригинала на 2-3 значения...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
10.02.2013, 17:51
Помогаю со студенческими работами здесь

Преобразование CString->float и обратно
Здравствуйте. Можно ли строку типа CString преобразовать в число типа float (или double) (я уверен, что в строка будет вида 123.123)и...

Преобразование int char и обратно
надо разложить число на два байта... unsigned char ghj; int fff = 11111; ghj = fff / 256; ghj = fff - (ghj * 256); //обратно ...

Преобразование класса в строку и обратно
Всем доброго времени суток. Пишу курсач на плюсах (простенький чат). Обязательным условием является использование классов(плюсы все таки)....

Преобразование типов wchar_t в char и обратно
Добрый вечер уважаемые форумчане! Как можно перевести из wchar_t в char и обратно. Если можно с примерами. За ранее спасибо!! ...

Продемонстровать неявное преобразование типов: из целого в вещественный и обратно
Помогите решить задачи по С++, никак не могу, вся надежда только на вас. 1. Даны вещественные и целые числа. Наглядно продемонстрируйте...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru