Форум программистов, компьютерный форум CyberForum.ru

преобразование bitmap в YCbCr и обратно - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 12, средняя оценка - 5.00
Ermak_nk
6 / 6 / 0
Регистрация: 11.08.2012
Сообщений: 109
09.02.2013, 17:17     преобразование bitmap в YCbCr и обратно #1
Доброго времени суток. Нужно преобразовать изображение из формата 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 и обратно  
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
ValeryS
Модератор
6374 / 4840 / 441
Регистрация: 14.02.2011
Сообщений: 16,043
09.02.2013, 17:25     преобразование bitmap в YCbCr и обратно #2
Цитата Сообщение от 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
проверка лишняя
Ermak_nk
6 / 6 / 0
Регистрация: 11.08.2012
Сообщений: 109
09.02.2013, 18:47  [ТС]     преобразование bitmap в YCbCr и обратно #3
Цитата Сообщение от ValeryS Посмотреть сообщение
или Y делай double
не помогло, все тот же результат, даже когда все переменные, участвующие в вычислениях сделал double

Добавлено через 1 час 4 минуты
почему то неправильно кодируется или восстанавливается красная компонента...
ValeryS
Модератор
6374 / 4840 / 441
Регистрация: 14.02.2011
Сообщений: 16,043
09.02.2013, 18:54     преобразование bitmap в YCbCr и обратно #4
по моему ты наврал с формулами
вот формулы которые используются в телевидении (на память пишу)коэффициенты более грубые

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;
Ermak_nk
6 / 6 / 0
Регистрация: 11.08.2012
Сообщений: 109
09.02.2013, 19:14  [ТС]     преобразование bitmap в YCbCr и обратно #5
Цитата Сообщение от ValeryS Посмотреть сообщение
по моему ты наврал с формулами
вот формулы которые используются в телевидении (на память пишу)коэффициенты более грубые
Формулы брал с википедии. Еще глядел на паре сайтов - вроде теже

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


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

Добавлено через 7 минут
Вполне возможно что формулы не верны, но других я не находил
ValeryS
Модератор
6374 / 4840 / 441
Регистрация: 14.02.2011
Сообщений: 16,043
09.02.2013, 19:18     преобразование bitmap в YCbCr и обратно #6
попробуй сначала с моими формулами
смещение выброси (у тебя 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
Ermak_nk
6 / 6 / 0
Регистрация: 11.08.2012
Сообщений: 109
09.02.2013, 19:31  [ТС]     преобразование bitmap в YCbCr и обратно #7
Цитата Сообщение от ValeryS Посмотреть сообщение
попробуй сначала с моими формулами
ок, попробую (затра), тока надо будет выводить формулы для обратного преобразования (может у вас завалялись такие?)
Цитата Сообщение от ValeryS Посмотреть сообщение
выброси вот эти строки
они могут давать искажения
Без этих строк происходило переполнение, в результате чего искажения белого и черного
ValeryS
Модератор
6374 / 4840 / 441
Регистрация: 14.02.2011
Сообщений: 16,043
09.02.2013, 21:07     преобразование bitmap в YCbCr и обратно #8
Цитата Сообщение от 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 это не выражения это цветоразностный сигнал
Ermak_nk
6 / 6 / 0
Регистрация: 11.08.2012
Сообщений: 109
10.02.2013, 14:04  [ТС]     преобразование bitmap в YCbCr и обратно #9
Цитата Сообщение от 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 и обратно  
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.02.2013, 17:51     преобразование bitmap в YCbCr и обратно
Еще ссылки по теме:

C++ Преобразование TCHAR в double и обратно
Продемонстровать неявное преобразование типов: из целого в вещественный и обратно C++
C++ Преобразование int char и обратно

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

Или воспользуйтесь поиском по форуму:
Ermak_nk
6 / 6 / 0
Регистрация: 11.08.2012
Сообщений: 109
10.02.2013, 17:51  [ТС]     преобразование bitmap в YCbCr и обратно #10
Спасибо всем, кто откликнулся, косяк я нашел - это косоглазие 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 значения...
Yandex
Объявления
10.02.2013, 17:51     преобразование bitmap в YCbCr и обратно
Ответ Создать тему
Опции темы

Текущее время: 02:39. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru