На данном практическом занятии мы познакомимся с основными принципами отрисовки простых геометрических объектов, научимся использовать функции рисования Windows API и создадим простое приложение, которое в зависимости от распознанного жеста производит отрисовку той или иной геометрической фигуры.
(рис 5.1) Выбор проекта Win32
Далее необходимо выбрать пункт "Приложение Windows", чтобы VisualStudio скомпилировал готовый для работы проект.
(рис 5.2) Определение типа приложения Win32
Подключение SDK к Win32 проекту осуществляется стандартным образом. Не забудьте изменить пункт "Библиотека времени выполнения" на Многопоточную отладку (/MTd), иначе попытка компиляции проекта с использованием SDK не увенчается успехом.
(рис 5.3) Изменение библиотеки времени выполнения
Для этого в обозревателе решений нажмите правой кнопкой мыши на папке с файлами ресурсов, выберите пункт "Добавить" и "Добавить существующий элемент".
(рис 5.4) Подключение утитлиты gesture_render.cpp и gesture_viewer.rc к проекту
Следующим шагом добавим каталог res к компилятору проекта. Для этого в свойствах проекта выберите свойства конфигурации, далее вкладку C/C++ и добавьте каталог res в дополнительные каталоги включаемых файлов, как на рисунке.
(рис 5.5) Добавление каталога к компилятору проекта
Наше приложение будет в зависимости от распознанного жеста включать или отключать рисование соответсвующей фигуры.
В первую очередь необходимо определить в качестве глобальной переменной массив для хранения флагов, в зависимости отtrue/false значения которых будет или не будет осуществляться прорисовка фигур. Также необходимо определить константу, задающую размер этого массива, и еще одну переменную-флаг drawready, с помощью которой будет вызываться отрисовка окна приложения. Таким образом, определение констант и глобальных переменных будет выглядеть следующим образом:
#define MAX_PARAMS 10 // максимальная длина массива флагов для рисования
// Глобальные переменные:
HINSTANCE hInst; // текущий экземпляр
HWND hWnd; //!делаем основное окно программы глобальным
bool paintFlag[MAX_PARAMS]; // массив флагов для рисования
bool drawready = false; // флаг для начала отрисовки
Далее опишем класс GesturePipeline, который будет наследовать от класса UtilPipeline, и определим связь между массивом флагов и распознаваемыми жестами, для чего переопределяем функцию OnGesture. При распознавании позы "победа" приложение должно останавливать распознавание жестов и выполнять рисование, поэтому меняем значение флага drawready.
//Создание наследника класса UtilPipeline
class GesturePipeline: public UtilPipeline {
public:
//создание конструктора
GesturePipeline (void):UtilPipeline(),m_render(L"Gesture Viewer") {
//вызов функции позволяющей распозновать жесты
EnableGesture();
}
//функция OnGesture вызывается, когда жест распознан
virtual void PXCAPI OnGesture(PXCGesture::Gesture *data) {
if (data->active) m_gdata = (*data);
switch (data->label)
{
case PXCGesture::Gesture::LABEL_POSE_PEACE: drawready = true; break;//действие на позу победа
case PXCGesture::Gesture::LABEL_NAV_SWIPE_LEFT: paintFlag[0] = true; break; //действие на жест скольжение влево
case PXCGesture::Gesture::LABEL_NAV_SWIPE_RIGHT: paintFlag[1] = true; break; //дествие на жест скольжение вправо
case PXCGesture::Gesture::LABEL_POSE_THUMB_DOWN: paintFlag[2] = true; break; //действие на позу большой палец вверх
case PXCGesture::Gesture::LABEL_POSE_THUMB_UP: paintFlag[3] = true; break;//действие на позу большой палец вниз
case PXCGesture::Gesture::LABEL_HAND_WAVE: paintFlag[4] = true; break;//действие на позу помахивание
}
}
Переопределим функцию OnNewFrame таким образом, чтобы, если флаг drawready имеет значение true, обнаружение новых фреймов прекращалось
//обнаружение нового фрейма
virtual bool OnNewFrame(void) {
if (drawready) return false; //если была распознана поза победы - выход из цикла
else return m_render.RenderFrame(QueryImage(PXCImage::IMAGE_TYPE_DEPTH),
QueryGesture(), m_gdata);
}
protected:
GestureRender m_render;
PXCGesture::Gesture m_gdata;
};
Далее необходимо осуществить изменения в методе _tWinMain. В первую очередь, необходимо инициализировать массив флагов.
for (int i=0; i<MAX_PARAMS; i++) paintFlag[i] = false; // инициализация глобального массива флагов для рисования
Следующий код создает GesturePipeline объект, который вызывает метод LoopFrames(), обрабатывающий все фреймы, отправляемые камерой.
GesturePipeline pipeline;
pipeline.LoopFrames();
Необходимо внести небольшое изменение в блок инициализации приложения. Запуск окна будет происходить только в тот момент, когда флаг drawready истинен, то есть был распознан жест "победа".
// Выполнить инициализацию приложения:
if (drawready!InitInstance (hInstance, nCmdShow))//
{
return FALSE;
}
Подход к рисованию графики в Windows API в основном схож с процессом рисования при работе с популярными графическими библиотеками, поэтому освоив рисование в Windows API, вы сможете создавать приложения с использованием функций сторонних графических библиотек.
Отрисовка окна происходит при получении сообщения WM_PAINT. Код рисования нужно помещать в блок метода WndProc, описывающий обработку сообщения WM_PAINT. Для рисования необходимо определить объект класса HDC (handle to a device context), в нашем случае - это hdc, именно к этому объекту будут обращаться все функции отрисовки. Также для отрисовки требуется объект класса PAINTSTRUCT, это объект ps.
Вызов метода BeginPaint подготавливает окно к дальнейшей отрисовке, а метод EndPaint закрывает процесс отрисовки, поэтому код рисования нужно обязательно располагать между вызовами этих двух методов.
SetPixel(hdc, х, у, RGB(255, 0, 0)). Последний параметр в вызове SetPixel отвечает за цвет пикселя в формате RGB (в данном случае - красный). Следующий код рисует на экране красный квадрат размером 100х100 пикселей:
for (int i=50; i<150; i++) for (int j=50; j<150; j++) SetPixel(hdc, i,j, RGB(255, 0, 0));
Для того, чтобы нарисовать линию, цикл использовать не нужно, существует специальная функция LineTo (hdc, х, у), которая рисует линию от текущей активной точки до точки с координатами х и у. Чтобы изменить положение текущей точки, используется метод MoveToEx (hdc, х, у, NULL), где х и у - координаты перемещения. Следующий код рисует прямую линию из точки (0,0) в точку (600,600):
MoveToEx (hdc, 0, 0, NULL); LineTo (hdc, 600, 600);
Если требуется нарисовать многоугольник, функция LineTo не используется. Для этих целей существует метод Polyline (hdc, apt, n), где apt - массив точек для соединения, n - количество точек, которые необходимо соединить. С помощью следующего кода происходит отрисовка восьмиугольника. Обратите внимание, чтобы фигура соединилась, первая и последняя точки в массиве должны совпадать.
POINT apt[9] = { 200, 200, 150, 250, 150, 350, 200, 400, 300, 400, 350, 350, 350, 250, 300, 200, 200, 200 };
Polyline (hdc, apt, 9);
Для рисования таких фигур, как прямоугольник и эллипс, предусмотрены специальные методы Rectangle (hdc, xLeft, yTop, xRight, yBottom) и Ellipse (hdc, xLeft, yTop, xRight, yBottom). Определение положения фигуры происходит по четырем точкам, как показано на рисунке 5.6.
![]() |
![]() |
| Рис. 5.6. Определение положения прямоугольника и эллипса | |
Rectangle (hdc, 450, 10, 850, 610);
Ellipse (hdc, 350, 10, 660, 310);
Код, содержащийся в обработке сообщения WM_PAINT, полностью представлен ниже.
hdc = BeginPaint(hWnd, ps);
// TODO: добавьте любой код отрисовки...
if (paintFlag[0]) { //рисуем красный квадрат
for (int i=50; i<150; i++)
for (int j=50; j<150; j++)
SetPixel(hdc, i, j, RGB(255, 0, 0));
}
if (paintFlag[1]) { //рисуем линию
MoveToEx (hdc, 0, 0, NULL) ;
LineTo (hdc, 600, 600) ;
}
if (paintFlag[2]) {//рисуем многоугольник
POINT apt[9] = { 200, 200, 150, 250, 150, 350, 200, 400, 300, 400, 350, 350, 350, 250, 300, 200, 200, 200 };
Polyline (hdc, apt, 9) ;
}
if (paintFlag[3]) { //рисуем прямоугольник
Rectangle (hdc, 450, 10, 850, 610) ;
}
if (paintFlag[4]) { //рисуем эллипс
Ellipse (hdc, 350, 10, 660, 310) ;
}
EndPaint(hWnd, ps);
(рис 5.7) Запуск программы, отображение глубинного изображения с камеры
В случае распознавания приложением какого-либо жеста, в окне будет отображаться его схематическое отображение.
(рис 5.8) Процесс распознавания приложением управляющих жестов
Когда приложение распознает жест победы LABEL_POSE_PEACE, дальнейшее распознавание жестов будет остановлено, а на экране появится окно с отрисованными фигурами, определенными с помощью жестов.
(рис 5.9) Результат работы программы: отображение геометрических фигур на основе распознанных жестов
Ниже представлен весь код файла ppainter.cpp
#include "stdafx.h"
#include "ppainter.h"
#include "util_render.h"
#include "util_pipeline.h"
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include "gesture_render.h"
#include "pxcgesture.h"
#define MAX_LOADSTRING 100
#define MAX_PARAMS 10 // максимальная длина массива флагов для рисования
// Глобальные переменные:
HINSTANCE hInst; // текущий экземпляр
HWND hWnd; //!делаем основное окно программы глобальным, так как оно одно
bool paintFlag[MAX_PARAMS]; // массив флагов для рисования
bool drawready = false; // флаг для начала отрисовки
TCHAR szTitle[MAX_LOADSTRING]; // Текст строки заголовка
TCHAR szWindowClass[MAX_LOADSTRING]; // имя класса главного окна
// Отправить объявления функций, включенных в этот модуль кода:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
//Создание наследника класса UtilPipeline
class GesturePipeline: public UtilPipeline {
public:
//создание конструктора
GesturePipeline (void):UtilPipeline(),m_render(L"Gesture Viewer") {
//вызов функции позволяющей распозновать жесты
EnableGesture();
}
//функция OnGesture вызывается, когда жест распознан
virtual void PXCAPI OnGesture(PXCGesture::Gesture *data) {
if (data->active) m_gdata = (*data);
switch (data->label) {
case PXCGesture::Gesture::LABEL_POSE_PEACE: drawready = true; break;//действие на позу победа
case PXCGesture::Gesture::LABEL_NAV_SWIPE_LEFT: paintFlag[0] = true; break; //действие на жест скольжение влево
case PXCGesture::Gesture::LABEL_NAV_SWIPE_RIGHT: paintFlag[1] = true; break; //действие на жест скольжение вправо
case PXCGesture::Gesture::LABEL_POSE_THUMB_DOWN: paintFlag[2] = true; break; //действие на позу большой палец вверх
case PXCGesture::Gesture::LABEL_POSE_THUMB_UP: paintFlag[3] = true; break;//действие на позу большой палец вниз
case PXCGesture::Gesture::LABEL_HAND_WAVE: paintFlag[4] = true; break;//действие на позу помахивание
}
}
//обнаружение нового фрейма
virtual bool OnNewFrame(void) {
if (drawready) return false; //если была распознана поза победы - выход из цикла
else return m_render.RenderFrame(QueryImage(PXCImage::IMAGE_TYPE_DEPTH),
QueryGesture(), m_gdata);
}
protected:
GestureRender m_render;
PXCGesture::Gesture m_gdata;
};
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
for (int i=0; i<MAX_PARAMS; i++) paintFlag[i] = false; // инициализация глобального массива
флагов для рисования
// TODO: разместите код здесь.
MSG msg;
HACCEL hAccelTable;
// Инициализация глобальных строк
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_PPAINTER, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
GesturePipeline pipeline;
pipeline.LoopFrames();
// Выполнить инициализацию приложения:
if (drawready!InitInstance (hInstance, nCmdShow))//
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PPAINTER))
// Цикл основного сообщения:
while (GetMessage(msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, msg))
{ TranslateMessage(msg);
DispatchMessage(msg);
}
}
return (int) msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PPAINTER));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_PPAINTER);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{ hInst = hInstance; // Сохранить дескриптор экземпляра в глобальной переменной
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd) { return FALSE; }
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Разобрать выбор в меню:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, ps);
// TODO: добавьте любой код отрисовки...
if (paintFlag[0]) { //рисуем красный квадрат
for (int i=50; i<150; i++)
for (int j=50; j<150; j++)
SetPixel(hdc, i, j, RGB(255, 0, 0));
}
if (paintFlag[1]) { //рисуем линию
MoveToEx (hdc, 0, 0, NULL) ;
LineTo (hdc, 600, 600) ;
}
if (paintFlag[2]) {//рисуем многоугольник
POINT apt[9] = { 200, 200, 150, 250, 150, 350, 200, 400, 300, 400,
350, 350, 350, 250, 300, 200, 200, 200 };
Polyline (hdc, apt, 9) ;
}
if (paintFlag[3]) { //рисуем прямоугольник
Rectangle (hdc, 450, 10, 850, 610) ;
}
if (paintFlag[4]) { //рисуем эллипс
Ellipse (hdc, 350, 10, 660, 310) ;
}
EndPaint(hWnd, ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Обработчик сообщений для окна "О программе".
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
LABEL_POSE_BIG5, LABEL_NAV_SWIPE_UP, LABEL_NAV_SWIPE_DOWN, LABEL_HAND_ CIRCLE. Измените код приложения таким образом, чтобы жест помахивания LABEL_HAND_WAVE стирал все нарисованные фигуры.Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.