BlueWall: Virtual Studio своими руками

Тема в разделе "WASM.SOFTWARE", создана пользователем Paguo_86PK, 1 мар 2011.

  1. Paguo_86PK

    Paguo_86PK Руслан

    Публикаций:
    0
    Регистрация:
    8 окт 2007
    Сообщения:
    911
    Адрес:
    Ташкент
    В общем, отдыхал я от интернета целых три месяца! Просто 1-го декабря прошлого года не продлил свой аккаунт и он заблокировался. Отдохнул от социальных сетей как следует...
    И вот сегодня я снова в сети!

    Естественно, я не сидел сложа руки перед тупым говорящим ящиком со стеклянным глазом.
    А потихонечку вспоминал все свои навыки в программировании.
    И, как всегда, решил заняться графикой. Но подойти с другой стороны. Так, если раньше я упрожнялся в бесконечном оттачивании алгоритмов построения линий и окружностей, то в этот раз я решил взяться за что-нибудь посложнее...

    Раньше в областях распознавания графических объектов я был полным нулём. Теперь и здесь имею маленький опыт.
    Так за месяц получилась крохотная утилита отделения заднего плана от остальных объектов кадра. Иными словами пародия на виртуальную студию.
    Функций у неё меньше чем у ManyCam, но и размер у неё в сотню раз меньше. Скорость же достигает 30-60 кадров 352x288 на процессоре Pentium-IV 2.4GHz, что позволяет сносно делает разные эффекты в линейном монтаже.

    Единственная неприятность, без VirtualDub она не работает. Так-как на винте не нашёл примеров доступа к платам видео захвата. По-этому, моя утилита после запуска сразу ищет окно VirtualDub, который обязательно должен быть в Capture Mode. К тому же, окно утилиты всегда "дырявится", чтобы не перекрывать активную область VirtualDub. Говоря иначе, костыль!

    Показал племяннице как в её сказках делают чудеса: Раздвоение персонажей, перемещение в пространстве, и т.п.
    Самым сложным оказалось найти ткань приличного размера голубого цвета. Да ещё правильно подсветить её, чтобы не было теней...

    Вот, решил было выложить свою работу в сеть как Open Source, однако друг долго настаивал на закрытом коде с финансовой выгодой. Конечно, под коммерческий проект программа врятли потянет, а вот для обучающихся графике и распознаванию образов, быть может, алгоритмы могут быть достаточно полезными.

    Вступление:
    Код (Text):
    1. /*****************************************************************************
    2. *                                                                            *
    3.    Задавшишь вопросом, отчего оффициальное программное обеспечение организации
    4. виртуальных студий имеет в основном закрытый код и распространяется в основном
    5. на платной основе, было решено опробовать собственные силы в этой области. Так
    6. за месяц работы над собственным алгоритмом, написанного с чистого листа, вышел
    7. довольно простой код, который, однако, обеспечивал сносную производительность.
    8.  
    9.    Как показала практика, организация всего алгоритма разбивается на несколько
    10. базовых функций. Прежде всего необходимо создать несколько битовых карт одного
    11. разрешения с Альфа-каналом. Как правило, по 32 бита на пиксел. Как минимум, их
    12. должно быть три:
    13. Source - Для хранения текущего захваченного кадра и сравнения с примерным;
    14. Sample - Хранит пример заднего плана. Идеально, может захватываться однажды;
    15. Result - Служит как промежуточный буфер комплексных данных и хранит результат.
    16.    Также весь комплекс генерируемых данных разделяется на несколько классов:
    17. Low-Level Noise - Низкоуровневый шум, вызваный погрешностями АЦП видео тракта;
    18. High-Level Noise - Высокоуровневый шум, образованый бликом, насекомым и пылью;
    19. Spot - Пятно, низкоуровневый объект кадра. Самый крупный всегда первый;
    20. Cast - Объект среднего уровня с отслеживаемой позицией.
    21.  
    22. Ступень #1:
    23.    Первым основным этапом является анализ приходящего изображения и сравнением
    24. с зафиксированным изображением заднего плана. Каждый пиксел проверяется и если
    25. разность хотябы одной из цветовых составляющих оказывается выше установленного
    26. порога, пиксел помечается альфа-маской как отличающийся. Но, полученное альфа-
    27. изображение, как правило, содержит много шума и не годится к непосредственному
    28. использованию в качестве маски.
    29.  
    30. Ступень #2:
    31.    Вторым основным этапом является анализ получившейся альфа-маски изображения
    32. и выявление всех полезных объектов изображения с подавлением паразитных. Самый
    33. простейщий и удобный способ заключается в алгоритма заливки. Так, классические
    34. способы заливки в этом случае не могут выполнить свою задачу и необходима своя
    35. функция. Заливка производится только в альфа-канале и все отличающияся пикселы
    36. проверяются на принадлежность к определённой группе, одновременно индексируясь
    37. порядковым номером пятна в проходе по всему изображеную. Если их количество не
    38. превышает установленный порог, пятно считается паразитным и удаляется в альфа-
    39. канале чисткой всех бит. Пятна, содержащие большее число пикселей, остаются со
    40. своим индексом, а количество пикселей заносится в буфер.
    41.    Всего допускается до 254 пятен, которые затем сортируются в порядке размера
    42. от крупного к мелкому и весь альфа-канал подвергается переиндексации всех этих
    43. пикселей с усечением индекса до первых самых крупных пятен из 16.
    44.  
    45. Ступень #3:
    46.    Теперь всего этого достаточно, чтобы заменить задний план изображения своим
    47. и можно объекты с определёнными индексами переместить, развернуть, отразить, а
    48. также просто скрыть. Однако, манипуляция над объектами по порядку их размера в
    49. кадре достаточна лишь при статическом изображении. В динамике же всё будет так
    50. или иначе путаться. Поэтому все объекты необходимо пересортировать по позициям
    51. и отслеживать их перемещение. А это решается простыми геометрическими приёмами
    52. с минимальными затратами на вычисление.
    53. ******************************************************************************
    54.    В целом, всё приложение составляется из нескольких описанных функций, а те,
    55. в свою очередь, делятся на две группы: написанные на ассемблере для достижения
    56. максимальной производительности и на описанные средствами высокоуровнего языка
    57. для повышения понимания логики с целью представления в Open Source проекте. Но
    58. при этом автором не распространяется ассемблерная часть кода в листинге, тогда
    59. как она может беспрепятственно восстанавливаться из соответствующей библиотеки
    60. практически как есть.
    61.    Весь проект состоит всего из нескольких в одном /inc/ подкаталоге:
    62. /inc/main.h     - Содержит базовые процедуры построения интерфейса;
    63. /inc/defines.h  - Содержит определение нужных значений и псевдо-функций;
    64. /inc/types.h    - Содержит описание всех необходимых типов и структур;
    65. /inc/vars.h     - Включает в себя все переменные, необходимые для работы;
    66. /inc/algs.h     - Описывает все ключевые процедуры работы с изображением;
    67. /inc/algs.x86.h - Оптимизированные варианты ключевых процедур;
    68. /inc/procs.h    - Все остальные функции, в основном, служащие интерактивности.
    69. ******************************************************************************
    70.    Интерфейс приложения представляется несколькими закладками со всеми нужными
    71. настройками параметров, а также интерактивной статусной строкой. Помимо данных
    72. о скорости обработки кадров и сложности, статусная строка содержит и несколько
    73. кнопок управления режимом, дублируемые клавишами F9, F10, F11 и Pause/Break, а
    74. также меню отображения/скрытия любого из объектов в кадре. Здесь полный список
    75. клавиш и сочетаний с их функциями:
    76. Ctrl+A- Переключение на закладку Samples;
    77. Ctrl+S- Переключение на закладку Source;
    78. Ctrl+D- Переключение на закладку Order;
    79. Ctrl+C- Переключение на закладку Compare;
    80. Ctrl+E- Переключение на закладку Preview;
    81. F9    - Включить/выключить режим "зеркало";
    82. F10   - Включить/выключить режим захвата заднего плана;
    83. F11   - Включить/выключить режим двухкратного вида;
    84. F12   - Включить/выключить режим ускорения;
    85. Pause - Включить/выключить режим захвата видео.
    86. *                                                                            *
    87. *****************************************************************************/
    И на последок. Напоролся я на уйму простых геометрических проблем. Например, очерчивание объектов в кадре контуром. Сначала использовал известные приёмы с комбинированием регионов, но они очень тормозят. А собственный алгоритм, который далее представлю, даёт сбои на зазубринах. В общем, по интересующим меня вопросам буду обращаться ниже. А пока, вот ссылка на демо-видео, где племянница демонстрирует работу иннерцоида в корыте :)))
    http://www.youtube.com/watch?v=pvkpDobVZ44
     
  2. Paguo_86PK

    Paguo_86PK Руслан

    Публикаций:
    0
    Регистрация:
    8 окт 2007
    Сообщения:
    911
    Адрес:
    Ташкент
    Итак, прошлой ночью гуглил по вопросу построения контура некоторой фигуры, однако попадались либо сильно примитивные алгоритмы, либо только математическая модель решения.
    Разработаный мною алгоритм способен построить контур фигуры, но он сбоит и практически не годится в моей "виртуальной студии".

    Суть алгоритма заключается в реализации маленького бота "черепашки", который "проползает" по всему контуру и заносит координаты точек границы в массив. Ползти бот может в одном из восьми направлений. А поворачивать может либо на 45°, либо на 90° в обоих направлениях.
    Основу "мозгов" бота составляет 5 "сенсоров" вокруг "головы" бота, собирающих информацию об окружающей обстановке. Вот описание расположение сенсоров в графическом фрейме и их биты в статусе:
    Код (Text):
    1. +45°  +0° -45° | 0x04 0x10 0x02
    2. +90° Head -90° | 0x08      0x01
    Тем самым, если "мина" находится впереди, получим код 0x10. А если впереди и впереди-слева, то код 0x14. И т.д.
    Далее, строим таблицу ассоциативного массива с постулатами действий бота. Так, если слева всё чисто, а справа и спереди - мины, свернём влево на 90°. Тем самым, в таблицу введём постулат 0x217, где 2 - 2x45°, а 17 - мина впереди(1) и по всем бортам, кроме крайне-левого(8):
    Код (Text):
    1. +45°  +0° -45° | 0x04 0x10 0x02 | Mine Mine Mine -> 0x04 0x10 0x02
    2. +90° Head -90° | 0x08      0x01 | Good +90° Mine -> 0x00      0x01
    Однако, будут попадаться ситуации тупика, когда необходимо ориентироваться по обстановке предыдущего шага. По-этому необходимо запоминать предыдущую ситуацию. А дополнить таблицу такими исключительными постулатами.
    Чтобы обеспечить реверс бота при одинаковых, но зеркальных условиях, при этом не дублировать всю таблицу, биты статуса нужно продублировать в слове, но в зеркальных позициях. Например, 0x0108 или 0x0402 или 0x030C и т.д. Код алгоритма по-очереди сравнивает статус с младшим словом таблицы, а затем со старшим. Если совпадение было в младшем, бот поворачивается на положительный угол. Если совпадение в старшем, соответственно на такой же, но отрицательный угол.
    Таким образом, код таблицы 0x020015 означает ситуацию:
    Код (Text):
    1. Mine Mine Good                Good Mine Mine
    2. Good +90° Mine или зеркальное Mine -90° Good
    А код 0x011C1A означает исключение:
    Код (Text):
    1. Good Mine Mine                Mine Mine Good
    2. Mine +45° Good или зеркальное Good -45° Mine
    3. если предыдущая ситуация выглядила как
    4. Mine Mine Good                Good Mine Mine
    5. Mine      Good или зеркальным Good      Mine
    Всего этого достаточно, чтобы описать любое сложное шаговое поведение нашего бота.
    Ниже представлен полный код программы на Си.
    Сам алгоритм:
    Код (Text):
    1. #include <math.h>
    2.  
    3. typedef DWORD       RGBA, *PRGBA;           // Needed for operations with bitmap
    4. #define BMP_WIDTH   640                     // Bitmap width
    5. #define BMP_HEIGHT  480                     // Bitmap height
    6. #define BMP_SQUARE  BMP_WIDTH * BMP_HEIGHT  // Bitmap square in pixels
    7. #define MAX_POINTS  8192                    // Maximal dimension of contour
    8. #define PI          3.141592f
    9. #define XY(x, y)    ((y) * BMP_WIDTH + (x)) // Compute address in bitmap array by X,Y-position
    10. #define PIXEL(b,x,y) b[XY(x, y)]            // Access to pixel
    11.  
    12. HBITMAP hBmp;                   // Our bitmap
    13. HDC     hBmpDC;                 // Bitmap context for output
    14. PRGBA   pBmp;                   // Pointer to bitmap array
    15. POINT   point[MAX_POINTS];      // Pixels of contour
    16. PPOINT  pPoint = &point[0];     // Pointer to current pixel of contour
    17. RECT    rt;
    18. DWORD   around = 0x89ABCDEF;
    19. char    dir;
    20. long    i;
    21.  
    22. static const
    23. DWORD   turning[] =             // Table of principles
    24. {
    25.      0x010003 ,0x010004 ,0x010007 ,0x010016 ,0x01001E ,0x020001 ,0x020005 ,0x020011
    26.     ,0x020015 ,0x011C1A ,0x011C16 ,0x01170B ,0x020305 ,0x02030D ,0x02081F ,0x020A1F
    27. /*  ,0x020C0F ,0x020C1F ,0x020E00 ,0x020E1F ,0x02151D ,0x021705 ,0x02170D ,0x02171D
    28.     ,0x021C1F ,0x021E1F ,0x021E00 ,0x030300 ,0x030304 ,0x031300 ,0x031304 ,0x031312
    29.     ,0x030314 ,0x031704 ,0x031710 ,0x031714 ,0x001C1E
    30.     ,0x02181F ,0x01110F ,0x021109 ,0x021B0D ,0x020B1F*/
    31. };
    32. static const                    // Table of position displace by direction
    33. char    dirs[] = {+0, +1, +1, +1, -0, -1, -1, -1};
    34. #define GetAt(a)    ((PIXEL(dst, pPoint[0].x + dirs[((a) + *dir) & 7], pPoint[0].y + dirs[((a) + *dir + 6) & 7]) >> 24))
    35. #define GoTo(a)     pPoint[0].x += dirs[((a) + *dir) & 7], pPoint[0].y += dirs[((a) + *dir + 6) & 7]
    36.  
    37. void    Look_About(DWORD *dst, PPOINT &pPoint, PDWORD around, PCHAR dir) {
    38. DWORD   code, turn;
    39. DWORD   q = 0x0;
    40. char    dirl;
    41.     if(*around != 0x89ABCDEF) { // Are we into object? Yes!
    42.         if((*around & 0x0000001F) != 0x00000000 && (*around & 0x0000001F) != 0x0000001F)
    43.             *around <<= 8;      // Save last environment
    44.         *around &= 0x1F001F00;
    45.         if(pPoint[0].y < 2 || pPoint[0].x < 2)
    46.             return;
    47.         if(GetAt(+2)) *around |= 0x00080001;    // Looking for right-side or flipped left-side
    48.         if(GetAt(+1)) *around |= 0x00040002;    // Looking for right-corner or flipped left-corner
    49.         if(GetAt(+0)) *around |= 0x00100010;    // Looking forward
    50.         if(GetAt(-1)) *around |= 0x00020004;    // Looking for left-corner or flipped right-corner
    51.         if(GetAt(-2)) *around |= 0x00010008;    // Looking for left-side or flipped right-side
    52.         PIXEL(dst, pPoint[0].x, pPoint[0].y) &= 0xFFFF0000; // Visual markup of pixel
    53.         dirl = *dir;
    54.         for(i = sizeof(turning) / sizeof(*turning); i --;) {// Scan for postulate
    55.             turn = turning[i];
    56.             if(turn & 0x00FF00)                 // Prepare to turns
    57.                 code = *around & 0x00FFFFFF;
    58.             else
    59.                 code = *around & 0x000000FF;
    60.             if((turn & 0x00FFFF) == (code & 0x00FFFF)) {
    61.                 *dir += (turn & 0x00030000) >> 16;  // Turn to ...
    62.                 break;
    63.             }
    64.             if(turn & 0x00FF00)                 // Prepare to reverse
    65.                 code = (*around >> 16) & 0x0000FFFF;
    66.             else
    67.                 code = (*around >> 16) & 0x000000FF;
    68.             if((turn & 0x00FFFF) == (code & 0x00FFFF)) {
    69.                 *dir -= (turn & 0x00030000) >> 16;  // Reverse to ...
    70.                 break;
    71.             }
    72.         }
    73.         *dir += 8;
    74.         *dir &= 7;
    75.         if(dirl != *dir) {                      // Did we turned? Yes, let's save point
    76.             pPoint[1].x = pPoint[0].x;
    77.             pPoint[1].y = pPoint[0].y;
    78.             ++ pPoint;
    79.         }
    80.         GoTo(0);                                // Do one step
    81.     } else {
    82.         for(long y = 1; y < BMP_HEIGHT - 1; ++ y)   // Are we into object? No ...
    83.         for(long x = 1; x < BMP_WIDTH - 1; ++ x) {  // Let's find to border of object
    84.             if(PIXEL(dst, x, y) >> 24) {
    85.                 pPoint->x = x;
    86.                 pPoint->y = y;
    87.                 ++ pPoint;
    88.                 pPoint->x = x;
    89.                 pPoint->y = y;
    90.                 *around = 0;
    91.                 *dir = 2;
    92.                 return;
    93.             }
    94.         }
    95.     }
    96. }
    97.  
    98. BOOL    Do_Step(HDC hDC) {
    99.     TCHAR   text[32];
    100.     UINT    state;
    101.     i = pPoint - point;
    102.     if(i > 1 && (i >= MAX_POINTS | (abs(point[0].x - pPoint->x) <= 2 && abs(point[0].y - pPoint->y) <= 2))) {
    103.         for(i = 0; i < pPoint - point; ++ i)
    104.             point[i].y = BMP_HEIGHT - point[i].y - 1;
    105.         SelectObject(hDC, GetStockObject(GRAY_BRUSH));
    106.         Polygon(hDC, point, i);
    107.         return false;
    108.     } else {
    109.         Look_About(pBmp, pPoint, &around, &dir);
    110.     }
    111.     i = 40;
    112.     BitBlt(hDC, 0, 0, BMP_WIDTH, BMP_HEIGHT, hBmpDC, 0, 0, SRCCOPY);
    113.     StretchBlt(hDC, BMP_WIDTH, 0, 64, 64, hBmpDC, pPoint->x - 7, BMP_HEIGHT - pPoint->y - 8, 15, 15, SRCCOPY);
    114.     rt.bottom = BMP_HEIGHT; rt.left = BMP_WIDTH;
    115.     rt.top = rt.bottom - i + 1; rt.right = rt.left + i - 1;
    116.     state = around & 0x08 ? DFCS_CHECKED : NULL;
    117.     state |= around & 0x0800 ? NULL : DFCS_INACTIVE;
    118.     DrawFrameControl(hDC, &rt, DFC_BUTTON, state); OffsetRect(&rt, 0, -i);
    119.     state = around & 0x04 ? DFCS_CHECKED : NULL;
    120.     state |= around & 0x0400 ? NULL : DFCS_INACTIVE;
    121.     DrawFrameControl(hDC, &rt, DFC_BUTTON, state); OffsetRect(&rt, i, 0);
    122.     state = around & 0x10 ? DFCS_CHECKED : NULL;
    123.     state |= around & 0x1000 ? NULL : DFCS_INACTIVE;
    124.     DrawFrameControl(hDC, &rt, DFC_BUTTON, state); OffsetRect(&rt, i, 0);
    125.     state = around & 0x02 ? DFCS_CHECKED : NULL;
    126.     state |= around & 0x0200 ? NULL : DFCS_INACTIVE;
    127.     DrawFrameControl(hDC, &rt, DFC_BUTTON, state); OffsetRect(&rt, 0, i);
    128.     state = around & 0x01 ? DFCS_CHECKED : NULL;
    129.     state |= around & 0x0100 ? NULL : DFCS_INACTIVE;
    130.     DrawFrameControl(hDC, &rt, DFC_BUTTON, state); OffsetRect(&rt, -i, 0);
    131.     wsprintf(text, "%02X|%02X", LOBYTE(around), HIBYTE(around));
    132.     DrawStatusText(hDC, &rt, text, SBT_POPOUT);
    133.     return true;
    134. }
    И необходимые вставки:
    Код (Text):
    1. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    2. BITMAPINFOHEADER bh;
    3. int     times;
    4. ...
    5.     case WM_TIMER:
    6.         hdc = GetDC(hWnd);
    7.         Do_Step(hdc);
    8.         ReleaseDC(hWnd, hdc);
    9.         break;
    10.     case WM_KEYDOWN:
    11.         hdc = GetDC(hWnd);
    12.         switch(LOWORD(wParam)) {
    13.         case VK_ESCAPE:
    14.             while(Do_Step(hdc))
    15.                 continue;
    16.             times = 0;
    17.             break;
    18.         case VK_RETURN:
    19.             times = 100;
    20.             break;
    21.         default:
    22.             times = 1;
    23.         }
    24.         while(times --)
    25.             Do_Step(hdc);
    26.         ReleaseDC(hWnd, hdc);
    27.         break;
    28. ...
    29.     case WM_DESTROY:
    30.         DeleteObject(hBmp);
    31.         ReleaseDC(NULL, hBmpDC);
    32.         PostQuitMessage(0);
    33.         break;
    34.     case WM_CREATE: // Create out bitmap and building complex spot
    35.         ZeroMemory(&bh, sizeof(bh));
    36.         bh.biSize = sizeof(bh);
    37.         bh.biWidth = BMP_WIDTH;
    38.         bh.biHeight = BMP_HEIGHT;
    39.         bh.biPlanes = 1;
    40.         bh.biBitCount = 32;
    41.         hBmp = CreateDIBSection(NULL, PBITMAPINFO(&bh), DIB_RGB_COLORS, (PVOID*)&pBmp, NULL, NULL);
    42.         hBmpDC = CreateCompatibleDC(NULL);
    43.         SelectObject(hBmpDC, hBmp);
    44.         SelectObject(hBmpDC, GetStockObject(WHITE_PEN));
    45.         SelectObject(hBmpDC, GetStockObject(WHITE_BRUSH));
    46.         for(i = 0; i < 360; ++ i) {
    47.             if(i < 270)
    48.                 point[i].x = long(BMP_WIDTH / 2 + float(sin(float(PI * i / 170.0f)) * (rand() % 2 + BMP_WIDTH / 2 - 4))),
    49.                 point[i].y = long(BMP_HEIGHT / 2 + float(cos(float(PI * i / 170.0f)) * (rand() % 2 + BMP_HEIGHT / 2 - 4)));
    50.             else
    51.                 point[i].x = long(BMP_WIDTH / 2 - float(sin(float(PI * i / 60.0f)) * (rand() % 2 + BMP_WIDTH / 3 - 4))),
    52.                 point[i].y = long(BMP_HEIGHT / 2 + float(cos(float(PI * i / 40.0f)) * (rand() % 2 + BMP_HEIGHT / 3 - 4)));
    53.         }
    54.         Polygon(hBmpDC, point, i);
    55.         ZeroMemory(&point, sizeof(point));
    56.         point[MAX_POINTS - 1].x = -1;
    57.         point[MAX_POINTS - 1].y = -1;
    58.         // Move image from RGB to Alpha
    59.         for(i = 0; i < BMP_SQUARE; ++ i)
    60.             pBmp[i] |= pBmp[i] ? 0xFF000000 : 0x00000000;
    61.         //SetTimer(hWnd, 1, 7, NULL);
    62.         break;
    Думаю, это всё. Кто решит проверить алгоритм в действии, без проблем вставит это в пустой Си-проект.
     
  3. qqwe

    qqwe New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2009
    Сообщения:
    2.914
    Paguo_86PK
    попробуйте оттолкнуться от http://potrace.sourceforge.net/
     
  4. Paguo_86PK

    Paguo_86PK Руслан

    Публикаций:
    0
    Регистрация:
    8 окт 2007
    Сообщения:
    911
    Адрес:
    Ташкент
    Оказалось оффициально такие алгоритмы называются "жуками", ползущими точно по контуру объектов. Правда многие из алгоритмов работают с 8-ю и 24-я соседями и принцип там сложнее.
    Вот ниже я выкладываю готовый проект.
    После компиляции и запуска можно смело нажать ESC и дождаться построения всего контура.
    Если в цикле WM_CREATE изменить параметры в строчках с sin/cos, можно изменить форму фигуры. При этом нажатие на ESC может привести к бесконечному циклу и ошибке. Потому советую после изменения фигуры протрассировать её.
    Для этого следует нажимать ПРОБЕЛ или ENTER. Пробелом делается один шаг жука, в правом-верхнем углу окна отображается Zoom ближайщего пространства жука. А в правом-нижнем углу окна выводится "зрение" жука: Состояние пяти сенсоров.
    Галочками помечается текущий статус, серостью - предыдущий. В центре - Hex-коды текущей обстановки и предыдущей. Именно в соответствии с этими кодами и строилась таблица "рефлексов" жука.
    Enter делает серию шагов.

    Это всё. Вот листинг на языке Си:
     
  5. DarkAngel

    DarkAngel New Member

    Публикаций:
    0
    Регистрация:
    15 ноя 2010
    Сообщения:
    12
    Просьба не расценивать это сообщение как рекламу. В настоящее время в мире создано множество редакторов, эл таблиц, графических пакетов, бесплатных и пиратских, но активно продолжается создание их клонов, созданных одним программистом. Чисто накопление опыта, хобби, личный интерес.

    Пройдет еще немного времени и Вы от создания простейшего бота с запрограммированным интеллектом перейдете к созданию простой игры. А начнется это с выбора подходящего игрового движка. Пожалуй, создание игр - это единстенная перспективная отрасль программирования. Возьмем, например S.T.A.L.K.E.R. Зов Припяти. После прохождения игры можно гулять по просторам трехмерной реальности, воссозданной авторами игры с фотографической точностью. 3D-ввижок xRay правильно воспроизводит геометрию и перспективу объектов, что снижает нагрузку на центральную нервную систему. Стоит прочитать документацию к игре, в которой упоминается, что неправильное сочетание цветовых пятен в игре может приводить к быстрой утомляемости и вызвать приступы эпилепсии. Честно, на таких играх отдыхаешь. Пожалуй, только растительный покров и деревья сделаны несколько топорно.
    В Интернете можно найти бесплатный движок трехмерной реальности OGRE с открытым кодом. Мне понравилась демка со Стоунхендом (magicofstonehenge - 8.7мег). Его можно использовать для своих проектов, презентаций и тд. После дополнения его необходимыми фичами из него можно сделать игровой движок с ботами.
     
  6. Paguo_86PK

    Paguo_86PK Руслан

    Публикаций:
    0
    Регистрация:
    8 окт 2007
    Сообщения:
    911
    Адрес:
    Ташкент
    Написaл фильтр, в функцию которого входит копирования буфера кадра источника в буфер приёмника. Но, с небольшой продвинутой фишкой:
    Каждый пиксел - 32 бита RGB+Alpha. Если Alpha == 0, то копируется всё линейно и быстро (метка moveARGB_Y).
    В противном случае, 24 бита RGB - это X и Y по 12 бит, указывающие координаты читаемого пиксела для подстановки. А сама Alpha указывает на индекс потока (видео с выбранной веб-камеры или avi).
    Всего потоков - 9. Так как Alpha - 8 бит, младшая тетрада - индекс 1-9 указывающий на конкретный поток, а 0 - текущий. Причём, нет разницы в разрешении выбранного потока, так как всё перемножается. Если нужно обойтись без коррекции координат, используются индексы 10-15, что являются теми же потоками 6-1, но с абсолютными координатами.
    Как Вы поняли уже, код достаточно замороченный. В режиме реального времени фильтр может копировать видео с восьми разных источников в один общий.

    Почему бы не использовать, например, OpenGL? Он используется, но нетрадиционно. Он "натягивает" с перспективой несколько текстур с координатными сетками, которые и образуют X/Y-координаты в RGB-битах. То есть, запускается оболочка, которая средствами OpenGL прорисовывает план сцены. Затем, оболочку можно закрыть (чаще - она обрушается сама), если конечно не нужна динамика колладжа из разных видео.
    В любом случае, представленный ниже код всё делает сам.
    Код (ASM):
    1.             mov         ecx,bitmap
    2.             mov         esi,src
    3.             mov         edi,dst
    4.             mov         eax,h
    5.             mov         j,eax
    6.             jmp         moveARGB_Y
    7. moveARGB_N: pop     edx
    8.             jmp     moveARGB_I
    9. moveARGB_M: push    edx
    10.             mov     ebx,pFilterData[ebx].pBlanks[eax*4]
    11.             mov     eax,0x000FFFFF
    12.             and     eax,edx
    13.             shr     eax,10
    14.             mov     edx,1024
    15.             neg     eax
    16.             lea     eax,[eax+edx]
    17.             mov     edx,PEUR_BITMAP[ebx].bih.biYPelsPerMeter
    18.             cmovnc  edx,PEUR_BITMAP[ebx].bih.biYPelsPerMeter
    19.             mul     edx
    20.             xor     eax,0x000FFC00
    21.             and     eax,0x000FFC00
    22.             xchg    eax,[esp]
    23.             and     eax,0x000003FF
    24.             mov     edx,1024
    25.             cmp     edx,PEUR_BITMAP[ebx].bih.biXPelsPerMeter
    26.             cmovnc  edx,PEUR_BITMAP[ebx].bih.biXPelsPerMeter
    27.             mul     edx
    28.             pop     edx
    29.             shr     eax,10
    30.             add     eax,edx
    31.             mov     eax,PEUR_BITMAP[ebx].raster[eax*4]
    32.             jmp     moveARGB_I
    33. moveARGB_L: mov     edx,[ecx+1024*1024*4]
    34.             rol     edx,8
    35.             bswap   edx
    36.             mov     eax,edx
    37.             test    eax,0x00F00000
    38.             je      moveARGB_J
    39. moveARGB_K: mov     ebx,pfd
    40.             shr     eax,20
    41.             and     eax,0x0F
    42.             je      moveARGB_J
    43.             cmp      al,10
    44.             jc      moveARGB_M
    45.             or      eax,0xFFFFFFF0
    46.             neg     eax
    47.             and     edx,0x000FFFFF
    48.             mov     ebx,pFilterData[ebx].pBlanks[eax*4]
    49.             mov     eax,PEUR_BITMAP[ebx].raster[edx*4]
    50.             jmp     moveARGB_I
    51. moveARGB_J: mov     ebx,0x000003FF
    52.             and     ebx,edx
    53.             mov     eax,0x000FFC00
    54.             and     eax,edx
    55.             shr     eax,10
    56.             mul     h
    57.             shr     eax,10
    58.             mul     srcpitch
    59.             shr     eax,2
    60.             xchg    eax,ebx
    61.             mul     w
    62.             mov     edx,src
    63.             shr     eax,10
    64.             add     eax,ebx
    65.             mov     eax,[edx+eax*4]
    66. moveARGB_I: mov     [edi],eax
    67.             mov     eax,0xFF000000
    68.             or      eax,[esi]
    69.             mov     [ecx],eax
    70.             add     esi,4
    71.             add     edi,4
    72.             add     ecx,4
    73.             mov     eax,esi
    74.             or      eax,edi
    75.             or      eax,ecx
    76.             and     eax,0x0000000C
    77.             jnz     moveARGB_L
    78.             jmp     moveARGB_V
    79. moveARGB_Y: mov         eax,w
    80.             mov         i,eax
    81. moveARGB_X: movdqa      xmm1,[ecx+1024*1024*4]
    82.             psrlq       xmm1,24
    83.             packssdw    xmm1,xmm1
    84.             packsswb    xmm1,xmm1
    85.             movd        eax,xmm1
    86.             and         eax,eax
    87.             jne         moveARGB_L//*/
    88.             movdqa      xmm1,[ecx]
    89.             movdqa      [edi],xmm1
    90.             pcmpeqb     xmm1,xmm1
    91.             pslld       xmm1,24
    92.             por         xmm1,[esi]
    93.             movdqa      [ecx],xmm1
    94.             add         esi,16
    95.             add         edi,16
    96.             add         ecx,16
    97. moveARGB_V: sub         i,4
    98.             jnle        moveARGB_X
    99.             mov         eax,sm
    100.             lea         esi,[esi+eax*4]
    101.             mov         eax,dm
    102.             lea         edi,[edi+eax*4]
    103.             mov         eax,jump
    104.             lea         ecx,[ecx+eax*4]
    105.             dec         j
    106.             jnz         moveARGB_Y
    А вот как это выглядит:

    Заметьте, что скорость движения центрального "баннера" меняется, что не является глюком, а управляется в оболочке вручную в реал-тайме. То, что "баннер" оставляет след - тоже опция с отключением предварительной зачистки кадра…
    Как Вы понимаете, идея сама по-себе достаточно занятная. В первую очередь тем, что:
    Запускается до 9 экземпляров VirtualDub каждый со своим источником видео. Затем, запускается оболочка со Squirrel-сценарием, в котором строится сцена и, при желании, анимируется. Если при анимации оболочка обрушится, просто анимация застрянет, но в VirtualDub'е все потоки будут продолжать показываться как есть…

    P.S.: Есть один изъян: Вся свистопляска в главном экземпляре VirtualDub жрёт до 22% процессорного времени (и от 3% при нормальном копировании одного потока), так как доступ происходит почти к рандомным областям памяти…
    Есть ли способы устранения этого? Например:
    Если строку кадра сначала заполнять в стек из разных областей памяти, а затем из стека выбрасывать линейно в буфер.
    Или есть OpenGL-механизмы?
    Да, я качал примеры с динамическими текстурами и прямым доступом к ним. Но, у меня каждый из девяти VirtualDub открывает свой bmp-файл на диске с мэппингом, а главный - читает всё с тех мэппов. Если позакрывать все сторонние, просто потоки разных источников уйдут в "паузу".
    По-идее, надо будет в каждом экземпляре VirtualDub буфер источника выбрасывать в OpenGL-текстуру со своим индексом, а в главном - всё собирать вместе? Но, даже в пределах одной "оболочки" разные потоки никак не могли управиться с OpenGL-контекстом и пришлось всё тупо проделывать в одном потоке. Как же тогда всё согласовать в разных экземплярах VirtualDub???