Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 12, средняя оценка - 5.00
Ermak_nk
8 / 8 / 0
Регистрация: 11.08.2012
Сообщений: 109
#1

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

09.02.2013, 17:17. Просмотров 1651. Ответов 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;
}

Заранее спасибо
0
Миниатюры
Преобразование bitmap в YCbCr и обратно   Преобразование bitmap в YCbCr и обратно  
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
09.02.2013, 17:17
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Преобразование bitmap в YCbCr и обратно (C++):

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

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

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

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

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

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

9
ValeryS
Модератор
6707 / 5116 / 482
Регистрация: 14.02.2011
Сообщений: 17,191
09.02.2013, 17:25 #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
проверка лишняя
0
Ermak_nk
8 / 8 / 0
Регистрация: 11.08.2012
Сообщений: 109
09.02.2013, 18:47  [ТС] #3
Цитата Сообщение от ValeryS Посмотреть сообщение
или Y делай double
не помогло, все тот же результат, даже когда все переменные, участвующие в вычислениях сделал double

Добавлено через 1 час 4 минуты
почему то неправильно кодируется или восстанавливается красная компонента...
0
ValeryS
Модератор
6707 / 5116 / 482
Регистрация: 14.02.2011
Сообщений: 17,191
09.02.2013, 18:54 #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;
0
Ermak_nk
8 / 8 / 0
Регистрация: 11.08.2012
Сообщений: 109
09.02.2013, 19:14  [ТС] #5
Цитата Сообщение от ValeryS Посмотреть сообщение
по моему ты наврал с формулами
вот формулы которые используются в телевидении (на память пишу)коэффициенты более грубые
Формулы брал с википедии. Еще глядел на паре сайтов - вроде теже

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


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

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

преобразование пользовательского типа в стандартный и обратно, перегрузка оперторов - C++
#ifndef INTEGER_H_ #define INTEGER_H_ class Integer{ public: Integer(int=0); ~Integer(); Integer&amp; operator++(); ...

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

Преобразование текстовых файлов из кодировки DOS в кодировку Windows и обратно - C++
Программа преобразования текстовых файлов из кодировки DOS в кодировку Windows и обратно.

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


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

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru