{"id":289,"date":"2017-08-11T06:11:03","date_gmt":"2017-08-11T06:11:03","guid":{"rendered":"http:\/\/interspecifics.cc\/comunicacionesespeculativas\/?p=289"},"modified":"2017-08-11T06:50:39","modified_gmt":"2017-08-11T06:50:39","slug":"tutorial-estudio-del-movimiento-con-optical-flow","status":"publish","type":"post","link":"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/2017\/08\/11\/tutorial-estudio-del-movimiento-con-optical-flow\/","title":{"rendered":"Tutorial: Estudio del movimiento con Optical Flow"},"content":{"rendered":"<p>Para identificar el movimiento de los elementos en una secuencia de im\u00e1genes analizamos el flujo \u00f3ptico. Las t\u00e9cnicas para identificar el flujo optico nos permite rastrear las posiciones de un conjunto de puntos de inter\u00e9s en dos im\u00e1gene sucesivas y con ello, estimar la trayectoria seguida por cada punto, lo que nos da una aproximaci\u00f3n del desplazamiento ocurrido entre una imagen y la siguiente.<\/p>\n<p>El algoritmo Lucas-Kanade se usa para estimar las posiciones a la que se desplaza un conjunto de puntos dados. Es decir, no se analizan todos los pixeles de una imagen sino un subconjunto de ellos seleccionados con un extractor de atributos como SIFT o SURF.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-292 size-full aligncenter\" src=\"http:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/img_00002.png\" alt=\"\" width=\"960\" height=\"540\" srcset=\"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/img_00002.png 960w, https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/img_00002-300x169.png 300w, https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/img_00002-768x432.png 768w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-291 size-full\" src=\"http:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/img_00001.png\" alt=\"\" width=\"960\" height=\"540\" srcset=\"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/img_00001.png 960w, https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/img_00001-300x169.png 300w, https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/img_00001-768x432.png 768w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/p>\n<p>En las im\u00e1genes anteriores se observan dos frames sucesivos de un timelapse.<\/p>\n<p>Para realizar una primera aproximaci\u00f3n al estudio del movimiento, usamos una adaptaci\u00f3n del algoritmo LK sobre los puntos de una reticula rect\u00e1ngular de dimensiones fijas. El siguiente procedimiento muestra los pasos b\u00e1sico del procedimiento.<\/p>\n<p># 1. importar m\u00f3dulos<br \/>\n<code>import cv2, math<br \/>\nimport numpy as np<br \/>\nfrom glob import glob<\/code><\/p>\n<p># 2. obtener una lista de nombres de archivos<br \/>\n<code>in_fns = glob(\".\/TL9\/*.png\")<\/code><\/p>\n<p># 3. carga una imagen para usar como referencia<br \/>\n<code>old_frame = cv2.imread(in_fns[0], cv2.IMREAD_UNCHANGED)<\/code><\/p>\n<p># 4. convertir a escala de grises<br \/>\n<code>old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)<br \/>\n# canny edge detection<br \/>\n#old_gray = cv2.Canny(old_gray, 30, 30)<\/code><\/p>\n<p># 5. crear la reticula con los puntos a observar<br \/>\n<code>h,w,c = old_frame.shape<br \/>\npts = []<br \/>\nfor i in range (0, w, 50):<br \/>\nfor j in range (0, h, 50):<br \/>\npts.append([[i, j]])<br \/>\np0 = np.array(pts, dtype=\"float32\")<\/code><\/p>\n<p># 6. par\u00e1metros para algoritmo LK<br \/>\n<code>lk_params = dict( winSize  = (15,15),<br \/>\nmaxLevel = 4,<br \/>\ncriteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))<\/code><\/p>\n<p># 7. carga y convierte una nueva imagen<br \/>\n<code>frame = cv2.imread(in_fns[2], cv2.IMREAD_UNCHANGED)<br \/>\nframe_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)<br \/>\n# canny<br \/>\n#frame_gray = cv2.Canny(frame_gray, 30, 30)<\/code><\/p>\n<p># 8. crear nueva imagen para dibujar l\u00edneas de direcci\u00f3n<br \/>\n<code>vfield = np.zeros_like(old_frame)<br \/>\n# canny<br \/>\n#vfield = np.zeros_like(frame_gray)<\/code><\/p>\n<p># 9. calcular el flujo \u00f3ptico sobre las im\u00e1genes usando los puntos de la ret\u00edcula<br \/>\n<code>p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)<\/code><\/p>\n<p># 10. filtrar aquellos puntos que registraron movimiento<br \/>\n<code>good_new = p1[st==1]<br \/>\ngood_old = p0[st==1]<\/code><\/p>\n<p># 11. dibujar l\u00edneas desde las posiciones iniciales a las posiciones finales<br \/>\n<code>for i,(new,old) in enumerate(zip(good_new,good_old)):<br \/>\na,b = new.ravel()<br \/>\nc,d = old.ravel()<br \/>\ncv2.line (vfield, (a,b),(c,d), (127, 125, 125),  1)<\/code><\/p>\n<p># 12. mezclar la imagen original con las l\u00edneas trazadas<br \/>\n<code>img = cv2.add(frame, vfield)<br \/>\n# canny<br \/>\n#img = cv2.add(frame_gray, vfield)<\/code><\/p>\n<p># 13. muestra la imagen resultante (y espera la tecla ESC para terminar)<br \/>\n<code>while (True):<br \/>\ncv2.imshow('frame', img)<br \/>\nk = cv2.waitKey(10) &amp; 0xff<br \/>\nif k == 27:<br \/>\nbreak<br \/>\ncv2.destroyAllWindows()<\/code><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-293 size-full\" src=\"http:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/lines_TL9_01.png\" alt=\"\" width=\"1202\" height=\"678\" srcset=\"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/lines_TL9_01.png 1202w, https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/lines_TL9_01-300x169.png 300w, https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/lines_TL9_01-768x433.png 768w, https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/lines_TL9_01-1024x578.png 1024w\" sizes=\"auto, (max-width: 1202px) 100vw, 1202px\" \/><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-294 size-full\" src=\"http:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/lines_TL9_01_canny.png\" alt=\"\" width=\"1202\" height=\"677\" srcset=\"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/lines_TL9_01_canny.png 1202w, https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/lines_TL9_01_canny-300x169.png 300w, https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/lines_TL9_01_canny-768x433.png 768w, https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-content\/uploads\/2017\/08\/lines_TL9_01_canny-1024x577.png 1024w\" sizes=\"auto, (max-width: 1202px) 100vw, 1202px\" \/>En las im\u00e1genes se muestran las l\u00edneas de desplazamiento sobre la ret\u00edcula en la im\u00e1gen original y aplicando el detector de bordes. Para usar el detector de bordes en el ejemplo anterior, activar las instrucciones comentadas en los pasos 4, 7, 8 y reemplazar la instrucci\u00f3n en 12.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Para identificar el movimiento de los elementos en una secuencia de im\u00e1genes analizamos el flujo \u00f3ptico. Las t\u00e9cnicas para identificar el flujo optico nos permite rastrear las posiciones de un&hellip;<\/p>\n","protected":false},"author":1,"featured_media":301,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,9],"tags":[11,10],"class_list":["post-289","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-code","category-tutorial","tag-opencv","tag-python"],"_links":{"self":[{"href":"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-json\/wp\/v2\/posts\/289","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-json\/wp\/v2\/comments?post=289"}],"version-history":[{"count":3,"href":"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-json\/wp\/v2\/posts\/289\/revisions"}],"predecessor-version":[{"id":296,"href":"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-json\/wp\/v2\/posts\/289\/revisions\/296"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-json\/wp\/v2\/media\/301"}],"wp:attachment":[{"href":"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-json\/wp\/v2\/media?parent=289"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-json\/wp\/v2\/categories?post=289"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/interspecifics.cc\/comunicacionesespeculativas\/wp-json\/wp\/v2\/tags?post=289"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}