Как получить цвет пикселя в Avi файле?

  • Автор темы ArtBerry
  • Дата начала
Статус
Закрыто для дальнейших ответов.
A

ArtBerry

#1
Люди добрые, помогите разаобраться в содранной программе.
Содрал из урока. Но разобраться толком не могу. "Я ведь еще не волшебник, я только учусь...". А надо очень.
Прошу вас откликнитесь.

Вопрос такой: Нужно получить цвет пискеля из видео потока, открытого файла.

Если я правильно понимаю, то поток загружен в память, но ввиде каких данных мне непонятно. Мне говорили, что можно оперировать с data, для получения цветов пикселя, но я ни как не могу понять как? Сам не понял, что написал.

Вощем текст программы вот. А получить надо цвет пикселя.

// avi.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h> // Заголовочный файл Windows
#include <vfw.h> // Заголовочный файл для "Видео для Windows"

#using <mscorlib.dll>
using namespace System;

#pragma comment( lib, "vfw32.lib" ) // Искать VFW32.lib при линковке

#ifndef CDS_FULLSCREEN // CDS_FULLSCREEN не определяется некоторыми
#define CDS_FULLSCREEN 4 // компиляторами. Определяем эту константу
#endif // Таким образом мы можем избежать ошибок

AVISTREAMINFO psi; // Указатель на структуру содержащую информацию о
PAVISTREAM pavi; // Дескриптор для открытия потока
PGETFRAME pgf; // Указатель на объект GetFrame
BITMAPINFOHEADER bmih; // Заголовочная информация для DrawDibDraw декодирования

HDC hdc = CreateCompatibleDC(0); // Создание совместимого контекста устройства
unsigned char* data = 0; // Указатель на наше измененное в размерах изображение
char *pdata; // Указатель на данные текстуры

void OpenAVI(LPCSTR szFile) // Вскрытие AVI файла (szFile)
{
AVIFileInit(); // Открывает файл

// Открытие AVI потока
if (AVIStreamOpenFromFile(&pavi, szFile, streamtypeVIDEO, 0, OF_READ, NULL) !=0)
{
// Если ошибка
MessageBox (HWND_DESKTOP, "Failed To Open The AVI Stream", "Error", MB_OK | MB_ICONEXCLAMATION);
}

AVIStreamInfo(pavi, &psi, sizeof(psi)); // Записываем информацию о потоке в psi

pgf=AVIStreamGetFrameOpen(pavi, NULL); // Создание PGETFRAME с нужными нам параметрами

}

void GrabAVIFrame(int frame) // Захват кадра
{
LPBITMAPINFOHEADER lpbi; // Содержит BitmapInfoHeader
// Получение данных из потока
lpbi = (LPBITMAPINFOHEADER)AVIStreamGetFrame(pgf, frame);
// Указатель на данные возвращенные AVIStreamGetFrame
// (Пропуск заголовка для получения указателя на данные)
pdata=(char *)lpbi+lpbi->biSize+lpbi->biClrUsed * sizeof(RGBQUAD);
//flipIt(data); // Перестановка красных и синих байтов
}


void CloseAVI(void) // Функция закрытия
{
DeleteObject(hBitmap); // Уничтожение устройства растра
DrawDibClose(hdd); // Закрытие контекста DrawDib устройства
AVIStreamGetFrameClose(pgf); // Закрытие объекта GetFrame
AVIStreamRelease(pavi); // Завершение потока
AVIFileExit(); // Закрытие файла
}

int _tmain()
{
OpenAVI("c:\\im20\\box.avi");
GrabAVIFrame(1);
CloseAVI();
//Console::WriteLine (data[2]);
Console::ReadLine ();
return 0;
}

Спасибо.
 
04.09.2006
2 566
3
#2
Ну если я правильно понял, то pdata - указатель на данные фрейма. Поле biBitCount структуры BITMAPINFOHEADER содержит количество бит, занимаемых одним пикселом. Следовательно, смещение некоторого пиксела от начала массива будет кратно значению этого поля.
 
M

MechWarrior

