Форум программистов, компьютерный форум, киберфорум
Pure Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.74/95: Рейтинг темы: голосов - 95, средняя оценка - 4.74
Ты за кого меня держиш!?
 Аватар для ЦарьКащей
22 / 23 / 7
Регистрация: 26.10.2011
Сообщений: 308
Записей в блоге: 1

Обработка изображения с веб камеры на предмет движущихся объектов\изменившихся пикселей

14.08.2012, 21:13. Показов 19661. Ответов 94
Метки нет (Все метки)

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

PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#WM_CAP_START                          = #WM_USER
#WM_CAP_SET_CALLBACK_ERROR             = #WM_CAP_START + 2
#WM_CAP_SET_CALLBACK_CAPCONTROL_STATUS = #WM_CAP_START + 3
#WM_CAP_SET_CALLBACK_YIELD             = #WM_CAP_START + 4
#WM_CAP_SET_CALLBACK_FRAME             = #WM_CAP_START + 5
#WM_CAP_SET_CALLBACK_VIDEOSTREAM       = #WM_CAP_START + 6
#WM_CAP_SET_CALLBACK_WAVESTREAM        = #WM_CAP_START + 7
#WM_CAP_GET_STATUS                     = #WM_CAP_START + 54;-------------------
#WM_CAP_DRIVER_CONNECT                 =  #WM_USER + 10
#WM_CAP_DRIVER_DISCONNECT              =  #WM_USER + 11
#WM_CAP_DRIVER_GET_CAPS                = #WM_CAP_START + 14
#WM_CAP_DLG_VIDEOFORMAT                = #WM_CAP_START + 41
#WM_CAP_DLG_VIDEOSOURCE                = #WM_CAP_START + 42
#WM_CAP_DLG_VIDEODISPLAY               = #WM_CAP_START + 43
#WM_CAP_SET_PREVIEW                    = #WM_CAP_START + 50
#WM_CAP_SET_PREVIEWRATE                = #WM_CAP_START + 52
#WM_CAP_GET_STATUS                     = #WM_CAP_START + 54
#WM_CAP_FILE_SAVEDIB                   =  #WM_USER + 25
#WM_CAP_SET_SCALE                      =  #WM_USER + 53
#WM_CAP_SET_CALLBACK_CAPCONTROL        = #WM_CAP_START + 85
 
 
 
;------------------------------------------------------------------------------------------------------------
 
 
 
Structure CAPSTATUS  ;Тут нас интересуют высота и ширина(первые две строчки)
  uiImageWidth.l 
  uiImageHeight.l 
  fLiveWindow.l 
  fOverlayWindow.l 
  fScale.l 
  ptScroll.Point 
  fUsingDefaultPalette.l 
  fAudioHardware.l 
  fCapFileExists.l 
  dwCurrentVideoFrame.l 
  dwCurrentVideoFramesDropped.l 
  dwCurrentWaveSamples.l 
  dwCurrentTimeElapsedMS.l 
  hPalCurrent.l 
  fCapturingNow.l 
  dwReturn.l 
  wNumVideoAllocated.l 
  wNumAudioAllocated.l 
EndStructure
 
CapStat.CAPSTATUS
 
Structure VIDEOHDR; в этой структуре первая строчка - кадр
  lpData.l
  dwBufferLength.l
  dwBytesUsed.l
  dwTimeCaptured.l
  dwUser.l
  dwFlags.l
  dwReserved.l[3]
EndStructure
 
Structure SBGR ;Цвета по байту на синий зелёный и красный считываемые из памяти далее
  b.b
  g.b
  r.b  
EndStructure
 
 
 
 
Global width     = 300
Global height    = 240
 
Global widthImg  = 0
Global heightImg = 0
 
Global Min       = 90
Global Max       = 110
 
Global Dim  B (0, 0);Объявление двух массивов, один для хранения старых данных, второй для записи в него результата
Global Dim  C (0, 0) ; Redim
 
 
 
Enumeration
  #STP         = 1;Шаг цикла. Если менять то надо в "*VideoMemoryAdress1 + 3" тройку умножать на шаг. Суть шага такова, что если он = 2 то скорость обработки увеличивается вдвое а качество тудаже уменьшается. 
  #Menu        = 1;Это всё про меню, оно для красоты
  #Menu_Device = 2
  #Menu_exit   = 3
  #Menu_Pause  = 4
EndEnumeration
 
 
 
;------------------------------------------------------------------------------------------------------------
 
 
 
Procedure FrameCallback(hWnd, *lpVHdr.VIDEOHDR);
  Protected *VideoMemoryAdress1.SBGR = *lpVHdr\lpData;Пошоль просесс
  Protected xn,yn, color, SA, SB
  For xn = heightImg - 1 To 0 Step - #STP
    For yn = 0 To widthImg - 1 Step #STP
      
      color = RGB(*VideoMemoryAdress1\r & $FF, *VideoMemoryAdress1\g & $FF,;считываем цвет *VideoMemoryAdress1\b & $FF)
      *VideoMemoryAdress1 + 3 ;перескакиваем на следующие 3 байта
      
      SA = color / 100;Один процент цвета 
      SB = B(yn, xn);Извлекаем цвет из предыдущего кадра, он в виде цифры в массиве
      B(yn, xn) = color;Присваиваем туда же новое значение, обновляя кадр
      If SA = 0 ; делить на 0 нельзя
        Shodstvo = 0
      Else
        Shodstvo =  SB / SA; Точка отсчёта равна ста процентам, а дальше дело техники, 110 мньше 100 на 10, 120 больше 100 на 20, чем больше разница - Shodstvo - 100, тем больше различий между пикселями в 2-х кадрах в одном и том же месте 
        If Shodstvo < 100 And shodstvo > Min Or Shodstvo > 100 And Shodstvo < Max
          С(yn, xn) = RGB(0, 0, 0))
        Else
          С(yn, xn) = color);Если ещё немного подшаманить и сдеать отрисовку результата а не присвоение значений элементам массива, то получим чёрный экран на котором будут видны только подвижные объекты. Хорошо фильтрует серую картинку, по тому что чем меньше диапазон значений, тем меньше разница между якобы похожими пикселями
        EndIf
      EndIf
      
    Next
  Next
 EndProcedure    
    
    
 
 
