Решил отписаться про свои успехи. в общем на .NET и EmguCV забил - раньше не сталкивался, с ходу не пошло, разбираться некогда.
Решил попробовать MFC, хоть с ним тоже раньше не сталкивался, но начал получать хоть какие-то результаты, потому решил на нем остановиться.
Для таких начинающих как я расскажу что и как я делал:
1) создал MFC проект в Visual Studio 2010
2) на dialog (главную форму) бросил компонент Picture Control
3) в свойствах Picture Control в поле "Тип" установил "Точечный рисунок", в поле "ИД" стоит IDC_STATIC - его нужно изменить, НЕ выбрать из выпадающего списка, а вбить ручками. я, например, вбил IDC_CAP_STATIC.
я еще ставил "Изображение по центру" в true, иначе у меня не получалось растянуть Picture Control по форме...
4) потом нужно добавить переменную для Picture Control, для того чтоб можно было с ним работать. для этого клацаем правой кн. по Picture Control и жмем "Добавить переменную". потом указываем имя, например m_cap, и тип переменной CStatic
5) теперь нужно прикрутить OpenCV к проекту. я делал как сказано тут. там же и простой примерчик.
6) в OpenCV изображения представлены типом IplImage, а компонент Picture Control понимает Bitmap.
для преобразования типов я воспользовался кодом, который нашел в сети (спасибо автору ):
HBITMAP CreateRGBBitmap(IplImage* _Grab)
{
char *App;
LPBITMAPINFO lpbi = new BITMAPINFO;
lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
lpbi->bmiHeader.biWidth = _Grab->width;
lpbi->bmiHeader.biHeight =_Grab->height;
lpbi->bmiHeader.biPlanes = 1;
lpbi->bmiHeader.biBitCount = 24;
lpbi->bmiHeader.biCompression = BI_RGB;
lpbi->bmiHeader.biSizeImage = WIDTHBYTES((DWORD)_Grab->width * 8) * _Grab->height;
lpbi->bmiHeader.biXPelsPerMeter = 0;
lpbi->bmiHeader.biYPelsPerMeter = 0;
lpbi->bmiHeader.biClrUsed = 0;
lpbi->bmiHeader.biClrImportant = 0;
void* pBits;
HBITMAP hBitmap = CreateDIBSection( NULL,lpbi,DIB_RGB_COLORS,(void **)&pBits,NULL,0 );
delete lpbi;
if ( hBitmap ) App=(char*)pBits;
long int length=0;
if(_Grab->nChannels==1) // Серое или бинарное
{
length = _Grab->width*(_Grab->height);
for (int i=0;i<_Grab->height;i++)
{
for (int j=0;j<_Grab->width;j++)
{
App[_Grab->width*3*(_Grab->height-i-1)+j*3]=_Grab->imageData[_Grab->width*(i)+j];
App[_Grab->width*3*(_Grab->height-i-1)+j*3+1]=_Grab->imageData[_Grab->width*(i)+j];
App[_Grab->width*3*(_Grab->height-i-1)+j*3+2]=_Grab->imageData[_Grab->width*(i)+j];
}
}
}
if(_Grab->nChannels==3) // Цветное
{
for (int i=0;i<_Grab->height;i++)
{
// Копируем память
memcpy(App+_Grab->width*3*(_Grab->height-i-1),_Grab->imageData+_Grab->width*3*i,_Grab->width*3);
}
}
return hBitmap;
}
7) теперь, уже имея картинку pBitmap с типом HBITMAP, можно отобразить ее на Picture Control (напомню, у нас есть переменная m_cap). для этого делаем следующее:
// Получить контекст устройства
CDC* dc = m_cap.GetDC();
// Создать контекст устройства в памяти
HDC hMemDC = CreateCompatibleDC(dc->m_hDC);
// Поместить растровое изображение в dc памяти и
// сохранить старое изображение
HGDIOBJ hOldBm = SelectObject(hMemDC, pBitmap);
// Копировать содержимое dc памяти в dc экрана
BitBlt(dc->m_hDC, 0, 0, width, height, // Приемник: dc экрана
hMemDC, 0, 0, SRCCOPY); // Источник: dc памяти
// Восстановить старое растровое изображение в dc памяти
SelectObject(hMemDC, hOldBm);
// Уничтожить dc памяти
DeleteDC(hMemDC);
// Освободить полученый контекст устройства
ReleaseDC(dc);
// Уничтожить растровое изображение
DeleteObject(pBitmap);
все... картинку показываем!!!
отображать видео у меня сначала не получилось, точнее картинка сильно мерцала. выделял отображение в отдельный поток - не помогло. потом, в сети, я вычитал что в MFC и Windows все основывается на сообщениях (можно почитать тут) и для вывода видео можно использовать таймер.
делается это так:
1) создаем таймер, захватчик камеры, и указатель на картинку:
UINT_PTR m_nTimer;
CvCapture* capture;
IplImage* frame;
а в методе OnInitDialog() дописываем:
// Инициализация таймера
// Таймер будет посылать WM_TIMER сообщение основному
// рамочному окну каждые 30 миллисекунд
m_nTimer = SetTimer(1, 30, 0);
// получаем любую подключенную камеру
capture = cvCreateCameraCapture(CV_CAP_ANY);
assert( capture );
2) добавляем обработку сообщений от таймера. т.е. жмем Проект->Мастер классов, выбираем имя класса диалога (как правило заканчивается на ...Dlg), переходим на вкладку "Сообщения" и в левой части находим WM_TIMER и добавляем обработчик (в правой части появится OnTimer и т.д.).
3) в обработчике OnTimer() дописываем захват изображения с камеры и отображение в Picture Control:
frame = cvQueryFrame( capture );
DrawData(CreateRGBBitmap(frame));
void CtestDlg::DrawData(HBITMAP pBitmap)
{
// Получить контекст устройства
CDC* dc = m_cap.GetDC();
// Создать контекст устройства в памяти
HDC hMemDC = CreateCompatibleDC(dc->m_hDC);
// Поместить растровое изображение в dc памяти и
// сохранить старое изображение
HGDIOBJ hOldBm = SelectObject(hMemDC, pBitmap);
// Копировать содержимое dc памяти в dc экрана
BitBlt(dc->m_hDC, 0, 0, width, height, // Приемник: dc экрана
hMemDC, 0, 0, SRCCOPY); // Источник: dc памяти
// Восстановить старое растровое изображение в dc памяти
SelectObject(hMemDC, hOldBm);
// Уничтожить dc памяти
DeleteDC(hMemDC);
// Освободить полученый контекст устройства
ReleaseDC(dc);
// Уничтожить растровое изображение
DeleteObject(pBitmap);
UpdateData(FALSE);
}
4) ну и нужно при выходе из программы освободить ресурсы:
cvReleaseCapture( &capture );
cvReleaseImage(&frame);
KillTimer(1);
я это делаю в обработчике сообщения WM_CLOSE...
ну, вроде и все... надеюсь ничего не пропустил и кому-то это поможет