Работал с камерой, от которой получал картинку — буффер и его длину. Проблема в том, что картинка с камеры
идет в формате i420..экономит канал...нодо конвертнуть i420 в RGB. Изучив информацию, которая приводится на www.fourcc.org
набросал код, который вроде бы должен работать...и он работает, но картинка частично "плывет". Возможно кто-нибудь уже сталкивался с такой проблемой..и если да — имеет кусок кода осуществляющего данное преобразование. В любом случае, привожу код, посмотрите — может у Вас получится увидеть ошибку, которую не вижу я.
Заранее благодарен.
struct TM_YUV
{
TM_YUV(){ Y=0; U=0; V=0; };
BYTE Y;
BYTE U;
BYTE V;
};
//---------------------------------------------------------------------------struct TM_RGB24
{
TM_RGB24(){ R=0; G=0; B=0; };
BYTE R;
BYTE G;
BYTE B;
};
//---------------------------------------------------------------------------
пример набросан в среде борланд с++ билдер 6.0
void __fastcall TForm1::BitBtn1Click(TObject *Sender)
{
Graphics::TBitmap* bmp = new Graphics::TBitmap();
bmp->Width = 352;
bmp->Height = 288;
bmp->PixelFormat = pf24bit;
vector<BYTE> i420; // данные формата i420
vector<TM_YUV> yuv; // данные формата YUV
vector<TM_RGB24> rgb; // данные RGB
// в файле "i420image.dat" содержатся данные одной картники формата i420
TFileStream* fs = new TFileStream( ExtractFilePath(Application->ExeName) + "i420image.dat", fmOpenRead );
i420.resize( fs->Size );
fs->Read( i420.begin(), fs->Size );
delete fs;
yuv.resize(bmp->Width*bmp->Height);
// Переписали все компоненты яркости, в данном формате их по каждой на пикселfor( int i = 0; i < bmp->Width*bmp->Height; i++ )
{
yuv[i].Y = i420[i];
}
int Counter = 0;
// Теперь компоненты цветоразностей, они одинаковы в каждом макропикселе, который представляет собой квадрат размером 2х2 пикселаfor( int i = 0; i < bmp->Width*bmp->Height/4; i++ )
{
yuv[Counter].U =
yuv[Counter + 1].U =
yuv[Counter + bmp->Width].U =
yuv[Counter + bmp->Width + 1].U = i420[bmp->Width*bmp->Height + i];
yuv[Counter].V =
yuv[Counter + 1].V =
yuv[Counter + bmp->Width].V =
yuv[Counter + bmp->Width + 1].V = i420[bmp->Width*bmp->Height + i + bmp->Width*bmp->Height/4];
Counter += 2;
if( Counter%bmp->Width == 0 )
if( (Counter/bmp->Width)%2 != 0 )
Counter += bmp->Width;
}
// теперь конфертнем из YUV в RGB
rgb.resize( bmp->Width*bmp->Height );
for( int i = 0; i < rgb.size(); i++ )
{
rgb[i].B = 1.164*(yuv[i].Y - 16) + 2.018*(yuv[i].U - 128);
rgb[i].G = 1.164*(yuv[i].Y - 16) - 0.813*(yuv[i].V - 128) - 0.391*(yuv[i].U - 128);
rgb[i].R = 1.164*(yuv[i].Y - 16) + 1.596*(yuv[i].V - 128);
}
// выведем на канву формыfor( int y = 0; y < bmp->Height; y++ )
{
Byte* ptr = (Byte*)bmp->ScanLine[y];
int c=0;
for(int x = 0; x < bmp->Width; x++)
{
ptr[c] = rgb[y*bmp->Width + x].B;
ptr[c+1] = rgb[y*bmp->Width + x].G;
ptr[c+2] = rgb[y*bmp->Width + x].R;
c+=3;
}
}
Canvas->Draw( 0, 0, bmp );
delete bmp;
}
Здравствуйте, Sinyagin Dmitry, Вы писали:
SD>уволил бы за такой код
ответ не в тему
давайте не будем ссоритться, ибо меня интересует в первую очередь корректность алгоритма преобразования...
или Вы где-нибудь в моем вопросе встретили фразу — :"мужчины, оцените мой код!?"
Код не претендует ни коим образом!!! на гениальность и ясен — не оптимизирован...он реализует определенную
последовательность действий по шагам так, чтобы человек знакомый с методикой i429->RGB смог достаточно
быстро прикинуть где я ошибся.
Смею Вас уверить нмкогда и никуда в таком виде код не пойдет.
Одно могу сказать точно — читать Ваш ответ мне было неприянто.
Я сказал все.
ЗЫ.Если Вы не удовлетворены моими объяснениями, или считаете что я возмутился несправедливо —
может продолжить дискуссию по эл. почте.
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, temofey, Вы писали:
CS>Что такое "плывет"?
CS>На вскидку: если имеем дело с Windows 24bpp bitmap CS>то там есть специфика — каждый pixel row должен содержать кол-во байтов кратное 4.
да, об этом позаботился...размер картинки 352х288...24 бит на пиксель
около 70% картинки декодируется нормально...замечена такая закономерность:
там, где слишком "светло" цвет перебрасывается в черный.
там, где слишком "темно" цвет перебрасывается в зеленый.
кое-где появляются небольшие пятна желтого...
если отбросить компоненты цветоразности, то как и должно быть получается
нормальная черно-белая картинка.
Вероятно изменение цвета наблюдается из-за того, что я не отслеживаю
выхода в результате мат операций за границы 0...255
но это надо еще проверить
...чем и займусь сегодня перед сном
Здравствуйте, temofey, Вы писали:
T>около 70% картинки декодируется нормально...замечена такая закономерность: T>там, где слишком "светло" цвет перебрасывается в черный. T>там, где слишком "темно" цвет перебрасывается в зеленый.
Не парься, лучше посмотри исходники какого-нить XviD'а. Вот например небольшой кусочек оттуда, как раз для твоей задачи:
Обрати внимание на таблицы RGB_Y_tab и пр. — они и нужны как раз для того, чтобы отсекать значения, выходящие за пределы 0-255, получающиеся при преобразовании.
Здравствуйте, temofey, Вы писали:
T>Работал с камерой, от которой получал картинку — буффер и его длину. Проблема в том, что картинка с камеры T>идет в формате i420..экономит канал...нодо конвертнуть i420 в RGB. Изучив информацию, которая приводится на www.fourcc.org T>набросал код, который вроде бы должен работать...и он работает, но картинка частично "плывет". Возможно кто-нибудь уже сталкивался с такой проблемой..и если да — имеет кусок кода осуществляющего данное преобразование. В любом случае, привожу
Стандартная ошибка потеря точности...
ты когда конвертишь из YUV в RGB используй не байты а для начала float-ы..
и только тогда поймешь что для формулы типа этой
BYTE b1 = 0.36*byte2 — 1.18*byte3
иногда будут переполнения ( как ты сказал иногда слишком черное иногда белое).