;------------------------------------------------------------------------------------------------------------
 
 
 
 
hWnd = OpenWindow(0, 0, 0, width + 4, height + 60, "", #PB_Window_SystemMenu| #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
 
If CreateMenu(#Menu, WindowID(0))
  MenuTitle("Программа")
    MenuItem(#Menu_exit, "Выключить")
      MenuBar()
    MenuItem(#Menu_Pause, "?")
  MenuTitle("Настройки")
    MenuItem(#Menu_Device, "Сменить устройство")
EndIf
 
 
 
;------------------------------------------------------------------------------------------------------------
 
 
 
 
If OpenLibrary(0, "AVICAP32.DLL")
  hWebcam = CallFunction(0, "capCreateCaptureWindowA", 0, #WS_VISIBLE+#WS_CHILD, 2, 20, width, height, hWnd, 0)
  
  SendMessage_(hWebcam, #WM_CAP_DRIVER_CONNECT          , 0 , 0);Подключаем устройство
  SendMessage_(hWebcam, #WM_CAP_SET_SCALE               , 1 , 0)
  SendMessage_(hWebcam, #WM_CAP_SET_PREVIEWRATE         , 50, 0)
  SendMessage_(hWebcam, #WM_CAP_SET_PREVIEW             , 1 , 0)
  
  SendMessage_(hWebcam, #WM_CAP_GET_STATUS              , SizeOf(CAPSTATUS), CapStat);------------
  widthImg  = CapStat\uiImageWidth;Устанавливаем ширину
  heightImg = CapStat\uiImageHeight;высоту
  ReDim B(widthImg, heightImg);устанавливаем размеры массивов, чтоб всё соответсвовало всему
  ReDim C(widthImg, heightImg)
  SendMessage_(hWebcam, #WM_CAP_SET_CALLBACK_FRAME      , 0 , @FrameCallback());и получаем заветные кадры
  
  
  
;------------------------------------------------------------------------------------------------------------
  
  
 
Repeat
  
  Event = WindowEvent()
  Select Event
      
    Case #PB_Event_CloseWindow
      Break
      
    Case #PB_Event_Menu
      Select EventMenu()
        Case #Menu_exit
          Break
          
          Case #Menu_Pause
            
          Case #Menu_Device
            
        EndSelect
      
  EndSelect
ForEver
  
  
  
  
;------------------------------------------------------------------------------------------------------------
  
  
  
  
  SendMessage_(hWebcam, #WM_CAP_SET_PREVIEW       , 0, 0)
  SendMessage_(hWebcam, #WM_CAP_DRIVER_DISCONNECT, @"BLUBBER", 0)
  
  CloseWindow(0)
  CloseLibrary(0)
  
EndIf
 
End
Конец

Добавлено через 41 секунду
Там только надо память очищать чтоб не утекла.

Добавлено через 4 минуты
По остальным вопросам лазим тут: http://msdn.microsoft.com/en-u... s.85).aspx
тут: http://purebasic.ru/manual.php?id=1104&lng=rus
тут: http://www.google.ru/webhp?source=search_app
и здесь.
2
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
14.08.2012, 21:13
Ответы с готовыми решениями:

Обработка изображения(группировка пикселей)
Здравствуйте, почитал статью http://job-interview.ru/articles/post/362 и захотел реализовать тоже самое, но что-то не получилось. В чем...

Обработка изображения размером 800х600 пикселей
Здравствуйте,подскажите пожалуйста, что не так. Есть исходное изображение размером 800х600 пикселей. Вырезаю из него фрагмент и хочу...

Обработка изображения: поиск пикселей определённого цвета
Добрый вечер! Имеется такое задание: есть изображение, нужно найти пиксели определенного цвета и записать их координаты в массив. В...

94
Кормпилятор
 Аватар для Quiet Snow
5044 / 1718 / 409
Регистрация: 25.04.2010
Сообщений: 4,827
Записей в блоге: 2
21.08.2012, 05:19
Студворк — интернет-сервис помощи студентам
Отрицательное значение Color имеет право на существование?
Да вы же читаете 1 байт функцией PeekB, вам возвращаются значения от -128 до 127.
Функция читает байт со знаком. PeekA читает байт без знака...
Вопрос в другом, куда читаются эти изменения, если не в идентичную структуру, то
битовая интерпретация данных будет неверна, точнее компилер будет думать, что работает
с другим типом данных, эти вопросы машиной не контролируются, комп тупо складывает,
умножает, вычитает эти байты, ему эти типы данных нужны чтобы строить маш. код программы.
Знаковые числа в памяти и регистрах представлены в виде дополнительного кода.
Для знаковых и беззнаковых разные операции умножения и деления.

Глядя на ваш код видно, что читаются байты, а потом вы пытаетесь воспроизаести
полноцветку из ничего, RGB(Red(Color), Green(Color), Blue(Color). Нужно читать за раз либо 3
байта, либо 4(это всё должно быть в документации по dll, с которой вы работаете).
Вы должны найти в исходной структуре как расположены байты R,G,B и скопировать их
в Image как показал вам Pro_grammer. Эту операцию можно делать через память,
получив указатель на буфер Image.

3) Как правильно организовать работу с памятью в данном случае?
С изображениями удобнее работать в двойном цикле, копирование памяти 1-м циклом
чуть быстрее работает, но вы должны чётко представлять структуру исходника(Source) и
структуру назначения(Destination).
1
Ты за кого меня держиш!?
 Аватар для ЦарьКащей
22 / 23 / 7
Регистрация: 26.10.2011
Сообщений: 308
Записей в блоге: 1
21.08.2012, 20:53  [ТС]
Чую я пока эта тема не моя. Трудно понять что ищу и как с этим разбираться, поэтому когда пойму ещё вернусь к данному вопросу.
0
Кормпилятор
 Аватар для Quiet Snow
5044 / 1718 / 409
Регистрация: 25.04.2010
Сообщений: 4,827
Записей в блоге: 2
22.08.2012, 13:13
Трудно понять что ищу
Ищете вы формат исходных данных, приходящих с вашей веб камеры и задача состоит
в том, чтобы скопировать эти данные в image, с которым можно делать в PureBasic
практически всё, что угодно. Вероятно различаются форматы хранения этих картинок
(но не факт, что различаются, могут и совпадать, тогда задача упрощается в разы).

и как с этим разбираться
Если лень читать документацию, то методом научного тыка))), написать свои дебаг функции и
посмотреть порядок байт RGB, подставляя к веб камере красные, зелёные и синие предметы.

Чую я пока эта тема не моя.
Задача не так сложна как вы думаете, вам нужно понять какое разрешение выдаёт камера,
если 640x480 то объём данных будет равен
Объём_данных = 640 * 480 * кол-во_байт_на_пиксель
И ваша прога не должна считывать из буфера больше данных, т.к. будет тупо ошибка доступа к памяти.
А кол-во байт на пиксель скорее либо 3, либо 4. Попробуйте разные варианты, может веб
камера возвращает в 16 битном формате(2 байта, по 5 бит на каждый цвет или 5 бит синий,
6 бит зелёный, 5 бит красный). Там делов то 10 минут протестировать.
И все ошибки у вас из-за того что этот формат данных вы неправильно читаете(нельзя
превышать границы считывания) + наверняка всю информацию о формате изображения можно
получить функциями библиотеки, которой вы пользуетесь и не тыкать пальцем в небо.

Image хранит своё изображение в формате
AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB
Т.е. первые 8 бит - синий
следующие 8 бит - зелёный
следующие 8 бит - красный
и последние 8 бит - альфа канал

Но это не вся информация о структуре изображения, нужно ещё знать как строки пикселей
располагаются в памяти. А располагаются они на изображении слева направо и снизу вверх,
если в памяти идти по порядку.

Код ваш примет вид:
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
   ;  Получить эти значения библиотечной функцией
   ;  Чтобы они соответствовали формату данных веб камеры
  BytePerPixel = 3
  ImgWidth = 640
  ImgHeight = 480
    BuffWidth = ImgHeight * BytePerPixel   ; Размер одной строки пикселей в нашем Image
    DatLen = ImgWidth * ImgHeight * BitPerPixel   ; Общий размер изображения
 
  im1 = CreateImage (#PB_Any, ImgWidth, ImgHeight, 32)
 
  StartDrawing(ImageOutput(im1))
    *Dbuf = DrawingBuffer()       ;  Получим смещение буфера Image
  StopDrawing()
  *VCamBuf = . . . ваш буфер веб камеры (дописать тут код получения указателя)
  A = 255                         ;   Альфа канал непрозрачен
  For iy = 0 TO ImgHeight - 1
     For ix = 0 To ImgWidth - 1
       ;  Читаем байты последовательно (если порядок другой меняем этот код)
         R = PeekA(*VCamBuf): *VCamBuf + 1
         G = PeekA(*VCamBuf): *VCamBuf + 1
         B = PeekA(*VCamBuf): *VCamBuf + 1   ;  +1  если 3 байта на пиксель   и   +2  если 4 байта н.п.
       ;  Пишем байты в Image по адресу пикселя
         PixAdr = ix * BytePerPixel + ((ImgHeight - 1) - iy) * BuffWidth
         PokeL(*Dbuf + PixAdr, B | (G << 8) | (R << 16) | (A << 24))
     Next
  Next
Код этот отладочный, дальше его нужно будет оптимизировать, рефакторить и всячески приводить
в порядок. Сначала пишем так "чтобы работало", а потом уже оптимизируем.
Оптимизируются такие вещи очень хорошо операциями сдвига бит и заранее заготовленными
таблицами.

Добавлено через 36 минут
Немного накосячил в коде там, уже поправил всё.
1
Ты за кого меня держиш!?
 Аватар для ЦарьКащей
22 / 23 / 7
Регистрация: 26.10.2011
Сообщений: 308
Записей в блоге: 1
30.08.2012, 19:48  [ТС]
После застоя решил таки продолжить. И начну с того, что исправил метод отбора (прямо таки эвристический) похожих значений в массивах:
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Width  = 100
Height = 100
 
Global Dim A(Width, Height)
Global Dim B(Width, Height)
Global Dim C(Width, Height)
 
  For n = 0 To Width
    For s = 0 To Height
      B(n,s) = Random(100)
      A(n,s) = Random(100)
    Next
  Next
 
  Procedure R(Width, Height)
    For n = 0 To Width
      For s = 0 To Height
        Procent.f = B(n,s) / 100
        If Procent > 0
          Shodstvo.f = A(n,s) / Procent
          Debug Shodstvo
          If Shodstvo > 90 And Shodstvo < 110
            C(n,s) = A(n,s)
          EndIf
        Else
          C(n,s) = 0
        EndIf
      Next
    Next
  EndProcedure
 
R(Width, Height)
Оказывается просто был неправильным тип переменных. А я то дурья бошка не мог понять, почему всё время после деления на 100 получается ноль. Это кому интересно.

Добавлено через 1 минуту
Затем хотелось бы спросить, для чего нужен символ ":" в коде?

Добавлено через 7 минут
Далее.
PureBasic
1
PokeL(*Dbuf + PixAdr, B | (G << 8) | (R << 16) | (A << 24))
Что означают в данном случае символы сравнения "<<"
PureBasic
1
 *Dbuf = DrawingBuffer()       ;  Получим смещение буфера Image
Что значит "Смещение буфера"?
A = 255 ---- Как понять используется ли там альфа канал и если нет, как это обойти?

PureBasic
1
2
3
4
5
6
7
8
9
10
11
For iy = 0 TO ImgHeight - 1
     For ix = 0 To ImgWidth - 1
       ;  Читаем байты последовательно (если порядок другой меняем этот код)
         R = PeekA(*VCamBuf): *VCamBuf + 1
         G = PeekA(*VCamBuf): *VCamBuf + 1
         B = PeekA(*VCamBuf): *VCamBuf + 1   ;  +1  если 3 байта на пиксель   и   +2  если 4 байта н.п.
       ;  Пишем байты в Image по адресу пикселя
         PixAdr = ix * BytePerPixel + ((ImgHeight - 1) - iy) * BuffWidth
         PokeL(*Dbuf + PixAdr, B | (G << 8) | (R << 16) | (A << 24))
     Next
  Next
Тут в принципе всё понятно кроме того о чём уже спросил и хитрых манипуляций с PixAdr.
Зачем писать в память это дело(третья с конца строчка)? так быстрее обработка или что?

Что происходит в третей с конца строки кроме очевидной записи в память чегото там?

Добавлено через 6 минут
И крайний вопрос.
В чём причина завышения значения ширины и высоты изображения в буфере видеоустройства на 50?
Тоесть выдаваемые ширина\высота = 320\240 а реальные 270\190.

Добавлено через 24 минуты
Вот что набросал. Естественно оно не работает.
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Procedure FrameCallback (hWnd, *lpVHdr.VIDEOHDR)
  Protected *VideoMemoryAdress.SBGR = *lpVHdr\lpData
  Protected xn,yn
  StartDrawing(ImageOutput(ImgOld))
  For n = 0 To *lpVHdr\dwBufferLength / 3
    R = PeekB(*VideoMemoryAdress\r & $FF)
    G = PeekB(*VideoMemoryAdress\g & $FF)
    B = PeekB(*VideoMemoryAdress\b & $FF)
    
    *VideoMemoryAdress + 3
    
    Plot(xn, yn, RGB (R, G, B))
  Next
  StopDrawing()
 EndProcedure
Осмысляю стандартный пример. И вот что там по этому поводу пишут:
PureBasic
1
2
3
4
5
6
Procedure FrameCallback(lwnd.l, *lpVHdr.VIDEOHDR)
  For k=0 To *lpVHdr\dwBufferLength-1
    Color = PeekB(*lpVHdr\lpData+k)
    PokeB(*lpVHdr\lpData+k, RGB(Blue(Color), Green(Color), Red(Color)))
  Next
EndProcedure
Добавлено через 39 секунд
И стандартный пример таки работает.

Добавлено через 15 минут
Сделал на основе примера
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
 
Procedure FrameCallback (hWnd, *lpVHdr.VIDEOHDR)
  Protected *VideoMemoryAdress.SBGR = *lpVHdr\lpData
  Protected xn, yn
  StartDrawing(ImageOutput(ImgOld))
  For yn=0 To widthImg - 1
    For xn=0 To heightImg - 1
      Color = PeekB(*lpVHdr\lpData+xn + yn)
      Plot(yn, xn, Color)
    Next
  Next
  StopDrawing()
 EndProcedure
Не работает дальше вывода картинки, которая заставка на время подключения драйвера. Ищу проблему.
0
 Аватар для Pro_grammer
6807 / 2839 / 527
Регистрация: 24.04.2011
Сообщений: 5,308
Записей в блоге: 10
30.08.2012, 21:02
Я на элементарные вопросы отвечу

Цитата Сообщение от ЦарьКащей Посмотреть сообщение
для чего нужен символ ":" в коде?
Для объединения разных операторов в одной строке
Т.о. это
PureBasic
1
R = PeekA(*VCamBuf): *VCamBuf + 1
значит то же что и это
R = PeekA(*VCamBuf)
*VCamBuf + 1

Цитата Сообщение от ЦарьКащей Посмотреть сообщение
в данном случае символы сравнения "<<"
Это не сравнение, а побитовый сдвиг влево, читаем справку
Example:
a=%1011 << 1 ; The value of a will be %10110. %1011=11, %10110=22
b=%111 << 4 ; The value of b will be %1110000. %111=7, %1110000=208
Вправо тоже бывает
1
Ты за кого меня держиш!?
 Аватар для ЦарьКащей
22 / 23 / 7
Регистрация: 26.10.2011
Сообщений: 308
Записей в блоге: 1
30.08.2012, 21:54  [ТС]
Теперь видно, что BGRA там
PureBasic
1
PokeL(*Dbuf + PixAdr, B | (G << 8) | (R << 16) | (A << 24))
переделывается в ARGB.
А в памяти байты в обратном порядке чтоль? зачем их сдвигать?
...
Неужель позиция в с которой считываются и в которую записываются байты у разных областей памяти одинаковая..

Добавлено через 3 минуты
Почти понял, почти сознал.

Добавлено через 43 секунды
убейте комара!думать мешает!
0
Ты за кого меня держиш!?
 Аватар для ЦарьКащей
22 / 23 / 7
Регистрация: 26.10.2011
Сообщений: 308
Записей в блоге: 1
01.09.2012, 01:39  [ТС]
Опять результат:
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Procedure FrameCallback (hWnd, *lpVHdr.VIDEOHDR)
  
  StartDrawing(ImageOutput(ImgOld))
  *Dbuf = DrawingBuffer()
  StopDrawing()
  *CamBuf = *lpVHdr\lpData
    
  Protected xn, yn, R, G, B, A,PixAdr
  
  For yn=0 To widthImg - 1
    For xn=0 To heightImg - 1
         R = PeekB(*CamBuf): *CamBuf + 1
         G = PeekB(*CamBuf): *CamBuf + 1
         B = PeekB(*CamBuf): *CamBuf + 1
         PixAdr = yn * 3 + (xn) * BuffWidth
         PokeB(*Dbuf + PixAdr, R | G | B)
       Next
     Next
     
  SetGadgetState(1, ImageID(ImgOld))
 EndProcedure
Уже заметный прогресс. Чтото да отображает. Даже цветное. Но всёравно я нихрена в этих строках логики не пойму:
PureBasic
1
2
PixAdr = ix * BytePerPixel + ((ImgHeight - 1) - iy) * BuffWidth
         PokeL(*Dbuf + PixAdr, B | (G << 8) | (R << 16) | (A << 24))
Адрес пикселя это отступ сверху умноженный на высоту строки + отступ слева.
Или при ix = 3 и ImgHeight - 1 = 189
PixAdr = 3*3 + 189*(189*3)
Циферка не великовата?

А картинка получается такая:

\\\\\\\\\\\ \\\\
\\\\\\\\\\\\\ \\
\\\\\\\\\\\\\\ \

покосившийся квадрат. жаль геометрию в школе не учил ато точно сказал бы параллепипедом выводится изображение или паралелограммом. Смещение имеет место, а почему?

Добавлено через 43 минуты
Промелькнула очередная мысль
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Procedure FrameCallback (hWnd, *lpVHdr.VIDEOHDR)
  
  StartDrawing(ImageOutput(ImgOld))
  *Dbuf = DrawingBuffer()
  StopDrawing()
  *CamBuf = *lpVHdr\lpData
    
  Protected xn, n, R, G, B, A,PixAdr
  
  For n=0 To (*lpVHdr\dwBufferLength - 1)/3
    R = PeekB(*CamBuf): *CamBuf + 1
    G = PeekB(*CamBuf): *CamBuf + 1
    B = PeekB(*CamBuf): *CamBuf + 1
    
    PokeL(*Dbuf, R) : *Dbuf + 1
    PokeL(*Dbuf, G) : *Dbuf + 1 
    PokeL(*Dbuf, B) : *Dbuf + 1
  Next
     
  SetGadgetState(1, ImageID(ImgOld))
 EndProcedure
Считывается буфер камеры вроде ничо так. А как считанное в картинку записывать правильно?
0
01.09.2012, 21:53

Не по теме:

Мне одному кажется, что человек не совсем понимает, какие манипуляции делает с прогой?

0
Ты за кого меня держиш!?
 Аватар для ЦарьКащей
22 / 23 / 7
Регистрация: 26.10.2011
Сообщений: 308
Записей в блоге: 1
01.09.2012, 23:10  [ТС]
Цитата Сообщение от >Quiet Snow< Посмотреть сообщение

Не по теме:

Мне одному кажется, что человек не совсем понимает, какие манипуляции делает с прогой?

Не тебе одному. Понимание ко мне приходит постепенно.

Добавлено через 23 минуты
Изображение 24 битное, значит в видеобуфере значиения цветов от -128 до 127, что соответствует диапазону 0 - 256.
Альфа канала судя по всему нет, так как возвращаемая "площадь" изображения (153600 байт) минус 100 и делённая на 3 равна размеру видеобуфера и значит что если даже значения цвета в видеобуфере расположены не как RGB а допустим как GRB, то всёравно запись по 3 байта на пиксель в буфер с картинкой должна быть корректной по крайней мере в расстановке пикселей по местам. У меня имеется некое смещение.

Думаю что используется какой то другой формат, как выяснить какой?

PeekA возращает значения без знака, это не есть хорошо. Цвета имеющие значения -128 45 128 после такого считывание становятся 128 45 128, но даже при значении 0 173 256 (+128 каждая составляющая цвета для получения диапазона 0-256) всёравно картинка остаётся как исходная в виде углеродного волокна, только уже с цветами отличающимися от серого.
Чесное слово мозг сломаю пока пойму как это считывать если носом не ткнёте пару раз.
0
Эксперт по электронике
6998 / 3314 / 341
Регистрация: 28.10.2011
Сообщений: 13,023
Записей в блоге: 7
01.09.2012, 23:24
Цитата Сообщение от ЦарьКащей Посмотреть сообщение
значиения цветов от -128 до 127
Цитата Сообщение от ЦарьКащей Посмотреть сообщение
PeekA возращает значения без знака, это не есть хорошо.

Какие -128 до 127?
Цвета представляются в виде целых, положительных чисел.
Из описания функции RGB().
Возвращает 24-битное значение цвета, соответствующее значениям цветовых компонент Red, Green, Blue. Как всегда каждое значение между 0 и 255, итого доступно 16.7 миллионов цветов.
0
Ты за кого меня держиш!?
 Аватар для ЦарьКащей
22 / 23 / 7
Регистрация: 26.10.2011
Сообщений: 308
Записей в блоге: 1
01.09.2012, 23:50  [ТС]
Появилось ещё одно предположение что считывая байты из видеобуфера надо их записывать в буфер картинки функцией
PureBasic
1
PokeL(*Dbuf, RGBA(R,G,B,A))
Тут так геморно нужно три байта в РГБ определить.

Цитата Сообщение от locm Посмотреть сообщение

Какие -128 до 127?
Цвета представляются в виде целых, положительных чисел.
Из описания функции RGB().
Ничо не знаю, Dеbug меня думаю не стал бы обманывать так как это не возвращаемое функцией RGB, а возвращаемое функцией PeekB значение.

Добавлено через 5 минут
А располагаются они на изображении слева направо и снизу вверх,
если в памяти идти по порядку.
Не в тему. Но. Не снизу вверх а сверху вниз, так как изображение из за фокусирующей линзы изначально перевёрнутое.
Ето предположение а не факт.
Но если ето факт то камеры делают придурки которым впадлу матрицу перевернуть. или драйверы пишут придурки так как матрицу перевернули, а они ещё переворачивают изображение.
0
Эксперт по электронике
6998 / 3314 / 341
Регистрация: 28.10.2011
Сообщений: 13,023
Записей в блоге: 7
01.09.2012, 23:56
Цитата Сообщение от ЦарьКащей Посмотреть сообщение
Ничо не знаю, Dеbug меня думаю не стал бы обманывать так как это не возвращаемое функцией RGB, а возвращаемое функцией PeekB значение.
Наверное Debug вам обманывает.
PureBasic
1
2
3
4
x=200
y=PeekB(@x)
Debug x
Debug y
Прочитайте про знаковые и без знаковые переменные.
0
Ты за кого меня держиш!?
 Аватар для ЦарьКащей
22 / 23 / 7
Регистрация: 26.10.2011
Сообщений: 308
Записей в блоге: 1
02.09.2012, 00:10  [ТС]
Положение изображения это условность никому не нужная, а два цикла обработки нужны только функции Plot для правильного представления координат.

Наверное Debug вам обманывает.
Добавлено через 2 минуты
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Procedure FrameCallback (hWnd, *lpVHdr.VIDEOHDR)
  
  StartDrawing(ImageOutput(ImgOld))
  *Dbuf = DrawingBuffer()
  StopDrawing()
  *CamBuf = *lpVHdr\lpData
  
  Protected xn, n, R, G, B, A,PixAdr
  For n=0 To  *lpVHdr\dwBufferLength
    Color = PeekB(*CamBuf + n)
 
    Debug Color; <--------------------- мы об этом?
 
    PokeL(*Dbuf + n, R)
  Next
  
  SetGadgetState(1, ImageID(ImgOld))
 EndProcedure
Добавлено через 2 минуты
выдаёт от -128 до 127.

Добавлено через 8 минут
PureBasic
1
2
3
4
x=200
y=PeekB(@x)
Debug x
Debug y
Два значения 200 и -56
0
Эксперт по электронике
6998 / 3314 / 341
Регистрация: 28.10.2011
Сообщений: 13,023
Записей в блоге: 7
02.09.2012, 00:52
Цитата Сообщение от ЦарьКащей Посмотреть сообщение
выдаёт от -128 до 127.
А если заменить PeekB() на PeekA()?


Цитата Сообщение от ЦарьКащей Посмотреть сообщение
Два значения 200 и -56
Но ведь изначально записали в переменную число 200, но после обработки функцией PeekB(), число стало равным -56, вывод?

А вот "волшебное превращение" числа -56 в число 200.
PureBasic
1
2
x = -56 & 255
Debug x
Добавлено через 2 минуты
Более того, числа -56 и 200 в памяти компа хранятся в одинаковом виде (в пределах одного байта).
PureBasic
1
2
Debug Bin(200, #PB_Byte)
Debug Bin(-56, #PB_Byte)
0
Ты за кого меня держиш!?
 Аватар для ЦарьКащей
22 / 23 / 7
Регистрация: 26.10.2011
Сообщений: 308
Записей в блоге: 1
02.09.2012, 01:46  [ТС]
А если заменить PeekB() на PeekA()?
Писал же что он только знак убирает, а других изменений я не увидел. Да и зачем мне 128 вместо -128. Не понимаю.

Цитата Сообщение от locm Посмотреть сообщение
Но ведь изначально записали в переменную число 200, но после обработки функцией PeekB(), число стало равным -56, вывод?

А вот "волшебное превращение" числа -56 в число 200.
PureBasic
1
2
x = -56 & 255
Debug x
Добавлено через 2 минуты
Более того, числа -56 и 200 в памяти компа хранятся в одинаковом виде (в пределах одного байта).
PureBasic
1
2
Debug Bin(200, #PB_Byte)
Debug Bin(-56, #PB_Byte)
Ето к чему?

Добавлено через 1 минуту
x = -56 & 255
Тоже самое что
x = -56 + 256

Добавлено через 37 минут
Более того, числа -56 и 200 в памяти компа хранятся в одинаковом виде (в пределах одного байта).
а это точно?
тошо 9999999999999999 тоже 11 11 11 11 - в пределах байта
0
Кормпилятор
 Аватар для Quiet Snow
5044 / 1718 / 409
Регистрация: 25.04.2010
Сообщений: 4,827
Записей в блоге: 2
02.09.2012, 15:56
Полагаю вам не помешает теория по двоичному представлению чисел.
тошо 9999999999999999 тоже 11 11 11 11 - в пределах байта
В байте содержится 8 бит и хранятся числа от 0 до 255, т.е. 256 комбинаций.

1 бит
0 - 0
1 - 1
2 бита
00 - 0
01 - 1
10 - 2
11 - 3
3 бита
000 - 0
001 - 1
010 - 2
011 - 3
100 - 4
101 - 5
110 - 6
111 - 7
так можете продолжить до 8-ми бит и увидете, как сопоставляются числа двоичному коду.

PeekA() "вытягивает" из памяти число в данном представлении.

Ваше число 9999999999999999 интерпретируется в бинарном коде как:
1000111000011011110010011011111100000011 11111111111111
Посчитал я это стандартным виндовым калькулятором, в числе 54 бита и влезет оно только в
восьмибайтовый тип Quad. Если вы попытаетесь его засунуть в байт(.b), то при отключенном отладчике
в байт занесётся число 9999999999999999 & 255, т.е. только младший байт, т.о. вы потеряете
информацию о старших разрядах числа(т.е. почти всю инфу о числе).

И будет это число -1 и его битовая интерпретация 11111111 в дополнительном коде.

Зачем существуют байты, слова, двойные слова и четверные слова. Затем чтобы варьировать
диапазон чисел и занимаемое этими числами место в памяти. К примеру зачем сохранять
четырёхбайтовые величины, если нам с лихвой хватит диапазона двухбайтовых, т.о. мы сэкономим
место в памяти. Также на плечи компилятора, ложится конверт типов друг между другом и
ясен пень числа большего диапазона НЕ ЗАСУНУТЬ в числа меньшего, это всё равно что в
двухлитровую бутылку пытаться налить кубометр воды. Ещё надо представлять зачем нам дали байт
знаковый и беззнаковый, а дали его затем, чтобы мы могли использовать разные диапазоны чисел.
Диапазон чисел -128..127 НЕ РАВЕН диапазону 0..255, потому что он всего лишь частично
пересекается в области положительных чисел, тут нам важно понимать что есть значение числа и что
оно может быть разным и что бывают числа, которые не влезут в регистры процессора.

В бинарном представлении биты читаются справа налево, также как мы читаем
десятичные числа, т.е. разряды числа идут таким же образом, это важно когда мы сдвигаем биты(>>, <<).

Над бинарными числами мы можем произвести побитовые логические операции
Дизъюнкцию(OR), Конъюнкцию(AND), Отрицание(NOT) и исключающее ИЛИ
В пюр бейсике это соответствует значкам | & ~ !

На сегодня пока хватит загрузов...

Добавлено через 10 часов 7 минут
Появилось ещё одно предположение что считывая байты из видеобуфера надо их записывать в буфер картинки функцией Код Basic4GL
PokeL(*Dbuf, RGBA(R,G,B,A))
Вы могли легко проверить как работает функция RGBA, таким вот кодом:

PureBasic
1
2
3
4
5
6
7
8
w.l = RGBA(1,0,0,0)
Debug w
w.l = RGBA(0,1,0,0)
Debug w
w.l = RGBA(0,0,1,0)
Debug w
w.l = RGBA(0,0,0,1)
Debug w
А работает она так:
PureBasic
1
Rezult = R + G << 8 + B << 16 + A << 24
И дело в общем то не в том, как она работает, вы можете ею воспользоваться
даже если формат изображения будет отличаться, т.к. функция покрывает LONG полностью.

выдаёт от -128 до 127
Дело в том, что не бывает отрицательного цвета в контексте железа(видеопамяти), т.к.
интерпретируется не дополнительный код, а самый что ни на есть прямой.

x = -56 & 255
Тоже самое что
x = -56 + 256
Ошибаетесь, конъюнкция(в простонародии AND) это не то же самое что сложение.
Во-первых конъюнкция работает напрямую с битами и ей без разницы прямой код или дополнительный,
а, во-вторых, функцию эту используют, чтобы выделять из числа биты.
locm, в своём примере выделил из числа -56 целый байт и пофигу в каком представлении
оно хранилось(4 байта знаковый integer), т.к. в итоге остались лишь первые 8 бит от него и занеслись
опять же в знаковый integer, число стало положительным из-за смещения диапазона,
вследствие его сокращения. Т.е. число переместилось из области, условно закреплённой за
отрицательными числами, в область закреплённую за положительными числами. Почему условно?
Потому что любой байт, слово, двойное слово МЫ можем интерпретировать либо как знаковое число,
либо как беззнаковое.

Добавлено через 32 минуты
Да и зачем мне 128 вместо -128. Не понимаю.
Чтобы не коверкать интерпретацию данных в программе.
Беззнаковое:
00000000 - 0
00000001 - 1
...
11111110 - 254
11111111 - 255
Знаковое(доп. код):
00000000 - 0
00000001 - 1
...
01111111 - 127
10000000 - -128
...
11111100 - -4
11111101 - -3
11111110 - -2
11111111 - -1
Чуете разницу?
0
Ты за кого меня держиш!?
 Аватар для ЦарьКащей
22 / 23 / 7
Регистрация: 26.10.2011
Сообщений: 308
Записей в блоге: 1
02.09.2012, 23:32  [ТС]
Беззнаковое:
00000000 - 0
00000001 - 1
...
11111110 - 254
11111111 - 255
Знаковое(доп. код):
00000000 - 0
00000001 - 1
...
01111111 - 127
10000000 - -128
...
11111100 - -4
11111101 - -3
11111110 - -2
11111111 - -1
Чуете разницу?
Не чую. Откуда взялось 255 в одном байте если в нём умещается только один символ в 10 цифр(0 - 9)?
254 = 00000010 00000101 00000100

Добавлено через 1 минуту
Дело в том, что не бывает отрицательного цвета в контексте железа(видеопамяти), т.к.
интерпретируется не дополнительный код, а самый что ни на есть прямой.
Ссылка чтото не работает. Пустую страницу показывает.
0
Кормпилятор
 Аватар для Quiet Snow
5044 / 1718 / 409
Регистрация: 25.04.2010
Сообщений: 4,827
Записей в блоге: 2
03.09.2012, 00:05
Ссылка чтото не работает. Пустую страницу показывает.
Что-то с форумом, редиректор сдох, т.к. раньше работало, может быть починят скоро.

Откуда взялось 255 в одном байте если в нём умещается только один символ в 10 цифр(0 - 9)?
Перечитайте всё, что написано выше про двоичные числа, это всё проходят в школе.
Может быть я конечно криво изложил, т.к. не писатель, поэтому можете попробовать открыть
любой учебник информатики, в котором есть раздел про двоичные числа.

254 = 00000010 00000101 00000100
Нет, нет и ещё раз нет...
0
Эксперт по электронике
6998 / 3314 / 341
Регистрация: 28.10.2011
Сообщений: 13,023
Записей в блоге: 7
03.09.2012, 00:12
Цитата Сообщение от ЦарьКащей Посмотреть сообщение
Откуда взялось 255 в одном байте если в нём умещается только один символ в 10 цифр(0 - 9)?
254 = 00000010 00000101 00000100
Шутите?
Вот чему равно ваше число в двоичной системе счисления
PureBasic
1
Debug Val("%000000100000010100000100")
Скачайте конвертер ситсем счисления и изучайте их (системы счисления).
Вложения
Тип файла: zip Hex_Dec_Bin.zip (15.2 Кб, 10 просмотров)
1
Кормпилятор
 Аватар для Quiet Snow
5044 / 1718 / 409
Регистрация: 25.04.2010
Сообщений: 4,827
Записей в блоге: 2
03.09.2012, 01:22
Давайте сделаем проще, проиллюстрирую, запустите прогу и листайте кнопочками вправо/влево
ну или колёсиком мыши, как вам удобнее и смотрите что происходит с байтом.

Прога
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
a = InitSprite()
b = InitKeyboard()
c = InitMouse()
 
d = OpenWindow(#PB_Any, 0, 0, 500, 360, "Двоичные числа", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
e = OpenWindowedScreen(WindowID(d), 0, 0, 500, 360, 1, 0, 0, #PB_Screen_NoSynchronization)
MyFont1 = FontID(LoadFont(#PB_Any, "Arial", 50))
MyFont2 = FontID(LoadFont(#PB_Any, "Arial", 30))
MyFont3 = FontID(LoadFont(#PB_Any, "Arial", 16))
 
MyByte.a
MyByte2.b
 
If e
Repeat ; Главный цикл программы
  ExamineKeyboard()
  ExamineMouse()
  Event = WindowEvent()
 
  ClearScreen(0) ; Очитска экрана
 
   ;  Прибавляем к нашему байту по единичке
  If KeyboardReleased(#PB_Key_Right): mybyte = mybyte + 1: EndIf
  If KeyboardReleased(#PB_Key_Left): mybyte = mybyte - 1: EndIf
  mybyte = mybyte + MouseWheel()
  
  PokeA(@MyByte2, PeekA(@MyByte))
  StartDrawing(ScreenOutput())
     DrawingFont(MyFont3)
     DrawText(350, 320, "Выход - ESC", $BBBB, 0)
     DrawingFont(MyFont2)
     DrawText(10, 0, "Двоичное", $BBBBBB, 0)
     DrawText(10, 120, "Десятичное беззнаковое", $BBBBBB, 0)
     DrawText(10, 240, "Десятичное знаковое", $BBBBBB, 0)
     DrawingFont(MyFont1)
     DrawText(50, 40, RSet(Bin(mybyte, #PB_Byte), 8, "0"), $FFFFFF, 0)
     DrawText(50, 160, Str(mybyte), $FFFFFF, 0)
     DrawText(50, 280, Str(mybyte2), $FFFFFF, 0)
  StopDrawing()
  
  Delay(12)
  FlipBuffers() ; Отображение на экране буфера, по которому рисовали
Until KeyboardPushed(#PB_Key_Escape) Or Event = #PB_Event_CloseWindow
 
CloseWindow(d)
EndIf


Скачайте конвертер ситсем счисления и изучайте их (системы счисления).
Можно калькулятором винды в инженерном режиме.

Добавлено через 28 минут
Впрочем, посмотрел я прогу от locm удобная весьма. Калькулятором в разы геморнее.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
03.09.2012, 01:22

Анализ изображения с веб-камеры
Всем привет! Буду очень признателен, если вы подскажете мне на каком языке проще и/или удобнее сделать следующий алгоритм. Принимает...

Захват изображения с веб-камеры
Привет всем! Накипело, много статеек пересмотрел как это сделать, везде свои касяки, т.к. статейки-то страые. Ну в общем как захватить...

Захват изображения с веб камеры
Здравствуйте Я как начинающий программист, в начале своего обучения столкнулся с тем, что мне нужно сделать захват изображения с веб...

Захват видео изображения с веб-камеры
Возникли проблемы при создании массива в C#.В общем дело обстоит так: имеется захват видео изображения с веб-камеры,необходимо сделать,...

Обработка кадров с веб камеры
Здрасти, задался вот таким вот вопросом: Дано два пятна определённого цвета, произвольного диаметра, расположенных в одной плоскости по...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
Сезонность и суточность закисления почв
anaschu 04.07.2026
200 часов это все равно моловато. Есть ситуации, но нестандартные, когда смена происходит за 5 лет. Но обычно это 50 лет и более. Наверное, закисление почвы происходит сезонно в средней. . .
В чем ценность человеческого опыта в глобальном смысле?
kumehtar 03.07.2026
Возможно, ценность человека не в том, что он однажды достигает мудрости, а в том, что он становится носителем карты пути. Он знает не только истину, но и последовательность внутренних изменений,. . .
интеграция AnyLogic с самописным REST API и переход на Odoo
anaschu 03.07.2026
Успешная интеграция AnyLogic с самописным REST API и переход на промышленную Odoo WMS Сегодня проделал огромный путь от простой симуляции физических процессов до построения полноценной. . .
Поиск всех путей на ориентированном графе. Linux
dcc0 02.07.2026
Переработка старого кода из моей статьи. Через несколько переработок от PHP кода к C89 (надеюсь, 89). Но довольно запутанно получилось. Код для Linux. Но если убрать time и то, что с ним. . .
Сам себя обучал rest api
anaschu 02.07.2026
Педагогический лайфхак: Почему чистый REST API для ученика намного круче, чем готовые библиотеки Когда мы отказались от капризного JAR-файла AnyLogic и переписали код на стандартный HttpClient,. . .
rest api anylogic - выполнение модели на своём русском сайте
anaschu 02.07.2026
Как подружиться с AnyLogic Cloud API, победить провайдеров и развернуться Java-бэкенд в Docker на бесплатном хостинге: Двухдневный лог борьбы Всем привет! Хочу поделиться свежим (и довольно. . .
Где деньги лежат
kumehtar 02.07.2026
Это - японская подводная лодка I-52 (тип C2, кодовое имя Momi) вышла из Японии в марте 1944 года с миссией в оккупированную немцами Францию (Лорьян). Это была одна из «Янаги»-миссий по обмену. . .
Krabik для WoW 3.3.5a, многоязычный
AmbA 02.07.2026
Допилил бота, думаю что окончательно. Изменения: - добавлена многоязычность - добавлено снятие скриншотов - добавлено поддержание бафов хождения по воде (для жреца, дк и шамана) - и так, по. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru