Генератор точечных стереограмм на ПЛИС
Статьи по теме
- Генератор Видеосигнала на NIOS II
- Огляд Quartus II
- FAQ: Создание нового проекта в Quartus II
- ЛР2 > Управление периферийными устройствами стенда DE2 с помощью процессорного ядра NiosII
- ЛР3 > Работа с аудиокодеком WM8731 на стенде DE2
- ЛР1 > Знакомство со средой проектирования Quartus II. Создание проекта
- Обробка відео потоку: накладання мультиплікаційного фільтру

Идея для проекта на базе учебной платы DE2:
Генератор точечных стереограмм в реальном времени
Введение
Задачей проекта является разработка платформы на базе учебного кита Altera DE2 генерирующей стереограммы. Платформа генерирует трехмерную стереокартинку по карте дальностей (глубин), в которой хранится расстояние до каждого пикселя в картинке. Карта глубины может быть динамической сценой с изменяемой во времени значениями глубины. Каждая горизонтальная линия стереогаммы генерируется на лету из соответствующих линий карты глубины. Изображение отображается на VGA экране с разрешением 640х480 пикселей. Пользователь может переключатся между отображением карты глубины и стереограммы, а также взаимодействовать с картой глубины с помощью переключателей на плате DE-2.
Высокоуровневое проектирование генератора стереограмм
Основной смысл проекта – развлекательная программа. Техническая часть является самой важной частью проекта, но хотелось, чтобы проект был также интересен.
Основной идеей стереограмм является то, что изображение объекта для каждого глаза – разное. Если глаза сохраняют определенную глубину резкости они не могут отличить одну точку на этой глубине или две точки по пути к этой глубине. Стереограммы обманывают глаз благодаря расположению пикселей по этим путям и заставляют мозг поверить, что глаза сфокусированы на конкретной глубине, хотя, на самом деле это не так.
Рис. 1 Сехма расположения 3D изображения
Глубина фона (BKDEPTH) – обозначает воспринимаемое расстояние между виртуальной нулевой высотой и поверхностью экрана в пикселях. Расстояние до наблюдателя (OBSERVER) – расстояние от экрана до наблюдателя. Расстояние между глаз (EYESEP) – обозначает ожидаемое число пикселей между центрами зрачков зрителя. Эти параметры определяют, как пиксели будут связаны вместе для 3D отображения.
Следующее уравнение может быть использовано для подсчета расстояния (SEP) двух связанных пикселей на поверхности экрана:
Процесс генерации стереограммы
Процесс генерации стереограммы разделяется на несколько шагов. Начинается он с карты глубины. Нужная сцена представляется полем величин высоты. Темные области расположенные далеко и черный цвет представляют собой фон. Светлые области расположены ближе к зрителю, а полностью белые обозначают наиболее близкую точку.
Рис 2. Пример карты глубины стереограммы
Когда карта глубины известна, нужно создать буфер связей для хранения информации о связях между пикселями. Для каждой точки карты глубины считается расстояние (SEP). Процесс состоит из задания правому связанному пикселю ссылки на левый.
Когда пиксели связаны, последним шагом является определение их значений. Если буфер связей элемента содержит свой собственный индекс, значит он не ассоциирован с другим элементом. Этот пиксель получает случайное число. Если буфер связи элемента содержит другой индекс, значит он был ассоциирован с пикселем слева. Соответствующий правый пиксель тогда получает значение левого пикселя. Процедура проходит с левой стороны буфера связей до правого, назначая либо случайное значение либо значение связанного элемента каждому пикселю.
Каждая горизонтальная линия стереограммы генерируется на лету. Что бы сгенерировать полную картинку, процесс должен быть повторен для каждой линии. Если карта глубины статична – нет нужды делать что-то еще, но если она динамична, каждый новый кадр должен быть создан для каждого изменения карты.
Результаты работы проекта генератора стереокартинки с помощью ПЛИС
Результатом работы является платформа генерирующая стереограммы. Пример на рисунке 3 содержит два больших квадрата в центре экрана, маленький квадрат в нижнем правом углу и длинный прямоугольник сверху.
Рис. 3 Результат работы
Результат работы также показан на видео:
Программный код проекта
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 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 |
// DE2 Top level module declaration removed for copyright reasons. module sirds (); // Link buffers reg [9:0] link1 [0:639]; reg [9:0] link2 [0:639]; // SIRDS variables wire [7:0] separation; reg [7:0] random_color; wire rand_out; wire signed [31:0] height; // SRAM Signals reg ub; reg lb; reg [17:0] addr_reg; reg [15:0] data_reg; reg we; wire reset; // Line buffer signals reg [9:0] lb_ra, lb_wa; reg [7:0] lb_d; reg lb_we; wire [7:0] lb_q; // VGA Signals wire [ 9:0] mVGA_R, mVGA_G, mVGA_B; wire [19:0] mVGA_ADDR; wire DLY_RST; wire VGA_CTRL_CLK; wire AUD_CTRL_CLK; reg reg_VGA_VS; reg reg_VGA_HS; wire [ 9:0] Coord_X, Coord_Y; //display coords reg [ 9:0] reg_Coord_X; reg [ 9:0] y_pos; reg [ 9:0] x_pos; reg [9:0] reg_mVGA_R [6:0]; reg [9:0] reg_mVGA_G [6:0]; reg [9:0] reg_mVGA_B [6:0]; // Pipeline registers reg [9:0] x0, x1, x2, x3, x4, x5; reg [9:0] y0, y1, y2, y3, y4, y5; reg [8:0] z1, z2, z3, z4, z5; reg [9:0] link_x4, link_x5; reg [7:0] sep; reg signed [10:0] left, right; // Movement signals reg [7:0] level; reg [7:0] depth; reg reg_KEY2, reg_KEY3; reg [31:0] accum; wire dir; wire [8:0] box_x; // Turn on all display assign HEX0 = 7'hFF; assign HEX1 = 7'hFF; assign HEX2 = 7'hFF; assign HEX3 = 7'hFF; assign HEX4 = 7'hFF; assign HEX5 = 7'hFF; assign HEX6 = 7'hFF; assign HEX7 = 7'hFF; assign LEDG = 9'h000; assign LEDR = 18'h0; assign LCD_ON = 1'b1; assign LCD_BLON = 1'b1; // All inout port turn to tri-state assign DRAM_DQ = 16'hzzzz; assign FL_DQ = 8'hzz; assign OTG_DATA = 16'hzzzz; assign LCD_DATA = 8'hzz; assign SD_DAT = 1'bz; assign I2C_SDAT = 1'bz; assign ENET_DATA = 16'hzzzz; assign AUD_ADCLRCK = 1'bz; assign AUD_DACLRCK = 1'bz; assign AUD_BCLK = 1'bz; assign GPIO_0 = 36'hzzzzzzzzz; assign GPIO_1 = 36'hzzzzzzzzz; // Enable CLOCK_27 assign TD_RESET = 1'b1; // Connect module to SRAM assign SRAM_DQ = (~we) ? data_reg : 16'hzzzz; assign SRAM_ADDR = addr_reg; assign SRAM_UB_N = ub; assign SRAM_LB_N = lb; assign SRAM_WE_N = we; assign SRAM_CE_N = 0; assign SRAM_OE_N = 0; // Connect module to other signals assign mVGA_R = (VGA_HS && VGA_VS) ? {lb_d,2'b0} : 0; assign mVGA_G = (VGA_HS && VGA_VS) ? {lb_d,2'b0} : 0; assign mVGA_B = (VGA_HS && VGA_VS) ? {lb_d,2'b0} : 0; assign reset = ~KEY[0]; // Bouncing box variables assign box_x = accum[25:17]; assign dir = accum[26]; // Picture parameters parameter WIDTH = 640; parameter HEIGHT = 480; parameter BKDEPTH = -800; parameter OBSERVER = 350; parameter EYE_SEP = 80; // Ccolor parameters parameter NUMCOLORS = 64; //Instantiate VGA control modules Reset_Delay r0 (.iCLK(CLOCK_50),.oRESET(DLY_RST)); VGA_Audio_PLL p1 (.areset(~DLY_RST),.inclk0(CLOCK_27),.c0(VGA_CTRL_CLK),.c1(AUD_CTRL_CLK),.c2(VGA_CLK)); VGA_Controller u1 ( // Host Side .iCursor_RGB_EN(4'b0111), .oAddress(mVGA_ADDR), .oCoord_X(Coord_X), .oCoord_Y(Coord_Y), .iRed(mVGA_R), .iGreen(mVGA_G), .iBlue(mVGA_B), // VGA Side .oVGA_R(VGA_R), .oVGA_G(VGA_G), .oVGA_B(VGA_B), .oVGA_H_SYNC(VGA_HS), .oVGA_V_SYNC(VGA_VS), .oVGA_SYNC(VGA_SYNC), .oVGA_BLANK(VGA_BLANK), // Control Signal .iCLK(VGA_CTRL_CLK), .iRST_N(DLY_RST) ); // Random number generator Random31 rand1 (.iCLK(VGA_CTRL_CLK), .oRand(rand_out)); // ROM to map heights to separation values sep_rom sep1 (.ADDR(z1), .DATA_OUT(separation)); // RAM to store the pixel values for linking line_buffer line ( .ra(lb_ra), .wa(lb_wa), .clk(VGA_CTRL_CLK), .d(lb_d), .we(lb_we), .q(lb_q)); // Bouncing Box position accumulator always @ (posedge VGA_CTRL_CLK) begin if (reset) accum <= 0; else accum <= accum+1; end // Adjustable box height control routine always @ (posedge VGA_CTRL_CLK) begin if (reset) begin reg_KEY2 <= 1; reg_KEY3 <= 1; level <= 0; end else begin // On falling edges of the switches, increment the box height index up or down reg_KEY2 <= KEY[2]; reg_KEY3 <= KEY[3]; if (reg_KEY3 && ~KEY[3] && level > 0) level <= level-1; else if (reg_KEY2 && ~KEY[2] && level < 27) level <= level+1; else if (level > 27) level <= 27; end end // Map from adjustable box height index to displayable height value always @ (level) begin case (level) 8'h00: depth = 8'h00; 8'h01: depth = 8'h09; 8'h02: depth = 8'h17; 8'h03: depth = 8'h24; 8'h04: depth = 8'h30; 8'h05: depth = 8'h3C; 8'h06: depth = 8'h48; 8'h07: depth = 8'h53; 8'h08: depth = 8'h5E; 8'h09: depth = 8'h69; 8'h0A: depth = 8'h73; 8'h0B: depth = 8'h7D; 8'h0C: depth = 8'h87; 8'h0D: depth = 8'h90; 8'h0E: depth = 8'h99; 8'h0F: depth = 8'hA2; 8'h10: depth = 8'hAA; 8'h11: depth = 8'hB3; 8'h12: depth = 8'hBB; 8'h13: depth = 8'hC2; 8'h14: depth = 8'hCA; 8'h15: depth = 8'hD1; 8'h16: depth = 8'hD9; 8'h17: depth = 8'hE0; 8'h18: depth = 8'hE7; 8'h19: depth = 8'hED; 8'h1A: depth = 8'hF4; 8'h1B: depth = 8'hFA; default: depth = 8'h00; endcase end // Update the random color once each cycle always @ (posedge VGA_CTRL_CLK) begin random_color <= {random_color[6:0],rand_out}; end // Pipelined registers update always @ (posedge VGA_CTRL_CLK) begin // Gen depth stage x0 <= Coord_X[9:0]; y0 <= Coord_Y[9:0]; // Gen separation stage x1 <= x0; y1 <= y0; // Gen L&R stage x2 <= x1; y2 <= y1; z2 <= z1; // Link stage x3 <= x2; y3 <= y2; z3 <= z2; // Read color stage x4 <= x3; y4 <= y3; z4 <= z3; // Write color stage x5 <= x4; y5 <= y4; z5 <= z4; link_x5 <= link_x4; end // Gen depth stage always @ (posedge VGA_CTRL_CLK) begin // Create seesaw if (y0 >= 60 && y0 < 100) begin if (x0 < 552) z1 <= (accum[25]) ? ((x0[8:1])*accum[24:17])/256 : ((255-accum[24:17])*(x0[8:1]))/256; else z1 <= 8'h00; end // Create static and adjustable boxes else if (y0 >= 190 && y0 < 290) begin if (x0 >= 170 && x0 < 270) z1 <= 8'h90; else if (x0 >= 370 && x0 < 470) z1 <= depth; else z1 <= 8'h00; end // Create bouncing square else if (y0 >= 380 && y0 < 420) begin if (dir) begin if (x0 >= 44+box_x && x0 < 44+40+box_x) z1 <= 8'h90; else z1 <= 8'h00; end else begin if (x0 >= 44+(511-box_x) && x0 < 44+40+(511-box_x)) z1 <= 8'h90; else z1 <= 8'h00; end end else z1 <= 8'h00; end // Gen separation stage always @ (posedge VGA_CTRL_CLK) begin // Read the seperation value to which the current height maps sep <= separation; end // Gen L&R stage always @ (posedge VGA_CTRL_CLK) begin // calculate the left and right indices of the current pixel left <= x2 - (sep>>1); right <= x2 + (sep>>1) + sep[0]; end // Link stage always @ (posedge VGA_CTRL_CLK) begin // Build two link buffers so that one is initialized as the other is processed if (y3[0]) begin // Initialize other link buffer link1[x3] <= x3; // Assign rightmost elements the values of their linked elements // Capture the index of the element to which the current element is linked if ((left >= 0) && (right < WIDTH)) begin link2[right[9:0]] <= left[9:0]; link_x4 <= (x3 == right[9:0]) ? left[9:0] : link2[x3]; end else begin link_x4 <= link2[x3]; end end else begin // Initialize other link buffer link2[x3] <= x3; // Assign rightmost element the value of its linked element // Capture the index of the element to which the current element is linked if ((left >= 0) && (right < WIDTH)) begin link1[right[9:0]] <= left[9:0]; link_x4 <= (x3 == right[9:0]) ? left[9:0] : link1[x3]; end else begin link_x4 <= link1[x3]; end end end // Read color stage always @ (posedge VGA_CTRL_CLK) begin // Read the color of the linked element lb_ra <= link_x4; end // Write color stage always @ (posedge VGA_CTRL_CLK) begin // Write the color of the current pixel to the line buffer RAM lb_we <= 1; lb_wa <= x5; // Toggle depth map display on and off if (SW[17]) begin lb_d <= z5; end // Toggle between displaying the linked value and the stereogram else if (SW[0]) begin if (link_x5 == x5) lb_d <= random_color; else lb_d <= lb_q; end else begin lb_d <= link_x5[9:2]; end end endmodule ////////////////////////////////////////////////// //// M4k ram for line buffer ///////////////////// ////////////////////////////////////////////////// module line_buffer (q, wa, ra, d, we, clk); output reg [7:0] q; input [7:0] d; input [9:0] ra; input [9:0] wa; input we, clk; reg [7:0] mem [639:0]; always @ (negedge clk) begin if (we) mem[wa] <= d; q <= mem[ra]; end endmodule ////////////////////////////////////////////////// |
Больше информации о проекте и ссылки на исходные файлы можно найти на сайте Корнелловского университета.
Автор дайджеста:
Шевченко И.О., группа ДК-21, , КЭВА, НТУУ «КПИ»