#3
Угу, фрейм возращается в виде стандартного DIB-растра (битмапа), характеристики которого хранятся в BITMAPINFOHEADER. На массив пикселов в данном коде указывает pdata. Пикселы в массиве хранятся по строкам (всего строк lpbi->biHeight), в каждой строке хранится lpbi->biWidth пикселов. Пиксел занимает lpbi->biBitCount битов. Например, если битов 24 (3 байта) - то это BGR-пиксел (по байту на синюю (B), зеленую (G), красную ® компоненту в соответствующем порядке), если 32 бита (4 байта) - то это BGRA (добавляется еще компонента A - которая реально обычно не используется).

Т.е. работа с (неупакованными) пикселами - это то же, что работа с массивом размерности lpbi->biHeight x lpbi->biWidth и с размером элемента lpbi->biBitCount битов. Только надо учитывать то, что размер строки пикселов всегда выравнивается на 32-битную границу, т.е. размер строки в байтах всегда кратен 4. И обычно первая строка массива пикселов отрисовывается снизу, а последняя - сверху, т.е. хранятся они в обратном отрисовке порядке (хотя это зависит от знака biHeight).
 
A

ArtBerry

#4
Друзья, во-первых - спасибо вам за ответы.

Только я не особо понял ваши мысли. Мне так и не понятно, как же все таки получить данные из pdata?

MechWarrior
"...это то же, что работа с массивом размерности lpbi->biHeight x lpbi->biWidth..." - это значит, что я могу, например, посмотреть на pdata[0][0]? А что там будет?

Я вот что намудрил на выходных:

//////////////////////////////////////////////////////////////
RGBQUAD *pdata;
pdata = (RGBQUAD *)AVIStreamGetFrame(pgf, frame); // Получение данных из потока

for (int i=0; i<100; i++)
{
// Хочу посмотреть на значения синего цвета в первых 100 пикселях.
// Я не знаю привильно ли это!

Console::WriteLine ((*(pdata+i)).rgbBlue);

// Но программа выводить одно и тоже, независимо от номера кадра.
};
//////////////////////////////////////////////////////////////

Мне непонятно то, как пользоваться pdata. Она может быть и какого-нибудь другого типа, в программе берется LPBITMAPINFOHEADER. Это я изменил ее на RGBQUAD.

В MSDN о фуекции AVIStreamGetFrame сказано:
...
Return Values
Returns a pointer to the frame data if successful or NULL otherwise. The frame data is returned as a packed DIB.
...

В переводе на нормальный язык это означает:
троеточие
Возвращаемые значения
Возвращает указатель на данные кадра, если все хорошо или "NULL" (в нормальных языках нет перевода таких слов), если все плохо.
Данные кадра есть возвращенные, как сжатый DIB.
троеточие




Если интересно, то вот http://www.yagodin.narod.ru/ca.rar архив проекта. Создан в VS .NET 2003
 
M

MechWarrior

#5
Давно тут не появлялся, сорри. Если еще актуально - то зачем результат AVIStreamGetFrame было указывать как RGBQUAD*, если он в самом первом посте был правильный - LPBITMAPINFOHEADER? Эта функция ведь возвращает указатель на DIB-битмап. Данный битмап (DIB) состоит из заголовка (BITMAPINFOHEADER), в котором описывается формат данного битмапа (размеры, количество цветов, палитра и .п.), за которым идет массив пикселов. Соответственно, чтобы получить указатель на массив пикселов, имея указатель на заголовок - надо перескочить через этот заголовок, что и делается в первом постинге (в процедуре GrabAVIFrame).

Получаем lpbi - указатель на заголовок, затем перескакиваем через него (его размеры lpbi->biSize, плюс к нему может быть подсоединена палитра из lpbi->biClrUsed цветов) и получаем pdata - указатель на массив пискелов. Им и надо пользоваться.

При этом, как я писал выше, элементами данного массива не обязательно являются 32-битные пикселы RGBQUAD - хотя могут быть и такие, но в общем случае надо смотреть заголовок битмапа и использовать указанные там параметры битмапа.
 
Статус
Закрыто для дальнейших ответов.