tag:blogger.com,1999:blog-25906171326751187692024-03-26T05:37:11.923-07:00Tutor de Programacióncomparte tus conocimientos de programación y aprende enseñandoUnknownnoreply@blogger.comBlogger360125tag:blogger.com,1999:blog-2590617132675118769.post-66172292053540826322021-01-21T06:41:00.006-08:002021-01-25T07:49:08.426-08:00Python Binance API<p>Vamos a aprender como integrar la API de Binance con nuestra aplicación Python, para este pequeño tutorial de programación estudiaremos los pasos necesarios que nos permitirán integrar esta tecnología de manera que podamos desarrollar una app que pueda dar seguimiento a los precios de las criptomonedas y realizar operaciones con las mismas, ya sean compras o ventas desde el exchange antes mencionado.</p>
<!-- readmore -->
<h3>Como integrar con Python 3</h3>
<p>Lo primero es instalar las correspondientes librerías, lo hacemos con el siguiente comando:</p>
<pre><code class='language-cmd' lang='cmd'>pip install python-binance
pip install keyboard
</code></pre>
<p>Si tienes estás en Windows y tienes problemas con la instalación de la librería Twisted la cual se requiere como dependencia puedes descargarla manualmente desde el <a href='https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted'>enlace</a> asegúrate de descargar la versión que coincida con la versión de Python que tienes instalada y también el sistema operativo.</p>
<p>El paso siguiente consiste en generar las claves de acceso a la api que nos permitirá acceder a nuestra cuenta en dicho exchange, no si tienes una cuenta en binance puede <a href='https://www.binance.com/en/register?ref=37674355'>registrarte</a> en caso contrario solo accede a tu cuenta y ve a la siguiente sección: Gestión de API / Crear API, le damos un nombre y guardamos los dos códigos que nos proporcionan.</p>
<p><img src="https://lh3.googleusercontent.com/0oUMhPqGSnKf6j8_iD8nwBfZ9eQJVCGnbNyWywqkptDKV-oopLbmZMo8UIM2wqwWwKaH2hdNnx3lx9opaL0mLoYBxigyruZqCBccpVtHO8141XOr-NoYIOMUCzZUmkmwaIYepa5EB4TxoOzq1WrBz6I2dacJAQm2Au45lbwakhDLHBbhzb4QEKozx05jkMo9b-Tre7DnjbWWY429a8pbwJ76LMwT2CV-lLSbizB6pMxM5yQdrd8pgiejA7FrZlBtzSCYuGnJeJGHmG90xhkd7rQllAqFdgNUXYHQ_sY5ildapGtMe-3kcVvHAVORjxolVRGkK8dhM0Cty9Ei_uKaeb8QhdueX468isLTPe7PlLas1En2PtydB3ZEi_EdZyPYXv4e9K84to92yvEVPoXX_szy-XadWIh_ucC3QC6pQZHk6rb21XQQqIliuG8MkoNNw5qMPzYHqHOY2fbMGMFUZkgcDFpztZXjoJ6adJZPbB3-EafUMTdfQcGkR8ez0zxtl6iEaNfDz6PDJLSQ4jTlpsJEJAuMZvilxHHoWdJFd20Ao_JfgstecP17iqAlBuhdDTkc_S6pvO-sQ3i_VihhKBU0lmfHKK8gK3gxfWEMpbJHjy98Jte38I25GtTvzX2_vGP4aFI7JKfaC8i5RhDSImktY9FuDhZ-FkY61w1Ee4yQNaCZGO_6dQ=w512-h198-no?authuser=0" referrerpolicy="no-referrer"></p>
<p>Si tenemos activados los métodos de verificación extra debemos completar esta acción y luego pasar al siguiente paso.</p>
<p>Recordar no compartir la API Key y la Secret Key. </p>
<p><img src="https://lh3.googleusercontent.com/Xh9oDKGdn0Ys93iSjWjh5fgy6yFAv4zhoQRo-ERj53C253MDsxbmOmqwdeKXxLwIzIU-q29MB8yIWe0vmFzw0_rvRJ2Sc5HyE2-QQXaLgM5yVqVYrIBZEGDF3GKJ3W-KmmzgZ6qYGYCi9Ahx6QWfBf8Ub0OTiTdXzE9pl95QLaq2hxMBBC5cu_PP0TgFJ2RoY4FnIsckjRUo3Htvi3ECxo5G7A6AVuzF6TFJmGmiEVBtLTRKlRq59VxXOhiLxhlinMo6eL8gqxnubFFp69YLFttFx-HP4ZAjV8Cff6STxUsHr-5GcNXL8L4rVtxqdtOa7s2IHnwtjaX_px9vQhv5rFFCj7Get7QMEOpYCkd0O7p6-C8RXywUToRQA0o7VeT5frd5x853c_C8AMRFrGoxvil6ER-UrBwKLnDAtYE0qnEyXEtDS9Tdm4LUOrUZi59maI08hMitVjcTOn3lHOpfGct1My9hGslyKs0xddLTQgDuZxK3DvQlwtvSnmpHdEKXMXKbw0DQm6wga_EVz-SDA7IzMqpTTqlyq2XunPVJg4YvHOC2Tp86UJt4zFpF3qAoTzWso3YE1heA-BpxwyHM-Ip76sbkA5Kcomq6C5SYLh5OZDTbA8erGmIw5j5rG1iJB8z_uW9f8ixuTVXDKGPdNNiOmXq9FGm1KICWz6G2NrzwozOtLsu-og=w512-h374-no?authuser=0" referrerpolicy="no-referrer"></p>
<p>Nuestro primer fragmento de código se ve de esta manera:</p>
<pre><code class='language-python' lang='python'>import keyboard
from binance.client import Client
from binance.websockets import BinanceSocketManager
from twisted.internet import reactor
api_key = 'xxxxxxxxxxxxxxxxxx'
api_secret = 'xxxxxxxxxxxxxxxxxx'
client = Client(api_key, api_secret)
bnb_balance = client.get_asset_balance(asset='BNB')
print("Balance: {}".format(bnb_balance))
print("Press q to exit")
keyboard.on_press_key("q", lambda _: reactor.stop() )
def process_message(msg):
print("Bid - Ask BTCUSDT price: {} - {}".format(msg['b'], msg['a']))
bm = BinanceSocketManager(client)
bm.start_symbol_ticker_socket('BTCUSDT', process_message)
bm.start()
</code></pre>
<p>Primer fragmento de código a analizar, aquí podemos ver como usamos las claves que obtuvimos previamente para instanciar la clase <strong>Client</strong> luego usamos el método <strong>get_asset_balance()</strong> para obtener nuestro balance total en la criptomoneda indicada, para nuestro ejemplo BNB. </p>
<pre><code class='language-python' lang='python'>client = Client(api_key, api_secret)
bnb_balance = client.get_asset_balance(asset='BNB')
</code></pre>
<p>Segundo fragmento de código a analizar, ahora vemos la clase <strong>BinanceSocketManager</strong> esta se encarga de conectar con el exchange mediante Sockets, en el ejemplo de abajo vemos como usamos el método <strong>start_symbol_ticker_socket</strong> para obtener los trades del par BTCUSDT.</p>
<pre><code class='language-python' lang='python'>def process_message(msg):
print("Bid - Ask BTCUSDT price: {} - {}".format(msg['b'], msg['a']))
bm = BinanceSocketManager(client)
bm.start_symbol_ticker_socket('BTCUSDT', process_message)
bm.start()
</code></pre>
<p>Este fragmento de código recibirá el mensaje en formato json con la información que podemos ver en la imagen.</p>
<p><img src="https://lh3.googleusercontent.com/2qGHLzvlZ97kDmijRnaDwfOnfcowpd1qr_8pJygAB9q0ORezCDWDUuciRth4OntDgKcU-nHP6_J2lLdJwL3WwU8h26Z2skBSXiaUhSHnYb4frEq9-vkZ-SqbtS6fzgia8Cs9_3sUDwTZoWpFJjMdNeXrSIGEARkAkM-xH71w7M9wFlZTMKF36_366v6f07a0glELEIKVt10c7HeYVEnul0HXGLBzmlIxBZBEveDbJQWujhvpmtupVuabYTkcewQW2Pv1TEOVxPodZoEcj-MPgIdk-_Lf-SEuqHP0euHeeoy2k4TNxolFMeeCzRsP7A0NuDxIATfSzMOhmtFfvCRCBI9zo_ZbhQ3lLkEHJ-Gjcguojs3ek4MY1-t5UuB8S7i1zkjx8DQVlbwfgkFPjnWBoOl7PCMcLAhHDYTen7KQRuG13CGPyZ6_OPAggZgr6i_2_vI3LeqtOxgQVkyPZ3383v7_XkBP0xCzER5tMKO5xAqjYHMvkUl3l9I9nunw8wkH7hqfzKF8mJb6JBWPAzbfNVa-rUvsr7s9uaTMv2kTS7Ph3THl_M8mAsnxN1AD7fnShRiZF8jDE4maC2WenoDIbyCGw64qKGqgOpYOTQTs4x1XIVf6Cx8a-2y4MLWj9pImADJL_aUT7me31AYv1HCVzAI_DNR0KPab9NaOfYE37IjGmu0HWfToFA=w952-h718-no?authuser=0" referrerpolicy="no-referrer"></p>
<p>Nosotros mostramos solo <strong>b</strong> y <strong>a</strong> para visualizar el <strong>Bid</strong> y <strong>Ask</strong> en tiempo real.</p>
<h3>Gráfica de velas en tiempo real</h3>
<p>Sí lo que deseamos es visualizar el gráfico de alguna criptomoneda necesitamos la ayuda de la libraría mplfinance, veremos un ejemplo en donde mostramos las velas del gráfico para el par BTCUSDT, esto es lo que pretendemos generar:</p>
<p><img src="https://lh3.googleusercontent.com/p7VHeIOaCzOyS4ufzZhE2Ux8P097ExUJBsuw9PLllmNADknjnSBxnfzotFWjO6OIEBQ4GDT66zoLGsD--UVJycxK3dPPdEozeJS9ixFLjJr9HZP0Elfxe-dIxgX6EhYEf7vw2q1RbLjPk1zK3CKTWcyakuJrnuJzrmXuwca_PJ6vBQXyuQHWE0SiDbR5jNXplGwzkubTo4qNxg8lYy7lT1CYrVdrUJXUQEfdX7qg5gZiEerbjtBOtpZQ8hMVUgZHQYZ8Y5EnzsBd_N9VVfo_v3GWd4SRNiKP5Ktof1Aa5iKBEXjmX0Zael2GO6hNyRtEgooB0LNsHau0ZVy7zCPeak0_BNs5gM_zcBjTkMgC7N5WAZDirnmF6Tgl_u_Wx1dEXWKxcUdb-r6idlk_3Fcld6T7fSFGpZoX9QABxEtnTLw715mZCfME_qOgelya0DKSJjs6HcYRVeXn5p3YdMUdUIym8U4mKkvHr9yWw29BhE2m6DU2_2UM62Xo84PBUw7HO6URJ3FeF4S0s98bARr76Xh2uqsDPUK0sWv38WE6FO7ixdrw98-_DHojq9M8LbpkuxwFxas6SHbVDosZtVO3JsrgisZmB_ho-N8DVzfcBHc1JCjIqXSw8oLYi3cuETXuoIfv7Jb5EgG3SihpC4aYHbNAZZUvlLMfnrcvQ-DAUDM5Z-NhPTrLIA=w1076-h575-no?authuser=0" referrerpolicy="no-referrer"></p>
<p>Lo primero que requerimos es instalar <strong>mplfinance</strong> esta nos permite de manera sencilla crear gráficos, en especial el de velas que estamos buscando crear. </p>
<pre><code class='language-cmd' lang='cmd'>pip install --upgrade mplfinance
</code></pre>
<pre><code class='language-python' lang='python'>from binance.client import Client
import mplfinance as mpf
import pandas as pd
import numpy as np
api_key = 'xxxxxxxxxxxxxxxxx'
api_secret = 'xxxxxxxxxxxxxxxxx'
client = Client(api_key, api_secret)
klines = client.get_historical_klines("BTCUSDT", Client.KLINE_INTERVAL_4HOUR, "15 day ago UTC")
df = pd.DataFrame(klines, columns=['Date',
'Open',
'High',
'Low',
'Close',
'Volume',
'Close time',
'Quote asset volume',
'Number of trades',
'Taker buy base asset volume',
'Taker buy quote asset volume',
'Ignore'])
df = df.drop(df.columns[[6, 7, 8, 9, 10, 11]], axis=1)
df['Date'] = pd.to_datetime(df['Date'], unit='ms')
df.set_index('Date', inplace=True, drop=True)
df['Open'] = df['Open'].astype(float)
df['High'] = df['High'].astype(float)
df['Low'] = df['Low'].astype(float)
df['Close'] = df['Close'].astype(float)
df['Volume'] = df['Volume'].astype(float)
mpf.plot(df, type='candle', style='binance', volume=True)
</code></pre>
<p>Debemos prestarle atención a <strong>get_historical_klines</strong> el cual nos devolverá el conjunto de datos que requerimos para crear las velas le indicamos el intervalo de tiempo entre cada vela y el rango de fechas para el cual deseamos obtener los datos, en nuestro ejemplo 15 días atrás desde el momento actual, necesitamos convertir estos datos a un <strong>DataFrame</strong> y solo vamos a utilizar los siguientes elementos: Date, Open, High, Low, Close, Volume, podemos descartar los demás, cuando tengamos los datos correctamente preparados usamos <strong>plot</strong> para generar y mostrar el gráfico. </p>
<p>Ahora hacemos una pequeña modificación al código para que nos permita actualizar los datos en tiempo real según los datos de binance, cambiaremos el intervalo de tiempo a 1 minuto para observar mejor lo que estamos haciendo.</p>
<pre><code class='language-python' lang='python'>from binance.client import Client
import matplotlib.animation as animation
import mplfinance as mpf
import pandas as pd
import numpy as np
api_key = 'xxxxxxxxxxxxxxxxxxxxxxxxx'
api_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxx'
crypto = 'BTCUSDT'
kline_interval = Client.KLINE_INTERVAL_1MINUTE
client = Client(api_key, api_secret)
klines = client.get_historical_klines(crypto, kline_interval, "1 hour ago UTC")
df = pd.DataFrame(klines, columns=['Date',
'Open',
'High',
'Low',
'Close',
'Volume',
'Close time',
'Quote asset volume',
'Number of trades',
'Taker buy base asset volume',
'Taker buy quote asset volume',
'Ignore'])
df = df.drop(df.columns[[6, 7, 8, 9, 10, 11]], axis=1)
df['Date'] = pd.to_datetime(df['Date'], unit='ms')
df.set_index('Date', inplace=True, drop=True)
df['Open'] = df['Open'].astype(float)
df['High'] = df['High'].astype(float)
df['Low'] = df['Low'].astype(float)
df['Close'] = df['Close'].astype(float)
df['Volume'] = df['Volume'].astype(float)
pkwargs=dict(type='candle', style='binance')
fig, axes = mpf.plot(df, title='Bitcoin Price in Binance', volume=True, returnfig=True, **pkwargs)
ax1 = axes[0]
ax2 = axes[2]
def animate(ival):
candle = client.get_klines(symbol=crypto, interval=kline_interval, limit=1)
c_open = float(candle[0][1])
c_high = float(candle[0][2])
c_low = float(candle[0][3])
c_close = float(candle[0][4])
c_vol = float(candle[0][5])
df2 = pd.DataFrame({'Date':[candle[0][0]], 'Open':[c_open],'High':[c_high],'Low':[c_low],'Close':[c_close],'Volume':[c_vol]})
df2['Date'] = pd.to_datetime(df2['Date'], unit='ms')
df2.set_index('Date', inplace=True, drop=True)
global df
if df.last_valid_index() != df2.last_valid_index():
data = pd.concat([df.iloc[1:], df2], ignore_index = False)
df = data
else:
data = df
data.iloc[-1, data.columns.get_loc('Open')] = c_open
data.iloc[-1, data.columns.get_loc('High')] = c_high
data.iloc[-1, data.columns.get_loc('Low')] = c_low
data.iloc[-1, data.columns.get_loc('Close')] = c_close
data.iloc[-1, data.columns.get_loc('Volume')] = c_vol
ax1.clear()
ax2.clear()
mpf.plot(data, ax=ax1,volume=ax2,**pkwargs)
ani = animation.FuncAnimation(fig, animate, interval=250)
mpf.show()
</code></pre>
<p>Es todo por ahora, nos queda por ver como crear ordenes de compra o venta, en los distintos mercados spot, futuros, etc., y algunas otras cosas interesantes que podemos hacer con la api.</p>
Unknownnoreply@blogger.com15tag:blogger.com,1999:blog-2590617132675118769.post-83175448693416591182020-11-28T05:14:00.002-08:002021-01-25T07:58:40.421-08:00Ejecutar aplicación WPF con permisos de administrador<p>En ocasiones requerimos que nuestra aplicación se ejecute con permisos de administración por diferentes motivos, en este breve tutorial veremos como podemos hacer que una app desarrollada con WPF solicite permisos al momento de ejecutarse. </p>
<!-- readmore -->
<p>Asumimos que ya tenemos una nuestra aplicación desarrollada y que estamos trabajando con Visual Studio.</p>
<p>Lo que debemos hacer es ir a la pestaña explorador de soluciones, clic derecho, agregar nuevo elemento. Seleccionamos archivo de manifiesto de Windows.</p>
<p><img src="https://lh3.googleusercontent.com/hKd_rTAx-EsKjnkyRh08-19lLYUQjuqrDVA5Zp_QMXiGujsZMSe7IiwH7rTDHgZtWJ67e66ytIA_LeQrJtEGzokBfWLOSNWR5ap6ZldGt4v4vPB5ahiWWRR7DJgau3nSkY6mJJX7TI6xWuGzTObPLEO844sthohmBPcdNzHtP3aW6nGQt-oxlYsJIsoPyrWMzCf1RzkW0U5NCfUa_B5o-HquqJpzj_3OCdV709EyDnSQ0qXmQX2TYwieLVZSmiCLXPb8d1HyRCKiDV7U_X4lhzCbyG5fw0MY2SkdfjXKM9665ws4vjuypZpF-Dg2rmgUPykU8UWDEOYdydJyI7vylzap7NhHt-hsEpRLsPTpXjZlbVfMEqjLjq2Iyu4-pCjU_wadR64hql_QfSlAJPoisOxF-AG_1zMSS8K7GiRedwcnahkS7ptg-a1G1RbbhRdT9LMv2yE3ug7qyTGSN6SRXSxTIPxrTDEd5fTedvuHI6gtfU_B550b1-hWlHdj8Au3Gas_nWhA2Iv21sTV_NUUkVk3a96RSlChJ3XC-0zrdwyL40qJsJ7KsOhAJra8Hmlgi9V4Q02uc-_SA1dS2AOoD3IyMWbHsW2FmObrutg2Nf-ElYAjEBJppGcDX9MtTnjvyeOF4I-QCVIexuX104tFuteGhKJHu_1kTseOZJcefB54MBvb2fpXwg=w1178-h816-no?authuser=0" referrerpolicy="no-referrer"></p>
<p>En el archivo <strong>app.manifest</strong> que se crea modificamos el código para cambiar lo siguiente: </p>
<p>reemplazar:</p>
<pre><code class='language-xml' lang='xml'><requestedExecutionLevel level="asInvoker" uiAccess="false" />
</code></pre>
<p>por:</p>
<pre><code class='language-xml' lang='xml'><requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</code></pre>
<p>El código quedaría de la siguiente manera:</p>
<pre><code class='language-xml' lang='xml'><?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
</application>
</compatibility>
</assembly>
</code></pre>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2590617132675118769.post-28696790142546413282020-11-03T06:42:00.003-08:002021-01-25T07:55:32.269-08:00Integrar ExoPlayer con Android Leanback<p><a href='https://developer.android.com/jetpack/androidx/releases/leanback?hl=es'>Leanback</a> es la librería de Android que facilita el desarrollar aplicaciones para Android TV, muchas de estas aplicaciones requieren o hacen uso de un reproductor multimedia, por lo que en este tutorial veremos como integrar el reproductor <a href='https://exoplayer.dev/'>ExoPlayer</a>.</p>
<a name='more'></a>
<p>Lo primero crear nuestro proyecto de la siguiente manera:</p>
<p><img src="https://lh3.googleusercontent.com/zlkHxeA2JYdeCP372buacPO0TKtF8clo8p8uQltn4XhQO3y4qckbvF-kKTETQDGjL6eVa11B69UjhckLBLSBFZFoGlld4BJ_xVQz9KNAxPQqYAnKh12p-bKOGM-1Z0jjypoEz9D_67TWlFEv3uWeq54Vm_NQ_6yGG9GUuwDNORxitUYp4Y7coRdGnINKTOlgmYpl61rN4qmJBbI0-FCvljY6k-AHgm--9E5Tx4DgGNkPFcLg94t57d9XJ9myNNJ2U01lhAAWLsIxK17mhE3YCF-x2koUKk-6n1-udvvaqfunDoIbO4xPu3OibpB8lX_JJW04OyTvM0rNrHwuB0kJxTOBkVzU2iNxRTCzB_B8rLZX6okrILfE6rKYWnkeP_bjDFz3vF0AWSiD7hVVb4dSamk7pZLjol_Vd176IVNtmW8vPyXqIuxk22BIRtSYw8H9f0KvDNUEjtaBOaIUZNvMM8zcQaaRRqCDeUm24hfEi-47PwEfBOEBiPMEvjRng9VJ0mPKFExbQFt5b0bSQn_NKp4MrvReWxPIKS5n2ugVukEh9CLpyGgpfiU5SpF9ZwRqbR1N2iVdkKnZgudUrnrTHtmN_kAsC7e_Qps0_tpjiY6xWQfxWx91ePoJ3U9SU5IMI28GOMoRL-BbOJgClGCzkwV2eWOgnorWg4Nq9x8nHdFKAgtn8VMugQ=w1127-h812-no?authuser=0" style="zoom: 50%;" /></p>
<p><img src="https://lh3.googleusercontent.com/-bPuuVKR7mTK6xev77JpWmJQG8HdcCbd2A_sWV0KMFz7OdIi-ELHNEWWTUlhmJXNiHF6hAZ5HhYygFEC3RMMMtw5SMhsX4M5OPeUgTngXz2nWjztro9lKbm9fPz0c2ntjOsS_aHnIRyElFfYEz6NTjkq4a2O5Dg6ZZ7PGUIbOcKuggo2DgWY9jGRJhQm3DaMcZV3h4WRkF6pHjUjqKxokl38liAFvdFE9Ff6RDIayaI7s3cctMD0543og8QJnSKMmTfvzNEOgc2tuIQpyetqqomlitUZixbqf_CTD5c97BeYsKkyx7TNe54tO8owMLwf8uHyBseLjT0zkjYvYhxyW9x_j-UXSW3iYROXd8erSPF7_aINkahn2NfATeZSZWY6k_riZvwUBdhnmXY5VUbNyzdi7no-EIqhhbr1rgbjGdM4ZxlBxtydstIHWGjxeJZWRcXB6WDgBZ9U1oDXlvBvGtAlWJOftlx1sGU_68xw8bTT_sBW_8cdNwNs7nFJriu3qYNyayYh1Wd7dmMQO_7cymV4bf0mefEk-mKOkI80oOojDz23KUJaTAYJ4_krT4k1v4AHTUKXO8j0GsKMsmvYvETDWNULmwD_LdxNX82wEzxHTRq3w_tGwmYS807I5W3OwO5Jot8QYenGLo9KJOw4wOUf1h_zyop6YVo1PC6YEUNKGuFrz70M9w=w1127-h812-no?authuser=0" style="zoom:50%;" /></p>
<p>Con esto creamos un proyecto vacío, lo que haremos ahora será agregar nuestra actividad, por ahora con el siguiente código:</p>
<pre><code class='language-java' lang='java'>public class LeanbackActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_leanback);
}
}
</code></pre>
<p>Debemos hacer las siguientes modificaciones en el AndroidManifest.xml el primer elemento para indicar si nuestra app se utilizará solo en dispositivos que utilicen la UI Leanback o también podrá ejecutarse en otros dispositivos en este ultimo caso establecemos el atributo a false como lo haremos nosotros, en el segundo indicaremos que no es necesario disponer de una pantalla táctil además se requiere para que Google Play identifique la aplicación como una de Android TV. </p>
<pre><code class='language-xml' lang='xml'> <uses-feature android:name="android.software.leanback" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
</code></pre>
<p>Para que la actividad se pueda iniciar debemos establecer el CATEGORY_LEANBACK_LAUNCHER, también se requiere de definamos el atributo android:banner de application este debe ser una imagen de 320 x 180 </p>
<pre><code class='language-xml' lang='xml'> <application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.Exoplayerleanback"
android:banner="@mipmap/ic_launcher">
<activity
android:name=".LeanbackActivity"
android:theme="@style/Theme.Exoplayerleanback">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
</application>
</code></pre>
<p>Con esto ya podemos correr la app aunque no veremos nada en pantalla, el siguiente paso es agregar el reproductor que en nuestro caso usaremos para reproducir contenido en streaming en formato HLS para ello utilizaremos ExoPlayer en la versión 2.12.x al momento de la redacción.</p>
<p>Para usar este reproductor agregamos la siguiente dependencia: <strong>com.google.android.exoplayer:exoplayer:2.X.X</strong> y <strong>com.google.android.exoplayer:extension-leanback:2.12.1</strong> además cambiamos la versión de compilación de Java a 1.8 </p>
<pre><code class='language-groovy' lang='groovy'>android {
compileSdkVersion 29
buildToolsVersion "30.0.2"
defaultConfig {...}
buildTypes {...}
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.leanback:leanback:1.0.0'
implementation 'com.google.android.exoplayer:exoplayer:2.12.1'
implementation 'com.google.android.exoplayer:extension-leanback:2.12.1'
}
</code></pre>
<p>No debemos olvidar agregar los permisos para poder acceder a internet ya que vamos a reproducir contenido online.</p>
<p>Al definir el layout de la actividad añadiremos un PlayerView y un fragment el primero hace referencia al reproductor ExoPlayer y el segundo lo usaremos para controlar el mismo, el código XML quedará de la siguiente manera:</p>
<pre><code class='language-xml' lang='xml'><?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LeanbackActivity">
<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/player"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:use_controller="false"/>
<fragment
android:id="@+id/video_fragment"
android:name="com.carmelo.exoplayer_leanback.LeanbackFragmentPlayer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</FrameLayout>
</code></pre>
<p>Es importante mencionar que establecimos en atributo <strong>use_controller</strong> a false porque deseamos ocultar los controles por defecto del reproductor y utilizar los controles de la UI Leanback.</p>
<p>Para incluir los controles Leanback el Fragment de extender la clase PlaybackSupportFragment aquí crearemos los métodos para inicializar y controlar la reproducción de contenido, mostramos los métodos preparePlayer(...) el cual se encarga de preparar el reproductor para visualizar el contenido indicado e initPlayer(...) el cual inicializa el reproductor y lo adapta a la UI Leanback.</p>
<pre><code class='language-java' lang='java'>public class LeanbackFragmentPlayer extends PlaybackSupportFragment
implements Player.EventListener, VideoPlayerGlue.OnActionClickedListener {
private SimpleExoPlayer player;
private VideoPlayerGlue playerGlue;
private void preparePlayer(Context context, ExoPlayer player, String videoUri) {
// Produces DataSource instances through which media data is loaded.
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context,
Util.getUserAgent(context, "receiver"));
// This is the MediaSource representing the media to be played.
MediaSource videoSource =
new HlsMediaSource.Factory(dataSourceFactory)
.createMediaSource(MediaItem.fromUri(videoUri));
// Prepare the player with the source.
player.setMediaSource(videoSource);
player.prepare();
}
private void initPlayer() {
PlayerView playerView = getActivity().findViewById(R.id.player);
player = new SimpleExoPlayer.Builder(getContext()).build();
playerView.setPlayer(player);
PlayerAdapter playerAdapter = new LeanbackPlayerAdapter(getContext(), player, 16);
playerGlue = new VideoPlayerGlue(getContext(), playerAdapter, this);
playerGlue.setHost(new PlaybackSupportFragmentGlueHost(this));
playerGlue.playWhenPrepared();
setAdapter(new ArrayObjectAdapter());
String url = "https://multiplatform-f.akamaihd.net/i/multi/will/bunny/big_buck_bunny_,640x360_400,640x360_700,640x360_1000,950x540_1500,.f4v.csmil/master.m3u8";
preparePlayer(getContext(), player, url);
}
//...
}
</code></pre>
<p>En initPlayer(...) le prestamos atención a la clase LeanbackPlayerAdapter esta no sirve de puente para conectar la UI con ExoPlayer además tenemos VideoPlayerGlue esta última la definimos nosotros y nos servirá para dar funcionalidad a cada uno de los controles del reproductor, podremos agregar o personalizar las funcionalidades del mismo, esta clase se define de la siguiente manera:</p>
<pre><code class='language-java' lang='java'>public class VideoPlayerGlue extends PlaybackTransportControlGlue<PlayerAdapter> {
private static final long TEN_SECONDS = TimeUnit.SECONDS.toMillis(10);
public interface OnActionClickedListener {
void onPrevious();
void onNext();
}
private final OnActionClickedListener mActionListener;
private PlaybackControlsRow.RepeatAction mRepeatAction;
private PlaybackControlsRow.ThumbsUpAction mThumbsUpAction;
private PlaybackControlsRow.ThumbsDownAction mThumbsDownAction;
private PlaybackControlsRow.SkipPreviousAction mSkipPreviousAction;
private PlaybackControlsRow.SkipNextAction mSkipNextAction;
private PlaybackControlsRow.FastForwardAction mFastForwardAction;
private PlaybackControlsRow.RewindAction mRewindAction;
private PlaybackControlsRow.ClosedCaptioningAction mClosedCaptionAction;
private PlaybackControlsRow.ShuffleAction mShuffleAction;
private PlaybackControlsRow.PictureInPictureAction mPictureAction;
public VideoPlayerGlue(
Context context,
PlayerAdapter playerAdapter,
OnActionClickedListener actionListener) {
super(context, playerAdapter);
mActionListener = actionListener;
mSkipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(context);
mSkipNextAction = new PlaybackControlsRow.SkipNextAction(context);
mFastForwardAction = new PlaybackControlsRow.FastForwardAction(context);
mRewindAction = new PlaybackControlsRow.RewindAction(context);
mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(context);
mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsUpAction.INDEX_OUTLINE);
mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(context);
mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsDownAction.INDEX_OUTLINE);
mRepeatAction = new PlaybackControlsRow.RepeatAction(context);
mClosedCaptionAction = new PlaybackControlsRow.ClosedCaptioningAction(context);
mShuffleAction = new PlaybackControlsRow.ShuffleAction(context);
mPictureAction = new PlaybackControlsRow.PictureInPictureAction(context);
}
@Override
protected void onCreatePrimaryActions(ArrayObjectAdapter adapter) {
super.onCreatePrimaryActions(adapter);
adapter.add(mRewindAction);
adapter.add(mSkipPreviousAction);
adapter.add(mSkipNextAction);
adapter.add(mFastForwardAction);
}
@Override
protected void onCreateSecondaryActions(ArrayObjectAdapter adapter) {...}
@Override
public void onActionClicked(Action action) {
if (shouldDispatchAction(action)) {
if(action == mFastForwardAction) {
getPlayerAdapter().seekTo(getPlayerAdapter().getCurrentPosition() + 60000);
}
return;
}
// Super class handles play/pause and delegates to abstract methods next()/previous().
super.onActionClicked(action);
}
// Should dispatch actions that the super class does not supply callbacks for.
private boolean shouldDispatchAction(Action action) {
return action == mRewindAction
|| action == mFastForwardAction
|| action == mThumbsDownAction
|| action == mThumbsUpAction
|| action == mRepeatAction
|| action == mShuffleAction
|| action == mClosedCaptionAction
|| action == mPictureAction;
}
@Override
public void next() {
mActionListener.onNext();
}
@Override
public void previous() {
mActionListener.onPrevious();
}
}
</code></pre>
<p>Con esto tenemos lo siguiente:</p>
<p><img src="https://lh3.googleusercontent.com/UVQwpc2c8DUh3f-BtU-5WmqFFzv8KWsjh2vVGAie0nm4tbgMaqs1QVrLRTOrS_a-fod-tE8H0pQni0jubrZ3mmmOsAMVFi_e1BJe-TBVrocmQIc4Y46g5bcGq6FLtV5mY6a7Tn1l6VmW4PTJ911D4tZ05cMKC6D2zQiYpT4K2awiwsbtIuIp9TK382gQHsqHqD557CGbagCG6H_GeiVoBG9Umx7G_5iHkeoUwTWpg3Upq5ND3CQtj5I7XAFKLDOYoHFc6ehMN9RtjtJZxcNWXLUozcesyR_lw0WlCWV7ofjmixHpiXVfXycRcqqF_S-cThiMzr-glb9RAYqsuisgADxXRE_i4tvBwr0LuiAEnFKT1n41RLc9YJsYR0YkTSt9IZBSRBQzBmdme21xqtUGXhQhXV6da7mVUqTkQiJdT7225-wRVUwFB-08Lj8CQ1XgwInp3OzrcSKTapanPsjFJXq-3gKmfB2NwucLedINI_d6QnuGhCqAYEWMI4L-wf_NMpXszv9fmjCdOysY7eAm_yUXgbWtjD-v2YE6l0mxqj7_bmE3YL_TC4jB4BdEOc8L7gPBT30Dr8L-9xdTM6aaAKnLx9KwSYs-AuwjGhHM-c_Qvep4ySFCUhnuNUM2KrvxOYj9sunlLy8W_J-rvmiLjeYizOJ0PV0crzZhLg6SqEH4x8LLetvZ-A=w1318-h733-no?authuser=0" style="zoom:50%;" /></p>
<p> El código completo se puede descargar en el siguiente enlace: <a href="https://github.com/TutorProgramacion/exoplayerleanback">Exoplayer-leanback code</a> </p>
<p> </p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2590617132675118769.post-14626669128006483482019-10-20T12:46:00.002-07:002019-10-20T12:46:46.747-07:00OpenCV lector de códigos QR<p>A partir de la versión 4.0.0 de OpenCV se agregó la funcionalidad de poder detectar y decodificar códigos QR sin necesidad de librerías externas, sin embargo la misma no realizaba el trabajo de la mejor manera, en la reciente versión 4.1.2 se agregaron mejoras que probaremos en día de hoy, veremos como usar OpenCV para crear un detector y decodificador de códigos QR en tiempo real con unas pocas líneas de código C++.</p>
<!-- -more -->
<p><img src="https://lh3.googleusercontent.com/4xbvWAQWGX2lWbZjumIWxhU8LstJDFoPdFrD8rzF2Cc6LwipIbs6XVVCSWzPqBspCjXtfomvO6k" alt="QR OpenCV" title="QR OpenCV"></p>
<p>La clase encargada de realizar la respectiva tarea es <code>QRCodeDetector</code>, usando sus métodos <code>detect(...)</code> podremos detectar un código QR en una imagen en colores o a escala de grises, con <code>decode(...)</code> decodificamos el código y obtenemos la información que contenga el mismo, para nuestro ejemplo una URL, también podremos usar <code>detectAndDecode(...)</code> para hacer ambas tareas en una sola llamada.</p>
<pre class=" language-cpp"><code class="prism language-cpp"><span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token keyword">int</span> argc<span class="token punctuation">,</span> <span class="token keyword">char</span><span class="token operator">*</span> argv<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">// Init QR Detector</span>
QRCodeDetector qr <span class="token operator">=</span> QRCodeDetector<span class="token operator">::</span><span class="token function">QRCodeDetector</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
VideoCapture capture<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>capture<span class="token punctuation">.</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
Mat frame<span class="token punctuation">;</span>
capture <span class="token operator">>></span> frame<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>frame<span class="token punctuation">.</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">continue</span><span class="token punctuation">;</span>
vector<span class="token operator"><</span>Point<span class="token operator">></span> pts<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>qr<span class="token punctuation">.</span><span class="token function">detect</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> pts<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
string decoded <span class="token operator">=</span> qr<span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> pts<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">drawQRCodeContour</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> pts<span class="token punctuation">,</span> decoded<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">imshow</span><span class="token punctuation">(</span><span class="token string">"QR"</span><span class="token punctuation">,</span> frame<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token function">waitKey</span><span class="token punctuation">(</span><span class="token number">30</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">27</span><span class="token punctuation">)</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
capture<span class="token punctuation">.</span><span class="token function">release</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Lo primero es crear una instancia de la clase <strong>QRCodeDetector</strong> para luego iniciar el <strong>VideoCapture</strong> que nos permitirá leer imágenes desde nuestra webcam, esto ya se ha explicado en tutoriales anteriores, así que nos centramos directamente en el siguiente fragmento de código que es el que nos interesa en este momento:</p>
<pre class=" language-cpp"><code class="prism language-cpp">vector<span class="token operator"><</span>Point<span class="token operator">></span> pts<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>qr<span class="token punctuation">.</span><span class="token function">detect</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> pts<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
string decoded <span class="token operator">=</span> qr<span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> pts<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>decoded<span class="token punctuation">.</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">drawQRCodeContour</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> pts<span class="token punctuation">,</span> decoded<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Aquí usamos el método <code>qr.detect(frame, pts)</code> para detectar el QR presente en la entrada, para nuestro ejemplo el cv::Mat frame, debemos indicar un <code>vector<cv::Point></code> en donde se almacenará los puntos que corresponden al las 4 esquinas del QR, este método retorna true en caso de éxito.</p>
<p>Lo que sigue es usar el método <code>qr.decode(frame, pts)</code> para obtener el texto contenido por el QR, le pasamos los datos obtenidos previamente, opcionalmente a este método se le puede pasar un tercer argumento que es un cv::Mat que contendrá una versión retificada del QR, es decir una imágen recortada y alineada.</p>
<p>También debes saber que es posible hacer ambas cosas en una sola llamada usando el método <code>qr.detectAndDecode(...)</code>.</p>
<p>Sí hemos logrado detectar y decodificar correctamente la información podemos mostrarla, para ello usamos la siguiente función a la cuál le pasamos la imagen, los puntos y texto decodificado.</p>
<pre class=" language-cpp"><code class="prism language-cpp"><span class="token keyword">void</span> <span class="token function">drawQRCodeContour</span><span class="token punctuation">(</span>Mat<span class="token operator">&</span> color_image<span class="token punctuation">,</span> vector<span class="token operator"><</span>Point<span class="token operator">></span> pts<span class="token punctuation">,</span> string url<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>pts<span class="token punctuation">.</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">4</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">line</span><span class="token punctuation">(</span>color_image<span class="token punctuation">,</span> pts<span class="token punctuation">.</span><span class="token function">at</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">,</span> pts<span class="token punctuation">.</span><span class="token function">at</span><span class="token punctuation">(</span><span class="token punctuation">(</span>i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">%</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> LINE_AA<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
RNG <span class="token function">rng</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">4</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
Scalar color <span class="token operator">=</span> <span class="token function">Scalar</span><span class="token punctuation">(</span>rng<span class="token punctuation">.</span><span class="token function">uniform</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">,</span> rng<span class="token punctuation">.</span><span class="token function">uniform</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">,</span> rng<span class="token punctuation">.</span><span class="token function">uniform</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">circle</span><span class="token punctuation">(</span>color_image<span class="token punctuation">,</span> pts<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">6.5</span><span class="token punctuation">,</span> color<span class="token punctuation">,</span> FILLED<span class="token punctuation">,</span> LINE_AA<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">putText</span><span class="token punctuation">(</span>color_image<span class="token punctuation">,</span> url<span class="token punctuation">,</span> <span class="token function">Point</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">30</span><span class="token punctuation">)</span><span class="token punctuation">,</span> FONT_HERSHEY_SIMPLEX<span class="token punctuation">,</span> <span class="token number">1.0</span><span class="token punctuation">,</span> <span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> LINE_AA<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>En el primer fragmento de código usamos <code>line(...)</code>, para crear una línea que una cada uno de los puntos encontrados, en el segundo con <code>circle(...)</code> dibujamos un circulo en cada una de las esquinas y al final con <code>putText(...)</code> escribimos el texto decodificado.</p>
<p>En el repositorio de este projecto podrás encontrar el CMakeLists.txt que te facilitará la generación del proyecto.</p>
<pre class=" language-cmake"><code class="prism language-cmake">cmake_minimum_required(VERSION 3.0)
PROJECT(qr-opencv)
FIND_PACKAGE( OpenCV REQUIRED )
INCLUDE_DIRECTORIES( ${OpenCV_INCLUDE_DIRS} )
ADD_EXECUTABLE(${PROJECT_NAME} main.cpp)
TARGET_LINK_LIBRARIES (${PROJECT_NAME} ${OpenCV_LIBS})
</code></pre>
<p><a href="https://github.com/TutorProgramacion/qr-code">Código de proyecto en GitHub</a></p>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2590617132675118769.post-18773490921708371552019-08-16T07:48:00.003-07:002019-08-16T07:49:19.636-07:00Segmentación de instancias con OpenCV DNN<p>La segmentación de instancias es el proceso mediante el cual buscamos detectar un objeto en una escena y generar una máscara que nos permita extraer con mayor presición el objeto detectado, puede verse como el conjunto de dos procesos primero detectar el área rectángular que contiene el objeto y luego obtener la máscara que segmenta dicho objeto.</p>
<a name='more'></a>
<p><img src="https://lh3.googleusercontent.com/ZlVn6CBQyRwlSssR3N2oTppq00PnUh_VP4i2ed-wdPlIwREfvcNSu2eVeAUvDqSPKBHTp8NGnfg" alt="segmentación de instancias" title="instance segmentation"></p>
<h3 id="mask-r-cnn">MASK R-CNN</h3>
<p>Esta arquitectura de aprendizaje profundo desarrollada por invetigadores de (FAIR) Facebook AI Research es una extensión a la arquitectura de detección de objetos Faster R-CNN, Mask R-CNN agrega una capa extra que permite generar una máscara para el objeto detectado.</p>
<p><img src="https://lh3.googleusercontent.com/RXdb4DqyuP-l5my__4cjenReTn6X7bAPivhybSPU5AZWAaAyYsbhWog3FSwSnMiBFYU_47uxduA" alt="mask r-cnn" title="mask r-cnn"></p>
<p>Para nuestra ejmplo usaremos un <a href="https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md">modelo pre-entrenado usando Tensorflow</a> con el conjunto de datos COCO, al igual que lo hicimos en el tutorial <a href="https://acodigo.blogspot.com/2019/03/cargar-modelos-tensorflow-en-opencv-dnn.html">detección de objetos con DNN</a> cargamos los archivos .pb y .pbtxt que corresponden al modelo y la descripción de la arquitectura del mismo.</p>
<pre class=" language-cpp"><code class="prism language-cpp"><span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// cargar el modelo pre-entrenado, debemos indicar la ruta de los archivos .pb y .pbtxt </span>
dnn<span class="token operator">::</span>Net net <span class="token operator">=</span> dnn<span class="token operator">::</span><span class="token function">readNet</span><span class="token punctuation">(</span><span class="token string">"data/files/mask_rcnn_inception_v2_coco_2018_01_28.pb"</span><span class="token punctuation">,</span>
<span class="token string">"data/files/mask_rcnn_inception_v2_coco_2018_01_28.pbtxt"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// cargar la imagen de prueba</span>
Mat image <span class="token operator">=</span> <span class="token function">imread</span><span class="token punctuation">(</span><span class="token string">"data/files/image.jpg"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Mat blob<span class="token punctuation">;</span>
<span class="token comment">// crear el blob 4D a partir de la imagen de entrada</span>
dnn<span class="token operator">::</span><span class="token function">blobFromImage</span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> blob<span class="token punctuation">,</span> <span class="token number">1.0</span><span class="token punctuation">,</span> <span class="token function">Size</span><span class="token punctuation">(</span>image<span class="token punctuation">.</span>cols<span class="token punctuation">,</span> image<span class="token punctuation">.</span>rows<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
vector<span class="token operator"><</span>String<span class="token operator">></span> outputNames <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">"detection_out_final"</span> <span class="token punctuation">,</span> <span class="token string">"detection_masks"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
vector<span class="token operator"><</span>Mat<span class="token operator">></span> outs<span class="token punctuation">;</span>
<span class="token comment">// establecer como entrada el blob creado anteriormente </span>
net<span class="token punctuation">.</span><span class="token function">setInput</span><span class="token punctuation">(</span>blob<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// correr la red neuronal para obtener las salidas para los nombres de la capas indicadas por outputNames</span>
net<span class="token punctuation">.</span><span class="token function">forward</span><span class="token punctuation">(</span>outs<span class="token punctuation">,</span> outputNames<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// leer el archivo que contiene los nombres de las classes</span>
<span class="token function">load_classes_names</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// procesar los resultados devueltos por la red y mostrarlos sobre la imagen de entrada</span>
<span class="token function">post_process</span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> outs<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// visualizar los resultados</span>
<span class="token function">imshow</span><span class="token punctuation">(</span><span class="token string">"Mask-RCNN"</span><span class="token punctuation">,</span> image<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">waitKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Detalles importantes de este código, creamos la red neuronal con <code>readNet(...)</code> luego usamos <code>blobFromImage(...)</code> para convertir la imagen cargada con OpenCV en una entrada válida para la red, usando <code>net.forward(...)</code> corremos la red y obtenemos los resultados, estos serán procesados por la función <code>post_process(...)</code> que describiremos más adelante.</p>
<p>Los resultados obtenidos los procesamos con la función que pasamos a describir, esta es la primera parte del código, es la encargada de obtener el rectángulo que contiene al objeto detectado, puede ser mas de uno y para cada uno de ellos guardamos su ID de clase, puntaje y objeto <code>cv::Rect</code>.</p>
<pre class=" language-cpp"><code class="prism language-cpp"><span class="token keyword">void</span> <span class="token function">post_process</span><span class="token punctuation">(</span>cv<span class="token operator">::</span>Mat<span class="token operator">&</span> frame<span class="token punctuation">,</span> <span class="token keyword">const</span> std<span class="token operator">::</span>vector<span class="token operator"><</span>Mat<span class="token operator">></span><span class="token operator">&</span> outs<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
Mat boxes <span class="token operator">=</span> outs<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// guarda las regiones rectangulares encontradas</span>
Mat masks <span class="token operator">=</span> outs<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// guarda las mascaras correspondientes a las regiones </span>
<span class="token keyword">const</span> <span class="token keyword">int</span> numDetections <span class="token operator">=</span> boxes<span class="token punctuation">.</span>size<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// cantidad de regiones </span>
<span class="token keyword">const</span> <span class="token keyword">int</span> numClasses <span class="token operator">=</span> masks<span class="token punctuation">.</span>size<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// cantidad de mascaras</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> frameW <span class="token operator">=</span> frame<span class="token punctuation">.</span>cols<span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> frameH <span class="token operator">=</span> frame<span class="token punctuation">.</span>rows<span class="token punctuation">;</span>
std<span class="token operator">::</span>vector<span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span> classIds<span class="token punctuation">;</span> <span class="token comment">// ID de clase a la que pertenece el objeto</span>
std<span class="token operator">::</span>vector<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span> confidences<span class="token punctuation">;</span> <span class="token comment">// puntaje </span>
std<span class="token operator">::</span>vector<span class="token operator"><</span>Rect<span class="token operator">></span> predBoxes<span class="token punctuation">;</span> <span class="token comment">// rectangulo</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> numDetections<span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// obtener datos de cada una de las regiones encontradas por la red, se organizan de la siguiente manera:</span>
<span class="token comment">// [batchId, classId, confidence, left, top, right, bottom] - 1x1xNx7</span>
<span class="token keyword">float</span><span class="token operator">*</span> box <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token operator">*</span><span class="token punctuation">)</span>boxes<span class="token punctuation">.</span>ptr<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">float</span> score <span class="token operator">=</span> box<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token comment">// nos quedamos con aquellas que superen el umbral establecido</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>score <span class="token operator">></span> confThreshold<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> classId <span class="token operator">=</span> <span class="token keyword">static_cast</span><span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span><span class="token punctuation">(</span>box<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> boxLeft <span class="token operator">=</span> <span class="token keyword">static_cast</span><span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span><span class="token punctuation">(</span>frameW <span class="token operator">*</span> box<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> boxTop <span class="token operator">=</span> <span class="token keyword">static_cast</span><span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span><span class="token punctuation">(</span>frameH <span class="token operator">*</span> box<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> boxRight <span class="token operator">=</span> <span class="token keyword">static_cast</span><span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span><span class="token punctuation">(</span>frameW <span class="token operator">*</span> box<span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> boxBottom <span class="token operator">=</span> <span class="token keyword">static_cast</span><span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span><span class="token punctuation">(</span>frameH <span class="token operator">*</span> box<span class="token punctuation">[</span><span class="token number">6</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// convertimos los datos a uno de tipo cv::Rect </span>
cv<span class="token operator">::</span>Rect rect<span class="token punctuation">{</span> cv<span class="token operator">::</span>Point<span class="token punctuation">{</span> boxLeft<span class="token punctuation">,</span> boxTop <span class="token punctuation">}</span><span class="token punctuation">,</span> cv<span class="token operator">::</span>Point<span class="token punctuation">{</span> boxRight<span class="token punctuation">,</span> boxBottom <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
rect <span class="token operator">&</span><span class="token operator">=</span> cv<span class="token operator">::</span><span class="token function">Rect</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token number">0</span><span class="token punctuation">,</span><span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> frame<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// guardamos los datos que nos interesen para su uso posterior</span>
classIds<span class="token punctuation">.</span><span class="token function">emplace_back</span><span class="token punctuation">(</span>classId<span class="token punctuation">)</span><span class="token punctuation">;</span>
predBoxes<span class="token punctuation">.</span><span class="token function">emplace_back</span><span class="token punctuation">(</span>rect<span class="token punctuation">)</span><span class="token punctuation">;</span>
confidences<span class="token punctuation">.</span><span class="token function">emplace_back</span><span class="token punctuation">(</span>score<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">//...</span>
<span class="token punctuation">}</span>
</code></pre>
<p>La siguiente parte del código corresponde a la extracción de la máscara para cada uno de los objetos, es necesario redimencionarla ya que la red nos devuelve una máscara de 15x15, luego la dibujamos sobre la imagen para poder visualizarla, dibujamos también el nombre de clase y rectángulo.</p>
<p><img src="https://lh3.googleusercontent.com/BQY0ecSVWaxSOj-VHRV1kpW98fZSO_y2L4jtWX_fQMKK-O7CMbfli69BGqB1xo_Qvk-9lGEZxMw" alt="mask cat dog"></p>
<p>Estas son las dos máscaras obtendas para nuestra imagen de prueba.</p>
<pre class=" language-cpp"><code class="prism language-cpp"><span class="token keyword">void</span> <span class="token function">post_process</span><span class="token punctuation">(</span>cv<span class="token operator">::</span>Mat<span class="token operator">&</span> frame<span class="token punctuation">,</span> <span class="token keyword">const</span> std<span class="token operator">::</span>vector<span class="token operator"><</span>Mat<span class="token operator">></span><span class="token operator">&</span> outs<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">//...</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> indices<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> idx <span class="token operator">=</span> indices<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> Rect box <span class="token operator">=</span> predBoxes<span class="token punctuation">[</span>idx<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> classId <span class="token operator">=</span> classIds<span class="token punctuation">[</span>idx<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token keyword">float</span> conf <span class="token operator">=</span> confidences<span class="token punctuation">[</span>idx<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> Scalar <span class="token function">color</span><span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">120</span><span class="token punctuation">,</span> <span class="token number">147</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> Scalar <span class="token function">rect_color</span><span class="token punctuation">(</span><span class="token number">243</span><span class="token punctuation">,</span> <span class="token number">150</span><span class="token punctuation">,</span> <span class="token number">33</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// obtener la mascara definida para cada uno de los objetos detectados en la imagen de entrada</span>
Mat <span class="token function">mask</span><span class="token punctuation">(</span>masks<span class="token punctuation">.</span>size<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> masks<span class="token punctuation">.</span>size<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span> CV_32F<span class="token punctuation">,</span> masks<span class="token punctuation">.</span>ptr<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token keyword">static_cast</span><span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">,</span> classId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">resize</span><span class="token punctuation">(</span>mask<span class="token punctuation">,</span> mask<span class="token punctuation">,</span> box<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// redimensionar la mascara para que coincida con el tamano de la region</span>
mask <span class="token operator">=</span> mask <span class="token operator">></span> maskThreshold<span class="token punctuation">;</span> <span class="token comment">// elimina aquellas partes de la mascara que no superen el umbral</span>
Mat coloredRoi<span class="token punctuation">;</span>
<span class="token comment">// resaltar en color diferente la mascara correspondiente al objeto detectado</span>
<span class="token function">addWeighted</span><span class="token punctuation">(</span><span class="token function">frame</span><span class="token punctuation">(</span>box<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.3</span><span class="token punctuation">,</span> color<span class="token punctuation">,</span> <span class="token number">0.7</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> coloredRoi<span class="token punctuation">)</span><span class="token punctuation">;</span>
coloredRoi<span class="token punctuation">.</span><span class="token function">copyTo</span><span class="token punctuation">(</span><span class="token function">frame</span><span class="token punctuation">(</span>box<span class="token punctuation">)</span><span class="token punctuation">,</span> mask<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Dibujar rectangulo correspondiente a la region detectada</span>
<span class="token function">rectangle</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> box<span class="token punctuation">,</span> rect_color<span class="token punctuation">)</span><span class="token punctuation">;</span>
std<span class="token operator">::</span>string label <span class="token operator">=</span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"%.2f"</span><span class="token punctuation">,</span> conf<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// obtener el nombre de clase usando si ID devuelto por la red MASK-RCNN</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>classes<span class="token punctuation">.</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
label <span class="token operator">=</span> classes<span class="token punctuation">[</span>classId<span class="token punctuation">]</span> <span class="token operator">+</span> <span class="token string">": "</span> <span class="token operator">+</span> label <span class="token operator">+</span> <span class="token string">" %"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> baseLine <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token comment">// obtener las posiciones para dibujar el texto</span>
cv<span class="token operator">::</span>Size label_size <span class="token operator">=</span> cv<span class="token operator">::</span><span class="token function">getTextSize</span><span class="token punctuation">(</span>label<span class="token punctuation">,</span> cv<span class="token operator">::</span>FONT_HERSHEY_SIMPLEX<span class="token punctuation">,</span> <span class="token number">0.6</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token operator">&</span>baseLine<span class="token punctuation">)</span><span class="token punctuation">;</span>
cv<span class="token operator">::</span>Rect label_rect<span class="token punctuation">{</span> box<span class="token punctuation">.</span><span class="token function">tl</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> cv<span class="token operator">::</span><span class="token function">Point2i</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> baseLine <span class="token operator">+</span> label_size<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">,</span> cv<span class="token operator">::</span><span class="token function">Size</span><span class="token punctuation">(</span>box<span class="token punctuation">.</span>width<span class="token punctuation">,</span> label_size<span class="token punctuation">.</span>height <span class="token operator">+</span> baseLine<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token comment">// dibujar rectangulo de fondo y texto informativo (nombre de clase + puntaje)</span>
<span class="token function">rectangle</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> label_rect<span class="token punctuation">,</span> rect_color<span class="token punctuation">,</span> cv<span class="token operator">::</span>FILLED<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">putText</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> label<span class="token punctuation">,</span> box<span class="token punctuation">.</span><span class="token function">tl</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> cv<span class="token operator">::</span><span class="token function">Point2i</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">4</span><span class="token punctuation">,</span> baseLine <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> cv<span class="token operator">::</span>FONT_HERSHEY_SIMPLEX<span class="token punctuation">,</span> <span class="token number">0.6</span><span class="token punctuation">,</span> cv<span class="token operator">::</span>Scalar<span class="token operator">::</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token number">225</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> LINE_AA<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>También tenemos la función <code>load_classes_names()</code> esta es simple solo lee un archivo de texto y guarda una lista con los nombres de las classes, estos está ordenados por ID y están en inglés.</p>
<p>Código en GitHub: <a href="https://github.com/TutorProgramacion/opencv_mask-rcnn">opencv mask r-cnn</a></p>
<p>Si deseas un ejemplo en Python pudes ver el que se encuentra de manera oficial en OpenCV: <a href="https://github.com/opencv/opencv/blob/master/samples/dnn/mask_rcnn.py">mask_r-cnn.py</a></p>
Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2590617132675118769.post-81121375852478993582019-08-12T12:41:00.002-07:002019-08-12T12:41:16.354-07:00Distribuir aplicación Qt-5 en Windows<p>Luego de haber creado nuestra aplicación Qt 5 para Windows la pregunta es, como la distribuimos, es decir que necesitamos hacer para que nuestra aplicación se ejecute en los ordenadores de los usuarios, para esta tarea el Framework Qt nos provee de una herramienta de línea de comandos llamada <strong>windeployqt</strong>, es este tutorial vamos a ver su uso.</p>
<a name='more'></a>
<p>Asumimos que ya tenemos nuestra aplicación compilada correctamente y ya hemos generado el ejecutable al que para este ejemplo llamaremos test-deploy.exe, ubicamos este archivo y lo copiamos a una carpeta de nuestra preferencia para nosotros <code>"C:\Developer\miapp\test-deploy.exe"</code>.</p>
<p>Lo siguiente es agregar windeployqt al PATH si aun no lo hemos hecho disponemos del script<br>
<strong>qtenv2.bat</strong> para esta tarea el mismo se puede encontrar en la carpeta de instalación de Qt en mi caso <code>"C:\Developer\qt-5.12.3\5.12.3\mingw73_32\bin\qtenv2.bat"</code> abrimos una ventana de comandos y ejecutamos este script.</p>
<p><img src="https://lh3.googleusercontent.com/F9U3nFGNtH_b205MHLakNYLFUyuIBabGwXTpyj8YUNklHae3ywL-_v4WgmDCYBjCI-NsAgehsfM" alt="" title="Qt env vars"></p>
<p>Para finalizar solo debemos ejecutar en la misma ventana CMD el comando: <code>windeployqt aplicacion.exe</code>.</p>
<p><img src="https://lh3.googleusercontent.com/28M4Sy84pAZ6rmTv3PYWHeEeaYZH2Y0AGOfPzXmt3ReEe0IFUTv-KtAo2PK5efRkMG7tuf-BYIg" alt="" title="Qt deploy app.exe"></p>
<p>Para comprobar que todo funciona correctamente puedes llevar la carpeta que contiene la aplicación y todos los archivos que se acaban de crear a una pc que no tenga instalado Qt y ejecutar la aplicación.</p>
<p>Podemos usar una o varias de las siguientes opciones de configuración para cambiar el resultado de nuestro deploy, por ejemplo: <code>windeployqt --no-angle aplicacion.exe</code> en donde <code>--no-angle</code> deshabilita el despliegue de ANGLE, estas son las posibles opciones:</p>
<pre><code>-?, -h, --help Displays this help.
-v, --version Displays version information.
--dir <directory> Use directory instead of binary directory.
--libdir <path> Copy libraries to path.
--plugindir <path> Copy plugins to path.
--debug Assume debug binaries.
--release Assume release binaries.
--pdb Deploy .pdb files (MSVC).
--force Force updating files.
--dry-run Simulation mode. Behave normally, but do not copy/update any files.
--no-patchqt Do not patch the Qt5Core library.
--no-plugins Skip plugin deployment.
--no-libraries Skip library deployment.
--qmldir <directory> Scan for QML-imports starting from directory.
--no-quick-import Skip deployment of Qt Quick imports.
--no-translations Skip deployment of translations.
--no-system-d3d-compiler Skip deployment of the system D3D compiler.
--compiler-runtime Deploy compiler runtime (Desktop only).
--no-compiler-runtime Do not deploy compiler runtime (Desktop only).
--webkit2 Deployment of WebKit2 (web process).
--no-webkit2 Skip deployment of WebKit2.
--json Print to stdout in JSON format.
--angle Force deployment of ANGLE.
--no-angle Disable deployment of ANGLE.
--no-opengl-sw Do not deploy the software rasterizer library.
--list <option> Print only the names of the files copied.
Available options:
source: absolute path of the source files
target: absolute path of the target files
relative: paths of the target files, relative to the target directory
mapping: outputs the source and the relative target, suitable for use within an Appx mapping file
--verbose <level> Verbose level (0-2).
</code></pre>
<p>Sí tu aplicación utiliza Qt WebEngine debes tomar algunas medidas extras: <a href="https://doc.qt.io/qt-5/qtwebengine-deploying.html">Qt deploy QtWebEngine</a></p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2590617132675118769.post-27326487029032666632019-07-18T13:11:00.002-07:002019-07-18T13:11:37.309-07:00Clasificación de género y detección de rostros<p>Seguimos probando lo que podemos hacer con el módulo DNN de OpenCV versión 4.0, esta vez vamos a crear una simple aplicación la cual captura video de la webcam, detecta un rostro e intenta predecir si el mismo pertenece a una cara masculina o femenina.</p>
<a name='more'></a>
<p><img src="https://lh3.googleusercontent.com/nVUZUt3oNUyjiz1VRKyI9Xelljgcygr5rOwir0Ial0Xl43ziw0xE_Ofcdc8RJbu1OtY71n7yWhQ" alt="enter image description here" title="OpenCV DNN"></p>
<p>Lo primero, iniciar la captura proveniente de la webcam, esto ya lo hemos hecho antes por lo que le dejo el enlace al respectivo tutorial: <a href="http://acodigo.blogspot.com/2013/06/acceso-la-webcam.html">Acceso a webcam con OpenCV</a>.</p>
<p>Ahora necesitamos saber si existe un rostro presente en el video capturado, para ello también usaremos un módelo preentrenado para este proposito, anteriormente lo habiamos hecho utilizando <a href="http://acodigo.blogspot.com/2013/06/deteccion-de-rostros.html">clasificadores en cascada</a> pero este método usando redes neuronales es mas robusto.</p>
<h3 id="detección-de-rostros">Detección de rostros</h3>
<p>Al siguiente método le pasamos una instancia de la red neuronal a utilizar, la imagen que deseamos procesar, un vector<rect> en donde se guardarán las regiones rectángulares de los rostros encontrados y por último un valor de tolerancia.</rect></p>
<pre class=" language-cpp"><code class="prism language-cpp"><span class="token keyword">void</span> <span class="token function">getFaceRect</span><span class="token punctuation">(</span>dnn<span class="token operator">::</span>Net net<span class="token punctuation">,</span> cv<span class="token operator">::</span>Mat<span class="token operator">&</span> frame<span class="token punctuation">,</span> vector<span class="token operator"><</span>cv<span class="token operator">::</span>Rect<span class="token operator">></span><span class="token operator">&</span> rc<span class="token punctuation">,</span> <span class="token keyword">double</span> conf_threshold<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> frameHeight <span class="token operator">=</span> frame<span class="token punctuation">.</span>rows<span class="token punctuation">;</span>
<span class="token keyword">int</span> frameWidth <span class="token operator">=</span> frame<span class="token punctuation">.</span>cols<span class="token punctuation">;</span>
<span class="token keyword">double</span> inScaleFactor <span class="token operator">=</span> <span class="token number">1.0</span><span class="token punctuation">;</span>
Size size <span class="token operator">=</span> <span class="token function">Size</span><span class="token punctuation">(</span><span class="token number">300</span><span class="token punctuation">,</span> <span class="token number">300</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Scalar meanVal <span class="token operator">=</span> <span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">104</span><span class="token punctuation">,</span> <span class="token number">117</span><span class="token punctuation">,</span> <span class="token number">123</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
cv<span class="token operator">::</span>Mat inputBlob<span class="token punctuation">;</span>
cv<span class="token operator">::</span>dnn<span class="token operator">::</span><span class="token function">blobFromImage</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> inputBlob<span class="token punctuation">,</span> inScaleFactor<span class="token punctuation">,</span> size<span class="token punctuation">,</span> meanVal<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
net<span class="token punctuation">.</span><span class="token function">setInput</span><span class="token punctuation">(</span>inputBlob<span class="token punctuation">,</span> <span class="token string">"data"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
cv<span class="token operator">::</span>Mat detection <span class="token operator">=</span> net<span class="token punctuation">.</span><span class="token function">forward</span><span class="token punctuation">(</span><span class="token string">"detection_out"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
cv<span class="token operator">::</span>Mat <span class="token function">detectionMat</span><span class="token punctuation">(</span>detection<span class="token punctuation">.</span>size<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> detection<span class="token punctuation">.</span>size<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span> CV_32F<span class="token punctuation">,</span> detection<span class="token punctuation">.</span>ptr<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> detectionMat<span class="token punctuation">.</span>rows<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">float</span> confidence <span class="token operator">=</span> detectionMat<span class="token punctuation">.</span>at<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>confidence <span class="token operator">></span> conf_threshold<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> x1 <span class="token operator">=</span> <span class="token keyword">static_cast</span><span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span><span class="token punctuation">(</span>detectionMat<span class="token punctuation">.</span>at<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span> <span class="token operator">*</span> frameWidth<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> y1 <span class="token operator">=</span> <span class="token keyword">static_cast</span><span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span><span class="token punctuation">(</span>detectionMat<span class="token punctuation">.</span>at<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token operator">*</span> frameHeight<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> x2 <span class="token operator">=</span> <span class="token keyword">static_cast</span><span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span><span class="token punctuation">(</span>detectionMat<span class="token punctuation">.</span>at<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span> <span class="token operator">*</span> frameWidth<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> y2 <span class="token operator">=</span> <span class="token keyword">static_cast</span><span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span><span class="token punctuation">(</span>detectionMat<span class="token punctuation">.</span>at<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span> <span class="token operator">*</span> frameHeight<span class="token punctuation">)</span><span class="token punctuation">;</span>
rc<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>cv<span class="token operator">::</span><span class="token function">Rect</span><span class="token punctuation">(</span>cv<span class="token operator">::</span><span class="token function">Point</span><span class="token punctuation">(</span>x1<span class="token punctuation">,</span> y1<span class="token punctuation">)</span><span class="token punctuation">,</span> cv<span class="token operator">::</span><span class="token function">Point</span><span class="token punctuation">(</span>x2<span class="token punctuation">,</span> y2<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Detalles importante del código:</p>
<p>Convertir la imagen a procesar en un formato que la red neuronal pueda manejar, de esto se encarga <code>dnn::blobFromImage</code>, luego este será nuestra entrada para la DNN, lo hacemos con <code>setInput(...)</code></p>
<pre class=" language-cpp"><code class="prism language-cpp"> cv<span class="token operator">::</span>Mat inputBlob<span class="token punctuation">;</span>
cv<span class="token operator">::</span>dnn<span class="token operator">::</span><span class="token function">blobFromImage</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> inputBlob<span class="token punctuation">,</span> inScaleFactor<span class="token punctuation">,</span> size<span class="token punctuation">,</span> meanVal<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
net<span class="token punctuation">.</span><span class="token function">setInput</span><span class="token punctuation">(</span>inputBlob<span class="token punctuation">,</span> <span class="token string">"data"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Correr la red y obtener la prediccion, para esto tenemos: <code>net.forward()</code></p>
<pre class=" language-cpp"><code class="prism language-cpp"> cv<span class="token operator">::</span>Mat detection <span class="token operator">=</span> net<span class="token punctuation">.</span><span class="token function">forward</span><span class="token punctuation">(</span><span class="token string">"detection_out"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
cv<span class="token operator">::</span>Mat <span class="token function">detectionMat</span><span class="token punctuation">(</span>detection<span class="token punctuation">.</span>size<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> detection<span class="token punctuation">.</span>size<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span> CV_32F<span class="token punctuation">,</span> detection<span class="token punctuation">.</span>ptr<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Guardar todos los rectángulos que corresponden a los restros detectados cuya probalidad de ser un rostro esté por encima de la tolerancia que se indico.</p>
<pre class=" language-cpp"><code class="prism language-cpp"> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> detectionMat<span class="token punctuation">.</span>rows<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">float</span> confidence <span class="token operator">=</span> detectionMat<span class="token punctuation">.</span>at<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>confidence <span class="token operator">></span> conf_threshold<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> x1 <span class="token operator">=</span> <span class="token keyword">static_cast</span><span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span><span class="token punctuation">(</span>detectionMat<span class="token punctuation">.</span>at<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span> <span class="token operator">*</span> frameWidth<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> y1 <span class="token operator">=</span> <span class="token keyword">static_cast</span><span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span><span class="token punctuation">(</span>detectionMat<span class="token punctuation">.</span>at<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token operator">*</span> frameHeight<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> x2 <span class="token operator">=</span> <span class="token keyword">static_cast</span><span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span><span class="token punctuation">(</span>detectionMat<span class="token punctuation">.</span>at<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span> <span class="token operator">*</span> frameWidth<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> y2 <span class="token operator">=</span> <span class="token keyword">static_cast</span><span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span><span class="token punctuation">(</span>detectionMat<span class="token punctuation">.</span>at<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span> <span class="token operator">*</span> frameHeight<span class="token punctuation">)</span><span class="token punctuation">;</span>
rc<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>cv<span class="token operator">::</span><span class="token function">Rect</span><span class="token punctuation">(</span>cv<span class="token operator">::</span><span class="token function">Point</span><span class="token punctuation">(</span>x1<span class="token punctuation">,</span> y1<span class="token punctuation">)</span><span class="token punctuation">,</span> cv<span class="token operator">::</span><span class="token function">Point</span><span class="token punctuation">(</span>x2<span class="token punctuation">,</span> y2<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Ya tenemos el rostro ahora podemos intentar predecir si es masculino o femenino.</p>
<h3 id="clasificación-de-género">Clasificación de género</h3>
<p>Para obtener el género usaremos un módelo entrenado con el framework Caffe, este nos devuelve la probablilidad de que la imagen de entrada pertenesca a la clase uno o dos, siendo estas mujer y hombre, este es el código:</p>
<pre class=" language-cpp"><code class="prism language-cpp"><span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">auto</span> net_file <span class="token operator">=</span> <span class="token string">"caffe-models/caffe/res10_300x300_ssd_iter_140000_fp16.caffemodel"</span><span class="token punctuation">;</span>
<span class="token keyword">auto</span> net_desc <span class="token operator">=</span> <span class="token string">"caffe-models/caffe/res10_300x300_ssd_iter_140000_fp16.prototxt"</span><span class="token punctuation">;</span>
<span class="token keyword">auto</span> net_file1 <span class="token operator">=</span> <span class="token string">"caffe-models/caffe/gender_net.caffemodel"</span><span class="token punctuation">;</span>
<span class="token keyword">auto</span> net_desc1 <span class="token operator">=</span> <span class="token string">"caffe-models/caffe/gender_deploy.prototxt"</span><span class="token punctuation">;</span>
<span class="token keyword">auto</span> net <span class="token operator">=</span> dnn<span class="token operator">::</span><span class="token function">readNetFromCaffe</span><span class="token punctuation">(</span>net_desc<span class="token punctuation">,</span> net_file<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">auto</span> net_gender <span class="token operator">=</span> dnn<span class="token operator">::</span><span class="token function">readNetFromCaffe</span><span class="token punctuation">(</span>net_desc1<span class="token punctuation">,</span> net_file1<span class="token punctuation">)</span><span class="token punctuation">;</span>
VideoCapture capture<span class="token punctuation">;</span>
capture<span class="token punctuation">.</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//...</span>
vector<span class="token operator"><</span>string<span class="token operator">></span> genderList <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">"Hombre"</span><span class="token punctuation">,</span> <span class="token string">"Mujer"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
Scalar meanVal <span class="token operator">=</span> <span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">104</span><span class="token punctuation">,</span> <span class="token number">117</span><span class="token punctuation">,</span> <span class="token number">123</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>capture<span class="token punctuation">.</span><span class="token function">isOpened</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
Mat frame<span class="token punctuation">;</span>
capture <span class="token operator">>></span> frame<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>frame<span class="token punctuation">.</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
vector<span class="token operator"><</span>cv<span class="token operator">::</span>Rect<span class="token operator">></span> rcFace<span class="token punctuation">;</span>
<span class="token function">getFaceRect</span><span class="token punctuation">(</span>net<span class="token punctuation">,</span> frame<span class="token punctuation">,</span> rcFace<span class="token punctuation">,</span> <span class="token number">0.6</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">auto</span> roi_face <span class="token operator">:</span> rcFace<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">auto</span> face <span class="token operator">=</span> <span class="token function">frame</span><span class="token punctuation">(</span>roi_face<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">auto</span> blob <span class="token operator">=</span> dnn<span class="token operator">::</span><span class="token function">blobFromImage</span><span class="token punctuation">(</span>face<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">Size</span><span class="token punctuation">(</span><span class="token number">227</span><span class="token punctuation">,</span> <span class="token number">227</span><span class="token punctuation">)</span><span class="token punctuation">,</span> meanVal<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
net_gender<span class="token punctuation">.</span><span class="token function">setInput</span><span class="token punctuation">(</span>blob<span class="token punctuation">)</span><span class="token punctuation">;</span>
vector<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span> genderPreds <span class="token operator">=</span> net_gender<span class="token punctuation">.</span><span class="token function">forward</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> max_index_gender <span class="token operator">=</span> std<span class="token operator">::</span><span class="token function">distance</span><span class="token punctuation">(</span>genderPreds<span class="token punctuation">.</span><span class="token function">begin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">max_element</span><span class="token punctuation">(</span>genderPreds<span class="token punctuation">.</span><span class="token function">begin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> genderPreds<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
string gender <span class="token operator">=</span> genderList<span class="token punctuation">[</span>max_index_gender<span class="token punctuation">]</span><span class="token punctuation">;</span>
cv<span class="token operator">::</span><span class="token function">rectangle</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> roi_face<span class="token punctuation">,</span> cv<span class="token operator">::</span><span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> LINE_AA<span class="token punctuation">)</span><span class="token punctuation">;</span>
cv<span class="token operator">::</span><span class="token function">putText</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> gender<span class="token punctuation">,</span> roi_face<span class="token punctuation">.</span><span class="token function">br</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> cv<span class="token operator">::</span><span class="token function">Point</span><span class="token punctuation">(</span>roi_face<span class="token punctuation">.</span>width <span class="token operator">-</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">,</span> FONT_HERSHEY_SIMPLEX<span class="token punctuation">,</span> <span class="token number">0.60</span><span class="token punctuation">,</span> cv<span class="token operator">::</span><span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> LINE_AA<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// ...</span>
cv<span class="token operator">::</span><span class="token function">imshow</span><span class="token punctuation">(</span><span class="token string">"face"</span><span class="token punctuation">,</span> frame<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">waitKey</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">27</span><span class="token punctuation">)</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
capture<span class="token punctuation">.</span><span class="token function">release</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Detalles importantes:</p>
<p>Cargar los modelos para la deteccion de rostros y la clasificación, el primero lo puedes encontrar entre los ejemplos porporcionados en el repositorio de OpenCV y el segundo en el siguiente enlace: <a href="https://talhassner.github.io/home/publication/2015_CVPR">gender-model</a></p>
<pre class=" language-cpp"><code class="prism language-cpp"> <span class="token keyword">auto</span> net_file <span class="token operator">=</span> <span class="token string">"caffe-models/caffe/res10_300x300_ssd_iter_140000_fp16.caffemodel"</span><span class="token punctuation">;</span>
<span class="token keyword">auto</span> net_desc <span class="token operator">=</span> <span class="token string">"caffe-models/caffe/res10_300x300_ssd_iter_140000_fp16.prototxt"</span><span class="token punctuation">;</span>
<span class="token keyword">auto</span> net_file1 <span class="token operator">=</span> <span class="token string">"caffe-models/caffe/gender_net.caffemodel"</span><span class="token punctuation">;</span>
<span class="token keyword">auto</span> net_desc1 <span class="token operator">=</span> <span class="token string">"caffe-models/caffe/gender_deploy.prototxt"</span><span class="token punctuation">;</span>
<span class="token keyword">auto</span> net <span class="token operator">=</span> dnn<span class="token operator">::</span><span class="token function">readNetFromCaffe</span><span class="token punctuation">(</span>net_desc<span class="token punctuation">,</span> net_file<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">auto</span> net_gender <span class="token operator">=</span> dnn<span class="token operator">::</span><span class="token function">readNetFromCaffe</span><span class="token punctuation">(</span>net_desc1<span class="token punctuation">,</span> net_file1<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Obtener la región que contiene el rostro con <code>getFaceRect(...)</code> función que explicamos previamente, luego corremos la red usando como entrada la región encontrada, <code>net_gender.forward()</code> esto nos devolverá un conjunto de datos que representa la probabilidad de que el rostro pertenesca a la clase uno o dos, nos quedaremos con el indice de la clase que tenga un valor más alto de probabilidad.</p>
<p>El restro del código es solo para mostrar la salida, marcar la cara e indicar con un texto la clase a la que pertenece.</p>
<pre class=" language-cpp"><code class="prism language-cpp">vector<span class="token operator"><</span>cv<span class="token operator">::</span>Rect<span class="token operator">></span> rcFace<span class="token punctuation">;</span>
<span class="token function">getFaceRect</span><span class="token punctuation">(</span>net<span class="token punctuation">,</span> frame<span class="token punctuation">,</span> rcFace<span class="token punctuation">,</span> <span class="token number">0.6</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">auto</span> roi_face <span class="token operator">:</span> rcFace<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">auto</span> face <span class="token operator">=</span> <span class="token function">frame</span><span class="token punctuation">(</span>roi_face<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">auto</span> blob <span class="token operator">=</span> dnn<span class="token operator">::</span><span class="token function">blobFromImage</span><span class="token punctuation">(</span>face<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">Size</span><span class="token punctuation">(</span><span class="token number">227</span><span class="token punctuation">,</span> <span class="token number">227</span><span class="token punctuation">)</span><span class="token punctuation">,</span> meanVal<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
net_gender<span class="token punctuation">.</span><span class="token function">setInput</span><span class="token punctuation">(</span>blob<span class="token punctuation">)</span><span class="token punctuation">;</span>
vector<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span> genderPreds <span class="token operator">=</span> net_gender<span class="token punctuation">.</span><span class="token function">forward</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> max_index_gender <span class="token operator">=</span> std<span class="token operator">::</span><span class="token function">distance</span><span class="token punctuation">(</span>genderPreds<span class="token punctuation">.</span><span class="token function">begin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">max_element</span><span class="token punctuation">(</span>genderPreds<span class="token punctuation">.</span><span class="token function">begin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> genderPreds<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
string gender <span class="token operator">=</span> genderList<span class="token punctuation">[</span>max_index_gender<span class="token punctuation">]</span><span class="token punctuation">;</span>
cv<span class="token operator">::</span><span class="token function">rectangle</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> roi_face<span class="token punctuation">,</span> cv<span class="token operator">::</span><span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> LINE_AA<span class="token punctuation">)</span><span class="token punctuation">;</span>
cv<span class="token operator">::</span><span class="token function">putText</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> gender<span class="token punctuation">,</span> roi_face<span class="token punctuation">.</span><span class="token function">br</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> cv<span class="token operator">::</span><span class="token function">Point</span><span class="token punctuation">(</span>roi_face<span class="token punctuation">.</span>width <span class="token operator">-</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">,</span> FONT_HERSHEY_SIMPLEX<span class="token punctuation">,</span> <span class="token number">0.60</span><span class="token punctuation">,</span> cv<span class="token operator">::</span><span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> LINE_AA<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>El código completo y los modelos los puedes encontrar en el repositorio indicado abajo, recordar que este ejemplo está preparado para trabajar con la webcam y además se incluye el script CMake para generar el proyecto fácilmente.</p>
<p><a href="https://github.com/TutorProgramacion/opencv_gender_dnn">Repositorio de código</a></p>
Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2590617132675118769.post-43056165868814078682019-06-16T07:48:00.002-07:002019-06-16T07:48:20.296-07:00Medir tiempo de ejecución y FPS<p>En ocaciones necesitamos conocer el tiempo que le toma a una función realizar su trabajo, para ello utilizaremos las funciones proporcionadas por OpenCV, estas son <code>cv::getTickFrequency()</code> y <code>cv::getTickCount()</code>, mas adelante veremos que hace cada una de ellas y como podemos usarlas para calcular los FPS cuando hacemos una aplicacion que funcione en tiempo real.</p>
<a name='more'></a>
<h3 id="medir-tiempo-de-ejecución">Medir tiempo de ejecución</h3>
<p>Calculamos el tiempo de ejecución de una función de la siguiente manera:</p>
<pre class=" language-c"><code class="prism ++ language-c"><span class="token keyword">double</span> t <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">double</span><span class="token punctuation">)</span><span class="token function">getTickCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ejecutar nuestra funcion ...</span>
t <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">double</span><span class="token punctuation">)</span><span class="token function">getTickCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> t<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token function">getTickFrequency</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
cout <span class="token operator"><<</span> <span class="token string">"Tiempo en segundos: "</span> <span class="token operator"><<</span> t <span class="token operator"><<</span> endl<span class="token punctuation">;</span>
</code></pre>
<p>La función <code>cv.getTickCount()</code> devuelve el número de ciclos de reloj después de un evento de referencia hasta el momento en que se llama a esta función. Entonces, si lo llama antes y después de la ejecución de la función, obtiene la cantidad de ciclos de reloj utilizados para ejecutar una función.</p>
<p>La función <code>cv.getTickFrequency()</code> devuelve la frecuencia de los ciclos de reloj, o la cantidad de ciclos de reloj por segundo.</p>
<h3 id="obtener-fps-en-tiempo-real">Obtener FPS en tiempo real</h3>
<p>Usando los conocimientos aprendidos anteriormente vamos a crear una aplicacion que captura video de la webcam en tiempo real y la procesa con algoritmo básico, la idea es medir el tiempo y calcular los FPS (cuadros por segundo) promedio a los que se ejecuta nuestra aplicación.</p>
<p>Código de ejemplo:</p>
<pre class=" language-c"><code class="prism ++ language-c"><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><opencv2/opencv.hpp></span></span>
<span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><iostream></span></span>
using namespace cv<span class="token punctuation">;</span>
using namespace std<span class="token punctuation">;</span>
<span class="token keyword">void</span> <span class="token function">processFrame</span><span class="token punctuation">(</span>cv<span class="token punctuation">:</span><span class="token punctuation">:</span>Mat<span class="token operator">&</span> frame<span class="token punctuation">)</span> <span class="token punctuation">{</span>
Mat gray<span class="token punctuation">,</span> blur<span class="token punctuation">,</span> blend<span class="token punctuation">;</span>
<span class="token function">cvtColor</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> gray<span class="token punctuation">,</span> COLOR_BGR2GRAY<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">GaussianBlur</span><span class="token punctuation">(</span>gray<span class="token punctuation">,</span> blur<span class="token punctuation">,</span> <span class="token function">Size</span><span class="token punctuation">(</span><span class="token number">21</span><span class="token punctuation">,</span> <span class="token number">21</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">cvtColor</span><span class="token punctuation">(</span>blur<span class="token punctuation">,</span> frame<span class="token punctuation">,</span> COLOR_GRAY2BGR<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
VideoCapture capture<span class="token punctuation">;</span>
capture<span class="token punctuation">.</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
int64 counter <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">double</span> elapsed <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> fps <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
int64 start <span class="token operator">=</span> <span class="token function">getTickCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>capture<span class="token punctuation">.</span><span class="token function">isOpened</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
Mat frame<span class="token punctuation">;</span>
capture <span class="token operator">>></span> frame<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>frame<span class="token punctuation">.</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">processFrame</span><span class="token punctuation">(</span>frame<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
int64 delta <span class="token operator">=</span> <span class="token function">getTickCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> start<span class="token punctuation">;</span>
<span class="token keyword">double</span> freq <span class="token operator">=</span> <span class="token function">getTickFrequency</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">double</span> elap <span class="token operator">=</span> delta <span class="token operator">/</span> freq<span class="token punctuation">;</span>
counter <span class="token operator">+</span><span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>elap <span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
fps <span class="token operator">=</span> counter <span class="token operator">/</span> elap<span class="token punctuation">;</span>
elapsed <span class="token operator">=</span> elap <span class="token operator">/</span> fps<span class="token punctuation">;</span>
counter <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
start <span class="token operator">=</span> <span class="token function">getTickCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
String text <span class="token operator">=</span> cv<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"Elapsed time: %.3f s - FPS: %.2f"</span><span class="token punctuation">,</span> elapsed<span class="token punctuation">,</span> fps<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> baseline <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
Size size <span class="token operator">=</span> cv<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">getTextSize</span><span class="token punctuation">(</span>text<span class="token punctuation">,</span> FONT_HERSHEY_PLAIN<span class="token punctuation">,</span> <span class="token number">1.0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token operator">&</span>baseline<span class="token punctuation">)</span><span class="token punctuation">;</span>
cv<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">rectangle</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> cv<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">Rect</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> size<span class="token punctuation">.</span>width <span class="token operator">+</span> <span class="token number">10</span><span class="token punctuation">,</span> size<span class="token punctuation">.</span>height <span class="token operator">+</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">128</span><span class="token punctuation">,</span> <span class="token number">128</span><span class="token punctuation">)</span><span class="token punctuation">,</span> FILLED<span class="token punctuation">,</span> LINE_AA<span class="token punctuation">)</span><span class="token punctuation">;</span>
cv<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">putText</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> text<span class="token punctuation">,</span> <span class="token function">Point</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> size<span class="token punctuation">.</span>height <span class="token operator">+</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">,</span> FONT_HERSHEY_PLAIN<span class="token punctuation">,</span> <span class="token number">1.0</span><span class="token punctuation">,</span> <span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> LINE_AA<span class="token punctuation">)</span><span class="token punctuation">;</span>
cv<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">imshow</span><span class="token punctuation">(</span><span class="token string">"face"</span><span class="token punctuation">,</span> frame<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">waitKey</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">27</span><span class="token punctuation">)</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
capture<span class="token punctuation">.</span><span class="token function">release</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>La parte que mas nos interesa de este código es el siguiente fragmento:</p>
<pre class=" language-c"><code class="prism ++ language-c"> <span class="token keyword">double</span> freq <span class="token operator">=</span> <span class="token function">getTickFrequency</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">double</span> elap <span class="token operator">=</span> delta <span class="token operator">/</span> freq<span class="token punctuation">;</span>
counter <span class="token operator">+</span><span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>elap <span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
fps <span class="token operator">=</span> counter <span class="token operator">/</span> elap<span class="token punctuation">;</span>
elapsed <span class="token operator">=</span> elap <span class="token operator">/</span> fps<span class="token punctuation">;</span>
counter <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
start <span class="token operator">=</span> <span class="token function">getTickCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Obtenemos el tiempo transcurrido como lo hicimos anteriormente, tambien agregamos un contador para calcular la cantidad de frames que han sido procesados luego de haber transcurrido 1 segundo, calculamos los FPS promedio y reiniciamos todo para el siguiente ciclo.</p>
<p>En el resto del códogo mostramos la información disponible.</p>
<p><img src="https://lh3.googleusercontent.com/RVfssa1iIsJZjnbfXtZKj-zRGza5CbwXIWxOBLYOGjT-RNVlTpilWliMGrODIYMYZYcTZsJ2iH0" alt="enter image description here" title="OpenCV FPS"></p>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2590617132675118769.post-74998431635850968112019-05-09T07:51:00.002-07:002019-05-09T07:51:26.598-07:00Emulador android en CPU AMD Ryzen<p>A partir de las versiones 3.2 Beta de Android Studio se introdujo la posibilidad de usar el emulador android en procesadores AMD anteriormente esto era posible pero el redimiento no estaba a la altura, haciendo uso de la <a href="https://docs.microsoft.com/es-es/virtualization/api/">API de virtualizacion</a> de Windows 10 podemos acelarar la ejecución del emulador y trabajar mucho mejor sin la necesidad de tener una CPU Intel.</p>
<a name='more'></a>
<p>Usando una laptop con un procesador Ryzen a la cual le instalamos Android Studio, creamos un proyecto he intentamos lanzar el emulador y obtenemos lo siguiente:</p>
<p><img src="https://lh3.googleusercontent.com/CxMXsud7Rwcm6bs8OOfnnkYybY1A70IQbjljGfKQTjdEhn0cSUqEmHqhtAfLDoQ4pQXv3T0NkHI" alt="enter image description here" title="Android en CPU AMD"></p>
<p>Como podemos ver tenemos el mensaje de error: <strong>Emulator: emulator: ERROR: x86 emulation currently requires hardware acceleration!</strong>, este mensaje puede ser diferente dependiendo de la version pero en general dice lo mismo, para solucionarlo debemos hacer lo siguiente:</p>
<p>Primero asegurarnos de tener los requisitos mínimos, entre ellos:</p>
<ul>
<li>Windows 10 con la actualizacion Abril 2018 Procesador AMD Ryzen</li>
<li>Android Studio 3.2 Beta o superior Activar la característica:</li>
<li>“Windows Hypervisor Platform” para esto vamos a Panel de control / Programas y características, en el panel de la izquierda pulsamos: activar o desactivar características de windows.</li>
</ul>
<p><img src="https://lh3.googleusercontent.com/P07B8pNOHsUZ5Jt8bYYsx4cAizEmtCPvMZgH2Zrk6zLeixFz9mOTdjbvHi0F5UF9OUg2gRqk3aQ" alt="enter image description here" title="Windows hipervisor platform"></p>
<p>Al hacer esto tendremos que reiniciar y listo, ya podremos ejecutar el emulador sin inconvenientes.</p>
<p><img src="https://4.bp.blogspot.com/--JDGMpc-dhE/W0OUetzsGyI/AAAAAAAAFmQ/IVVQjR5YF_UQEhrmq21chrm9sGuvk-GCQCLcBGAs/s1600/amd_android_emulator.png" alt="enter image description here"></p>
Unknownnoreply@blogger.com7tag:blogger.com,1999:blog-2590617132675118769.post-6899037625148192792019-05-08T08:22:00.002-07:002019-05-08T08:22:42.879-07:00Conectar OpenCV a cámara IP<p>Creamos este corto tutorial para que podamos aprender a conectar una aplicación OpenCV a una cámara IP, decir que es bastante sencillo y no hay que hacer mas que colocar la dirección IP a la que nos deseamos conectar, el resto es exactamente igual a como lo hariamos para trabajar con un video en local.</p>
<a name='more'></a>
<p>Lo primero es que no dispongo de una cámara IP por lo que utilizaré una App Android llama <a href="https://play.google.com/store/apps/details?id=com.pas.webcam&hl=es_PA">Ip Webcam</a> para que mi dispositivo móvil se comporte como una cámara IP, la aplicacion es facil de usar, instalamos y luego pulsamos Iniciar servidor, en la pantalla nos aparecerá la dirección a la que debemos conectarnos para capturar las imagenes.</p>
<p><img src="https://lh3.ggpht.com/Nz6jdaP_-sz7ci_jng-p-vmpgX4BdMGPOXvcQ9CSJvngTaFTwR8LQnL0rhnL7FNFu40=w1536-h722-rw" alt="enter image description here"></p>
<p>Lo siguente es crear nuestro código C++ para obtener las imágenes y procesarlas con OpenCV, en su majoria el código es igual al que vimos en el tutorial que explica como <a href="https://acodigo.blogspot.com/2013/06/acceso-la-webcam.html">cargar un video desde la webcam</a> y precesarlo.</p>
<pre class=" language-cpp"><code class="prism language-cpp"><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><opencv2/opencv.hpp></span></span>
<span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><iostream></span></span>
<span class="token keyword">using</span> <span class="token keyword">namespace</span> std<span class="token punctuation">;</span>
<span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
cv<span class="token operator">::</span>VideoCapture cap<span class="token punctuation">;</span>
<span class="token keyword">bool</span> opened <span class="token operator">=</span> cap<span class="token punctuation">.</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token string">"http://name:pass@192.167.44.1:8080/videofeed"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
cout <span class="token operator"><<</span> <span class="token string">"IP Cam open: "</span> <span class="token operator"><<</span> opened<span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>opened<span class="token punctuation">)</span> <span class="token punctuation">{</span>
cv<span class="token operator">::</span>Mat frame<span class="token punctuation">;</span>
cap <span class="token operator">>></span> frame<span class="token punctuation">;</span>
cv<span class="token operator">::</span><span class="token function">cvtColor</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> frame<span class="token punctuation">,</span> cv<span class="token operator">::</span>COLOR_BGR2GRAY<span class="token punctuation">)</span><span class="token punctuation">;</span>
cv<span class="token operator">::</span><span class="token function">resize</span><span class="token punctuation">(</span>frame<span class="token punctuation">,</span> frame<span class="token punctuation">,</span> cv<span class="token operator">::</span><span class="token function">Size</span><span class="token punctuation">(</span><span class="token number">800</span><span class="token punctuation">,</span> <span class="token number">600</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
cv<span class="token operator">::</span><span class="token function">imshow</span><span class="token punctuation">(</span><span class="token string">"Video IP"</span><span class="token punctuation">,</span> frame<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>cv<span class="token operator">::</span><span class="token function">waitKey</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">27</span><span class="token punctuation">)</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Lo único diferente que observamos en este código es lo siguiente:</p>
<pre class=" language-cpp"><code class="prism language-cpp">cap<span class="token punctuation">.</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token string">"http://name:pass@192.167.44.1:8080/videofeed"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Si haz configurado la App para usar un nombre de usuario y contraseña deberas ingresarlos en name y pass por ejemplo:<br>
<code>http://juanperez:123456789@192.167.44.1:8080/videofeed</code> si no requieres esto escribes la dirección de la siguiente manera: <code>http://192.167.44.1:8080/videofeed</code> debes tener en cuenta que la IP y puerto puedes variar así que asegurate de escribir la que aparece en la pantalla de la aplicación.</p>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2590617132675118769.post-83531717707735369292019-05-07T06:29:00.001-07:002019-05-07T06:29:01.693-07:00Activar C++ 17 en Visual Studio 2019<p>Visual Studio 2019 tiene soporte para los estandares C++ 14 y C++ 17 pero al crear un proyecto estos no están habilitados por defecto, por lo que se hace necesario activar esta característica para que la misma pueda ser reconocida por el IDE.</p>
<p>Veamos el siguiente código de ejemplo:</p>
<p><img src="https://lh3.googleusercontent.com/69spAyVZTfHPMLqJsX1m0ItDi8BxZ6L5T5dhxf9T-lE2T9NDdLjTZw0-sh39_1UJZ6B9IXpYXOU" alt="Error sin C++ 17" title="Sin C++ 17"></p>
<p>Como vemos se marca el error en el if al utilizar un if-init, para solucionarlo debemos indicarle al IDE que usaremos el estándar 17, para ello vamos a la opción propiedades del proyecto / C++ / idioma / Estándar de lenguaje</p>
<p><img src="https://lh3.googleusercontent.com/k1gbwMBGjbZ2hB3cwq2QP0u1qKk_Nnn_uzgEjI2kV52U1sURB-QRVbpcpr96VJP23Qxffxo1BrU" alt="Activar C++ 17 en VS 2019" title="Activar C++ 17 en VS 2019"></p>
<p>Con esto podremos ver que ya no se muestra el error y podemos compilar sin problemas.</p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2590617132675118769.post-76778773738593420042019-03-18T06:39:00.001-07:002019-03-18T06:38:46.633-07:00Estimar pose cuerpo humano<p>Para este tutorial veremos como estimar la pose de un cuerpo humano, es decir, trataremos de localizar las posiciones en las que encuentra cada una de las partes del cuerpo, brazos, piernas, cabeza, tronco, etc., para esto utilizaremos PoseNet que trabaja sobre Tensorflow, esta vez lo haremos desde NodeJS.</p>
<a name='more'></a>
<p>PoseNet puede extraer las posiciones ya sea si se proporciona una una imagen que contenga un solo cuerpo o varios en la misma imagen, para esto tenemos métodos diferentes que veremos mas adelante.</p>
<h3 id="cargar-modelo-pre-entrenado">Cargar modelo pre entrenado</h3>
<p>Para esto utilizaremos el método <code>load(multiplier)</code> enviándole el parámetro indicado, este establece la versión del modelo que deseamos utilizar para la predicción, puede ser: 1.0, 0.75, 0.50, por defecto es 0.75, este es recomendable para versiones de hardware de rango medio, si tienes pocos recursos deberías utilizar 0.50 y si cuentas con hardware potente pues 1.0, cuanto mayor sea este valor mejor nuestras predicciones pero en contra requieren mayor tiempo de cómputo.</p>
<pre class=" language-js"><code class="prism language-js"><span class="token keyword">const</span> net <span class="token operator">=</span> <span class="token keyword">await</span> posenet<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span>multiplier<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<h3 id="estimar-pose-un-solo-cuerpo">Estimar pose un solo cuerpo</h3>
<p>El método <code>estimateSinglePose(...)</code> nos servirá para detectar las posiciones de un solo cuerpo presente en la imagen de entrada, deberemos pasar los siguientes parámetros:</p>
<ul>
<li><strong>image</strong> - Imagen de entrada para la red neuronal.</li>
<li><strong>imageScaleFactor</strong> - Un número entre 0.2 y 1.0, el valor predeterminado es 0.50, usaremos este valor para reducir el tamaño de la imagen y así aumentar la velocidad de procesamiento pero disminuimos la precisión.</li>
<li><strong>flipHorizontal</strong> - Valor predeterminado es falso, indica si las poses deben voltearse o reflejarse horizontalmente.</li>
<li><strong>outputStride</strong> - Paso deseado para las salidas cuando se alimenta la imagen a través del modelo, puede ser 32, 16, 8. El valor predeterminado es 16, cuanto mayor sea el número, más rápido será el rendimiento pero más lenta será la precisión, y viceversa.</li>
</ul>
<pre class=" language-js"><code class="prism language-js"><span class="token keyword">const</span> pose <span class="token operator">=</span> <span class="token keyword">await</span> net<span class="token punctuation">.</span><span class="token function">estimateSinglePose</span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> imageScaleFactor<span class="token punctuation">,</span> flipHorizontal<span class="token punctuation">,</span> outputStride<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>El resultado devuelto tiene la siguiente estructura:</p>
<pre class=" language-json"><code class="prism language-json"><span class="token punctuation">{</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.32371445304906</span><span class="token punctuation">,</span>
<span class="token string">"keypoints"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">76.291801452637</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">253.36747741699</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"nose"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.99539834260941</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">71.10383605957</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">253.54365539551</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"leftEye"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.98781454563141</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">71.839515686035</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">246.00454711914</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"rightEye"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.99528175592422</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">72.848854064941</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">263.08151245117</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"leftEar"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.84029853343964</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">79.956565856934</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">234.26812744141</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"rightEar"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.92544466257095</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">98.34538269043</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">399.64068603516</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"leftShoulder"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.99559044837952</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">95.082359313965</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">458.21868896484</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"rightShoulder"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.99583911895752</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">94.626205444336</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">163.94561767578</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"leftElbow"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.9518963098526</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">150.2349395752</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">245.06030273438</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"rightElbow"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.98052614927292</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">113.9603729248</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">393.19735717773</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"leftWrist"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.94009721279144</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">186.47859191895</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">257.98034667969</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"rightWrist"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.98029226064682</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">208.5266418457</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">284.46710205078</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"leftHip"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.97870296239853</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">209.9910736084</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">243.31219482422</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"rightHip"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.97424703836441</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">281.61965942383</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">310.93188476562</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"leftKnee"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.98368924856186</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">282.80120849609</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">203.81164550781</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"rightKnee"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.96947449445724</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">360.62716674805</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">292.21047973633</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"leftAnkle"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.8883239030838</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">347.41177368164</span><span class="token punctuation">,</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">203.88229370117</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"rightAnkle"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.8255187869072</span>
<span class="token punctuation">}</span>
<span class="token punctuation">]</span>
<span class="token punctuation">}</span>
</code></pre>
<h3 id="estimar-pose-varios-cuerpos">Estimar pose varios cuerpos</h3>
<p>El método <code>estimateMultiplePoses(...)</code> nos permite obtener las posiciones de todos los cuerpos que estén presentes en la imagen de entrada, los parámetros a utilizar son los mismo que en el método anterior mas tres extras que son opcionales, estos son:</p>
<ul>
<li><strong>maxPoseDetections</strong>: el número máximo de poses a detectar. El valor predeterminado es 5.</li>
<li><strong>scoreThreshold</strong>: solo devuelve las detecciones de instancia que tienen una puntuación mayor o igual a este valor. Por defecto es 0.5.</li>
<li><strong>nmsRadius</strong>: Necesita ser estrictamente positivo. Dos partes se suprimen entre sí si están a menos de nmsRadius píxeles de distancia. El valor predeterminado es 20.</li>
</ul>
<pre class=" language-js"><code class="prism language-js"><span class="token keyword">const</span> poses <span class="token operator">=</span> <span class="token keyword">await</span> net<span class="token punctuation">.</span><span class="token function">estimateMultiplePoses</span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> imageScaleFactor<span class="token punctuation">,</span> flipHorizontal<span class="token punctuation">,</span> outputStride<span class="token punctuation">,</span> maxPoseDetections<span class="token punctuation">,</span> scoreThreshold<span class="token punctuation">,</span> nmsRadius<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>El resultado se estructura de la siguiente manera:</p>
<pre class=" language-json"><code class="prism language-json"><span class="token punctuation">[</span>
<span class="token comment">// pose 1</span>
<span class="token punctuation">{</span>
<span class="token comment">// pose score</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.42985695206067</span><span class="token punctuation">,</span>
<span class="token string">"keypoints"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">126.09371757507</span><span class="token punctuation">,</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">97.861720561981</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"nose"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.99710708856583</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">132.53466176987</span><span class="token punctuation">,</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">86.429876804352</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"leftEye"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.99919074773788</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">100.85626316071</span><span class="token punctuation">,</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">84.421931743622</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"rightEye"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.99851280450821</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token operator">...</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">72.665352582932</span><span class="token punctuation">,</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">493.34189963341</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"rightAnkle"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.0028593824245036</span>
<span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// pose 2</span>
<span class="token punctuation">{</span>
<span class="token comment">// pose score</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.13461434583673</span><span class="token punctuation">,</span>
<span class="token string">"keypoints"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">116.58444058895</span><span class="token punctuation">,</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">99.772533416748</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"nose"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.0028593824245036</span>
<span class="token punctuation">}</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">133.49897611141</span><span class="token punctuation">,</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">79.644590377808</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"leftEye"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.99919074773788</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">100.85626316071</span><span class="token punctuation">,</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">84.421931743622</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"rightEye"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.99851280450821</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token operator">...</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">72.665352582932</span><span class="token punctuation">,</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">493.34189963341</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"rightAnkle"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.0028593824245036</span>
<span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token comment">// pose 3</span>
<span class="token punctuation">{</span>
<span class="token comment">// pose score</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.13461434583673</span><span class="token punctuation">,</span>
<span class="token string">"keypoints"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">116.58444058895</span><span class="token punctuation">,</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">99.772533416748</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"nose"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.0028593824245036</span>
<span class="token punctuation">}</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">133.49897611141</span><span class="token punctuation">,</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">79.644590377808</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"leftEye"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.99919074773788</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token operator">...</span>
<span class="token punctuation">{</span>
<span class="token string">"position"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"x"</span><span class="token punctuation">:</span> <span class="token number">59.334579706192</span><span class="token punctuation">,</span>
<span class="token string">"y"</span><span class="token punctuation">:</span> <span class="token number">485.5936152935</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"part"</span><span class="token punctuation">:</span> <span class="token string">"rightAnkle"</span><span class="token punctuation">,</span>
<span class="token string">"score"</span><span class="token punctuation">:</span> <span class="token number">0.004110524430871</span>
<span class="token punctuation">}</span>
<span class="token punctuation">]</span>
<span class="token punctuation">}</span>
<span class="token punctuation">]</span>
</code></pre>
<h3 id="estimar-pose-node--posenet">Estimar pose Node + PoseNet</h3>
<p>Vamos a crear un pequeño ejemplo en donde detectaremos la pose de un cuerpo presente en un imagen, para ello usaremos Node aunque también se puede hacer con JS desde el navegador, primero le dejo el <code>package.json</code> para nuestro proyecto de ejemplo:</p>
<pre class=" language-json"><code class="prism language-json"><span class="token punctuation">{</span>
<span class="token string">"name"</span><span class="token punctuation">:</span> <span class="token string">"posenet"</span><span class="token punctuation">,</span>
<span class="token string">"version"</span><span class="token punctuation">:</span> <span class="token string">"1.0.0"</span><span class="token punctuation">,</span>
<span class="token string">"description"</span><span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
<span class="token string">"main"</span><span class="token punctuation">:</span> <span class="token string">"index.js"</span><span class="token punctuation">,</span>
<span class="token string">"scripts"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"test"</span><span class="token punctuation">:</span> <span class="token string">"echo \"Error: no test specified\" && exit 1"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"author"</span><span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
<span class="token string">"license"</span><span class="token punctuation">:</span> <span class="token string">"ISC"</span><span class="token punctuation">,</span>
<span class="token string">"dependencies"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"@tensorflow-models/posenet"</span><span class="token punctuation">:</span> <span class="token string">"^1.0.0"</span><span class="token punctuation">,</span>
<span class="token string">"@tensorflow/tfjs"</span><span class="token punctuation">:</span> <span class="token string">"^1.0.1"</span><span class="token punctuation">,</span>
<span class="token string">"canvas"</span><span class="token punctuation">:</span> <span class="token string">"^2.3.1"</span><span class="token punctuation">,</span>
<span class="token string">"xhr2"</span><span class="token punctuation">:</span> <span class="token string">"^0.1.4"</span><span class="token punctuation">,</span>
<span class="token string">"xmlhttprequest"</span><span class="token punctuation">:</span> <span class="token string">"^1.8.0"</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Seguido el código de ejemplo, el mismo usa canvas para leer una imagen y enviarla a la red neuronal, una vez obtengamos las posiciones marcamos los puntos y los conectamos con lineas para visualizarlos mejor.</p>
<pre class=" language-js"><code class="prism language-js">global<span class="token punctuation">.</span>XMLHttpRequest <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"xhr2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> posenet <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'@tensorflow-models/posenet'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> Image <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'canvas'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> createCanvas <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'canvas'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> loadImage <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'canvas'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> imageScaleFactor <span class="token operator">=</span> <span class="token number">1.0</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> outputStride <span class="token operator">=</span> <span class="token number">16</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> flipHorizontal <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token keyword">function</span> <span class="token function">predictPose</span><span class="token punctuation">(</span>img<span class="token punctuation">,</span> mul<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> canvas <span class="token operator">=</span> <span class="token function">createCanvas</span><span class="token punctuation">(</span><span class="token number">512</span><span class="token punctuation">,</span> <span class="token number">512</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> ctx <span class="token operator">=</span> canvas<span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token string">'2d'</span><span class="token punctuation">)</span>
ctx<span class="token punctuation">.</span><span class="token function">drawImage</span><span class="token punctuation">(</span>img<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> canvas<span class="token punctuation">.</span>width<span class="token punctuation">,</span> canvas<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span>
posenet<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span>mul<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>net <span class="token operator">=></span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Net loaded!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
net<span class="token punctuation">.</span><span class="token function">estimateSinglePose</span><span class="token punctuation">(</span>canvas<span class="token punctuation">,</span> imageScaleFactor<span class="token punctuation">,</span> flipHorizontal<span class="token punctuation">,</span> outputStride<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>pose <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> pose<span class="token punctuation">.</span>keypoints<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">var</span> kp <span class="token operator">=</span> pose<span class="token punctuation">.</span>keypoints<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> pos <span class="token operator">=</span> kp<span class="token punctuation">.</span>position<span class="token punctuation">;</span>
ctx<span class="token punctuation">.</span>fillStyle <span class="token operator">=</span> <span class="token string">"#00FF00"</span><span class="token punctuation">;</span>
ctx<span class="token punctuation">.</span><span class="token function">beginPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
ctx<span class="token punctuation">.</span><span class="token function">arc</span><span class="token punctuation">(</span>pos<span class="token punctuation">.</span>x<span class="token punctuation">,</span> pos<span class="token punctuation">.</span>y<span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">2</span> <span class="token operator">*</span> Math<span class="token punctuation">.</span>PI<span class="token punctuation">)</span><span class="token punctuation">;</span>
ctx<span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//ctx.fillText(kp.part, pos.x, pos.y);</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'> Pos (X, Y): '</span> <span class="token operator">+</span> pos<span class="token punctuation">.</span>x <span class="token operator">+</span> <span class="token string">', '</span> <span class="token operator">+</span> pos<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'> Score: '</span> <span class="token operator">+</span> kp<span class="token punctuation">.</span>score <span class="token operator">+</span> <span class="token string">', Part: '</span> <span class="token operator">+</span> kp<span class="token punctuation">.</span>part <span class="token operator">+</span> <span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
ctx<span class="token punctuation">.</span>strokeStyle <span class="token operator">=</span> <span class="token string">"#00FF00"</span><span class="token punctuation">;</span>
<span class="token function">drawLine</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> pose<span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">drawLine</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> pose<span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">drawLine</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> pose<span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">drawLine</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> pose<span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">drawLine</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> pose<span class="token punctuation">,</span> <span class="token number">11</span><span class="token punctuation">,</span> <span class="token number">13</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">drawLine</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> pose<span class="token punctuation">,</span> <span class="token number">13</span><span class="token punctuation">,</span> <span class="token number">15</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">drawLine</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> pose<span class="token punctuation">,</span> <span class="token number">12</span><span class="token punctuation">,</span> <span class="token number">14</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">drawLine</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> pose<span class="token punctuation">,</span> <span class="token number">14</span><span class="token punctuation">,</span> <span class="token number">16</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span><span class="token string">'./images/pose_2.jpg'</span><span class="token punctuation">,</span> canvas<span class="token punctuation">.</span><span class="token function">toBuffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">drawLine</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> pose<span class="token punctuation">,</span> p1<span class="token punctuation">,</span> p2<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">var</span> pt1 <span class="token operator">=</span> pose<span class="token punctuation">.</span>keypoints<span class="token punctuation">[</span>p1<span class="token punctuation">]</span><span class="token punctuation">.</span>position<span class="token punctuation">;</span>
<span class="token keyword">var</span> pt2 <span class="token operator">=</span> pose<span class="token punctuation">.</span>keypoints<span class="token punctuation">[</span>p2<span class="token punctuation">]</span><span class="token punctuation">.</span>position<span class="token punctuation">;</span>
ctx<span class="token punctuation">.</span><span class="token function">beginPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
ctx<span class="token punctuation">.</span><span class="token function">moveTo</span><span class="token punctuation">(</span>pt1<span class="token punctuation">.</span>x<span class="token punctuation">,</span> pt1<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">;</span>
ctx<span class="token punctuation">.</span><span class="token function">lineTo</span><span class="token punctuation">(</span>pt2<span class="token punctuation">.</span>x<span class="token punctuation">,</span> pt2<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">;</span>
ctx<span class="token punctuation">.</span><span class="token function">stroke</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">loadImage</span><span class="token punctuation">(</span><span class="token string">'./images/test_2.jpg'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>img <span class="token operator">=></span> <span class="token function">predictPose</span><span class="token punctuation">(</span>img<span class="token punctuation">,</span> <span class="token number">0.75</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre>
<p>Probando nuestro código obtenemos la siguiente salida:</p>
<p><img src="https://lh3.googleusercontent.com/cEsTfGLujhKLhheQ8N6WUisHaSfapEcAuNX02FNDw6p3ETwl3rJcV3HcLN0QtIkWt3Yr-jFWsmA" alt="PoseNet NodeJS"></p>
<p>Podemos aplicar lo mismo para trabajar sobre varios cuerpos solo debemos tener presente que el método <code>estimateMultiplePoses(...)</code> devolverá un conjunto de poses iguales al que tenemos en el ejemplo previo.</p>
<p>Descargar código: <a href="https://drive.google.com/open?id=1yq-RbzHF5MuFc_Q-HfJ4kfLQ8O537zjl">estimar_pose.zip</a></p>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2590617132675118769.post-51077303543436570642019-03-07T11:41:00.001-08:002019-03-16T07:41:34.921-07:00Desplegar imagen Docker en AWS<p>Veamos como desplegar una imagen Docker en AWS Beanstalk, para este ejemplo creamos una aplicación sencilla usando Node y el Framework ExpressJS, añadiremos su respectivo Dockerfile y finalmente, que es lo que realmente nos interesa aprenderemos a desplegar esta app en AWS.</p><a name='more'></a> <p>Primero programamos nuestra aplicación web de ejemplo, algo sencillo solo nuestra un mensaje al acceder a la web, para esto usamos ExpressJS de la siguiente manera:</p><pre class=" language-js"><code class="prism language-js"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'express'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> PORT <span class="token operator">=</span> <span class="token number">3000</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> HOST <span class="token operator">=</span> <span class="token string">'0.0.0.0'</span><span class="token punctuation">;</span>
app<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">'Hello Node & Docker'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span>PORT<span class="token punctuation">,</span> HOST<span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Server listen in port: '</span> <span class="token operator">+</span> PORT<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Este es el <code>package.json</code> que usamos para nuestro ejemplo:</p><pre class=" language-json"><code class="prism language-json"><span class="token punctuation">{</span>
<span class="token string">"name"</span><span class="token punctuation">:</span> <span class="token string">"docker_aws"</span><span class="token punctuation">,</span>
<span class="token string">"version"</span><span class="token punctuation">:</span> <span class="token string">"1.0.0"</span><span class="token punctuation">,</span>
<span class="token string">"description"</span><span class="token punctuation">:</span> <span class="token string">"Desplegar imagen docker en aws"</span><span class="token punctuation">,</span>
<span class="token string">"main"</span><span class="token punctuation">:</span> <span class="token string">"index.js"</span><span class="token punctuation">,</span>
<span class="token string">"scripts"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"start"</span><span class="token punctuation">:</span> <span class="token string">"node index.js"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token string">"author"</span><span class="token punctuation">:</span> <span class="token string">"Tutor de programacion"</span><span class="token punctuation">,</span>
<span class="token string">"license"</span><span class="token punctuation">:</span> <span class="token string">"ISC"</span><span class="token punctuation">,</span>
<span class="token string">"dependencies"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
<span class="token string">"express"</span><span class="token punctuation">:</span> <span class="token string">"^4.16.4"</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Lógicamente como el tutorial trata de como hacer el deploy de un proyecto Docker necesitamos crear nuestro <code>Dockerfile</code>, nada del otro mundo, queda de la siguiente manera:</p><pre class=" language-docker"><code class="prism language-docker"><span class="token keyword">FROM</span> node<span class="token punctuation">:</span>8<span class="token punctuation">-</span>alpine
<span class="token keyword">WORKDIR</span> /usr/src/app
<span class="token keyword">COPY</span> package*.json ./
<span class="token keyword">RUN</span> npm install
<span class="token keyword">COPY</span> . .
<span class="token keyword">EXPOSE</span> 3000
<span class="token keyword">CMD</span> <span class="token punctuation">[</span> <span class="token string">"npm"</span><span class="token punctuation">,</span> <span class="token string">"start"</span> <span class="token punctuation">]</span>
</code></pre><h3 id="desplegar-aplicación-docker-en-aws">Desplegar aplicación Docker en AWS</h3><p>Lo primero que vamos a hacer es dirigirnos a la consola AWS, en el botón de servicios vamos a buscar Beanstalk, hacemos clic sobre él.</p><p><img src="https://lh3.googleusercontent.com/npRV-cEb8WGzA58xi7eHJJq5whFOfPV6fbsGDHQ3yV36qEs-Ro61jJgumLNmZSjFYMAVB_ADjbo" alt="AWS Elastic Beanstalk"></p><p>Cuando estemos allí debemos crear nuestra aplicación, para ello usamos el botón crear aplicación.</p><p><img src="https://lh3.googleusercontent.com/9vO_YA3Qqwvn_h1EHdKo5qIxfjzAwogwRRbcn0jg5Mxbv1JrNU_7XqWF3W-sWAURLKVdSPBYtt0" alt="Crear app beanstalk"></p><p>Le damos un nombre y una descripción, presionamos crear.</p><p><img src="https://lh3.googleusercontent.com/G3r9eTySWo8RZ9bTNdlttRAQN_DnNA2fDvpl59y4hvpVwgTQDexPg5SWnekCrmmHpg-dpypfJiI" alt="Nueva app aws"></p><p>El paso siguiente es configurar el entorno, seleccionamos para que se un entorno web.</p><p><img src="https://lh3.googleusercontent.com/SvKbGIqUvYyA9MJJ5g5iLiGH5aD_JLm327NzhJpqAYDVY0fhpr3ryu94P9R1fSeeBZb-0tB0HW8" alt="Entorno web"></p><p>Ahora cambiamos la plataforma a Docker, seleccionamos la opción cargar su código y presionamos Crear un entorno.</p><p><img src="https://lh3.googleusercontent.com/YxjA8UtXHEw3PQP7GRRW14rVvWdnRIgwc9FFtFAqsrwgbh6PW8eI4zH1H28RTfYfOin6TZfxQ70" alt="Configurar para docker"></p><p>El esta ventana seleccionamos el código de nuestro proyecto, deberá estar comprimido en ZIP, es importante que lo guardemos de tal manera que del Dockerfile quede en la raíz del archivo comprimido, si por ejemplo, dentro del archivo comprimido crear una carpeta y dentro de esta colocar el proyecto AWS no podrá encontrar el Dockerfile y dará error, al final encontrarás el enlace para descargar nuestro ejemplo.</p><p><img src="https://lh3.googleusercontent.com/esvLT6QshSTtULg-7CllBgg1LDTT8JNKvZh6CX_obxFgtjOdzUFwpeQayo1i6VDfuWaxCdMQkjY" alt="Cargar código fuente"></p><p>Si todo está correcto veras lo siguiente, puedes acceder a la URL indicada y comprobar de que tu aplicación esta corriendo y se ejecuta de manera adecuada.</p><p><img src="https://lh3.googleusercontent.com/ZhQSuJVRNITxYgtlhvEwNsevAg63glSqgexoseBb-gQctmSRq55JGHwW1_43_bgk85oU29Ho17g" alt="AWS listo"></p><p>Descargar código: <a href="https://drive.google.com/open?id=1ZZ25XuUF7XUcfNYBlS3R78LKtCf8pOQY">Node_Docker.zip</a>.</p>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2590617132675118769.post-31061178481406542162019-03-06T11:30:00.001-08:002019-03-16T07:39:56.381-07:00Subir archivos a AWS-S3 desde Node<p>Veremos como podemos subir archivos al servicio de almacenamiento en la nube proporcionado por Amazon, el mismo es llamado S3, utilizaremos el lenguaje de programación Node para crear un pequeño ejemplo de como subir un archivo que se encuentre en el servidor.</p><a name='more'></a> <p>Antes que nada primero debemos crear el Bucket S3, esto no es nada mas que nuestro espacio de almacenamiento, para hacerlo vamos a la consola AWS y seleccionamos el servicio S3.</p><p><img src="https://lh3.googleusercontent.com/6sjt9tCkEDDUuqcX0UNgpi971LAoH2qVqKppCim-zE7FXSMlutftfdV65rgmiqsaQUptHVeIPGo" alt="Almacenamiento AWS S3" title="Amazon S3 tutorial"></p><p>Luego presionamos el botón <strong>Crear Bucket</strong>, le damos un nombre para nuestro ejemplo usaremos “tutor-programacion-bucket” y presionamos Crear.</p><p><img src="https://lh3.googleusercontent.com/TQjhpi30o-EEKjYZT9t874B2eDUqNnJk_DCUfNnGyffqIQaXnnxMOa6lTgtEpQhEkwHo0mKWeM0" alt="Crear Bucket AWS S3" title="Crear bucket S3"></p><p>Lo siguiente que necesitamos será crear un par de claves para poder conectarnos al servicio, para esto vamos a la consola, nombre de cuenta | Mis credenciales de seguridad.</p><p><img src="https://lh3.googleusercontent.com/Z-kz1umDqi_2GNUr3tC1N20Ewcf3kVhwqqOT3XqFhogFhWVd0e2oW7npDnn725ykdRhQQ-5dIDA" alt="Credenciales AWS"></p><p>Seleccionamos la opción crear una clave de acceso.</p><p><img src="https://lh3.googleusercontent.com/elzIrMrDhF1TNmV2cTtlYrAFW92_89_cKHXIb2QoG5-jqEvCtBys3m5Bcd4iQQtElxCyT8jrfcg" alt="AWS clave de acceso"></p><p>Con esto tenemos AWS preparado.</p><h3 id="crear-aplicacion-node-aws-s3">Crear aplicacion Node AWS S3</h3><p>Primero el paquete aws-sdk que nos permitirá conectarnos al servicio de almacenamiento en la nube de Amazon.</p><pre><code>npm install aws-sdk --save
</code></pre><p>Lo siguiente es configurar el entorno AWS para lo cual deberemos indicar las claves de acceso que hemos creado anteriormente, en <strong>accessKeyId</strong> establecemos el ID de la clave de acceso y en <strong>secretAccessKey</strong> la clave de acceso secreta.</p><pre class=" language-js"><code class="prism language-js"><span class="token keyword">const</span> AWS <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'aws-sdk'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//cconfigurar AWS con las claves de acceso</span>
AWS<span class="token punctuation">.</span>config<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
accessKeyId<span class="token punctuation">:</span> <span class="token string">"xxxxxxxxxxxxxxx"</span><span class="token punctuation">,</span>
secretAccessKey<span class="token punctuation">:</span> <span class="token string">"xxxxxxxxxxx"</span><span class="token punctuation">,</span>
region<span class="token punctuation">:</span> <span class="token string">'us-east-1'</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Lo que resta es subir el archivo, para nuestro caso usaremos un archivo de texto que se encuentra en la carpeta data, el método que usamos para esto es <code>upload(...)</code>.</p><pre class=" language-js"><code class="prism language-js"><span class="token comment">//configuring parameters</span>
<span class="token keyword">var</span> params <span class="token operator">=</span> <span class="token punctuation">{</span>
Bucket <span class="token punctuation">:</span> <span class="token string">'tutor-programacion-bucket'</span><span class="token punctuation">,</span>
Body <span class="token punctuation">:</span> fs<span class="token punctuation">.</span><span class="token function">createReadStream</span><span class="token punctuation">(</span>filePath<span class="token punctuation">)</span><span class="token punctuation">,</span>
Key <span class="token punctuation">:</span> <span class="token string">"folder/"</span> <span class="token operator">+</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"_"</span> <span class="token operator">+</span> path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>filePath<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
s3<span class="token punctuation">.</span><span class="token function">upload</span><span class="token punctuation">(</span>params<span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span>err<span class="token punctuation">,</span> data<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">//handle error</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Error"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//success</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>data<span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Uploaded in:"</span><span class="token punctuation">,</span> data<span class="token punctuation">.</span>Location<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Como podemos ver primero creamos una seria de parámetros, en <strong>Bucket</strong> indicas el nombre del espacio de almacenamiento en el cual deseas guardar el archivo, <strong>Body</strong> establece el contenido y <strong>Key</strong> indica la ruta con nombre único en donde guardamos el archivo.</p><p>Al ejecutar tendremos el siguiente resultado:</p><p><img src="https://lh3.googleusercontent.com/AClNOrjJaxJlrKCTmWoR5Z6gPkJQZb_1Waus3h3cBXa8DRot29X0ZFmUAe78V7zAXCB375etBAY" alt="Node subir archivo a S3"></p><p>Con esto tenemos el archivo en la nube, solo debemos tener presente que el acceso al archivo en privado, si deseamos que el archivo sea subido como público para que cualquier persona lo pueda ver o descargar debemos hacer el siguiente cambio.</p><p>Agregamos <code>ACL</code> a los parámetros con el valor <code>'public-read'</code> de la siguiente manera:</p><pre class=" language-js"><code class="prism language-js"><span class="token keyword">var</span> params <span class="token operator">=</span> <span class="token punctuation">{</span>
Bucket <span class="token punctuation">:</span> <span class="token string">'tutor-programacion-bucket'</span><span class="token punctuation">,</span>
Body <span class="token punctuation">:</span> fs<span class="token punctuation">.</span><span class="token function">createReadStream</span><span class="token punctuation">(</span>filePath<span class="token punctuation">)</span><span class="token punctuation">,</span>
Key <span class="token punctuation">:</span> <span class="token string">"folder/"</span> <span class="token operator">+</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"_"</span> <span class="token operator">+</span> path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>filePath<span class="token punctuation">)</span><span class="token punctuation">,</span>
ACL <span class="token punctuation">:</span> <span class="token string">'public-read'</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><p>Antes de ejecutar debemos también cambiar la configuración del AWS S3 para permitir este comportamiento, para ello hacemos lo siguiente:</p><p><img src="https://lh3.googleusercontent.com/40rQAFosFp2oD6RJc0kPOQfk1coZFQvkN0tYl4DOr8POXk-j2erAw8hna989dL9wMHEgjtIua2c" alt="AWS configurar acceso público"></p><p>Vamos a la consola AWS S3, seleccionamos el bucket, damos clic en permisos luego en el cuadro inferior presionamos editar y desactivamos las opciones que podemos ver en la imagen superior.</p><p>Descargar código: <a href="https://drive.google.com/open?id=1SmnKAqiFtrMkQCXRn7Ss3CyoTnc4j1TA">Node_S3.zip</a></p>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2590617132675118769.post-91324796688732758742019-03-03T13:07:00.001-08:002019-03-16T07:38:39.500-07:00Cargar modelos Tensorflow en OpenCV DNN<p>DNN es un módulo desarrollado para trabajar con redes neuronales profundas, anteriormente este debía se instalado desde <em>opencv_contrib</em> pero a partir de la versión 3.3 ya forma parte oficial de OpenCV por lo que no se requieren dependencias externas.</p><a name='more'></a> <p>Podremos cargar y utilizar modelos pre-entrenados provenientes de los frameworks mas conocidos como:</p><ul><li><a href="http://caffe.berkeleyvision.org/">Caffe</a></li>
<li><a href="https://www.tensorflow.org/">TensorFlow</a></li>
<li><a href="http://torch.ch/">Torch</a></li>
<li><a href="https://pjreddie.com/darknet/">Darknet</a></li>
</ul><h3 id="detección-de-objetos-opencv---tensorflow">Detección de objetos OpenCV - Tensorflow</h3><p>Para nuestro ejemplo vamos a realizar detección de objetos, para ello utilizaremos un modelo pre-entrenado con Tensorflow usando el dataset COCO, lo primero que debemos saber es que requerimos tener dos archivos, primero el modelo “<em>.pb</em>”, lógicamente, y segundo el archivo de configuración del mismo “<em>.pbtxt</em>”, los enlaces a ambos archivos estarán incluidos en el al final de la publicación junto con el código fuente C++ del ejemplo.</p><pre class=" language-cpp"><code class="prism language-cpp"><span class="token keyword">auto</span> net <span class="token operator">=</span> dnn<span class="token operator">::</span><span class="token function">readNet</span><span class="token punctuation">(</span><span class="token string">"../data/frozen_inference_graph.pb"</span><span class="token punctuation">,</span> <span class="token string">"../data/ssd_mobilenet_v2_coco_2018_03_29.pbtxt"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Lo primero, usar la función <code>dnn::readNet(...)</code> para cargar el modelo, esto nos devuelve un objeto <code>cv::dnn::Net</code> que representa una red neuronal artificial.</p><pre class=" language-cpp"><code class="prism language-cpp"><span class="token keyword">auto</span> blob <span class="token operator">=</span> dnn<span class="token operator">::</span><span class="token function">blobFromImage</span><span class="token punctuation">(</span>src<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">Size</span><span class="token punctuation">(</span><span class="token number">300</span><span class="token punctuation">,</span> <span class="token number">300</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
net<span class="token punctuation">.</span><span class="token function">setInput</span><span class="token punctuation">(</span>blob<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Lo siguiente será procesar la imagen que deseamos analizar para convertirla en una entrada válida para la red, este propósito lo cumple la función <code>dnn::blobFromImage(...)</code>, para nuestro caso le pasaremos tres parámetros: imagen, factor de escala y tamaño, este último será 300x300 ya que es lo que nos exige el modelo que estamos utilizando.</p><pre class=" language-cpp"><code class="prism language-cpp">std<span class="token operator">::</span>vector<span class="token operator"><</span>Mat<span class="token operator">></span> outs<span class="token punctuation">;</span>
net<span class="token punctuation">.</span><span class="token function">forward</span><span class="token punctuation">(</span>outs<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p>Ya para finalizar usaremos el método <code>forward(...)</code> de la clase <strong>Net</strong> para realizar la predicción, es decir, iniciamos la red neuronal y obtenemos nuestro resultado.</p><p>Lo que resta ahora es interpretar los datos que nos ha devuelto la red, esto será un blob que tendrá la forma 1x1xNx7 en donde N es el numero de detecciones, por cada detección tendremos las siguiente información: <em>[batchId, classId, confidence, left, top, right, bottom]</em></p><p>Veamos en código para dibujar un rectángulo sobre el objeto detectado, le añadiremos el <em>classId</em> y <em>confidence</em>.</p><pre class=" language-cpp"><code class="prism language-cpp"><span class="token keyword">float</span> confThreshold <span class="token operator">=</span> <span class="token number">0.50</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t k <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> k <span class="token operator"><</span> outs<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> k<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">float</span><span class="token operator">*</span> data <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token operator">*</span><span class="token punctuation">)</span>outs<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">.</span>data<span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>size_t i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> outs<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">total</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i <span class="token operator">+</span><span class="token operator">=</span> <span class="token number">7</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">float</span> confidence <span class="token operator">=</span> data<span class="token punctuation">[</span>i <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>confidence <span class="token operator">></span> confThreshold<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> left <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>data<span class="token punctuation">[</span>i <span class="token operator">+</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> top <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>data<span class="token punctuation">[</span>i <span class="token operator">+</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> right <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>data<span class="token punctuation">[</span>i <span class="token operator">+</span> <span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> bottom <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>data<span class="token punctuation">[</span>i <span class="token operator">+</span> <span class="token number">6</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> width <span class="token operator">=</span> right <span class="token operator">-</span> left <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> height <span class="token operator">=</span> bottom <span class="token operator">-</span> top <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>width <span class="token operator">*</span> height <span class="token operator"><=</span> <span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
left <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">(</span>data<span class="token punctuation">[</span>i <span class="token operator">+</span> <span class="token number">3</span><span class="token punctuation">]</span> <span class="token operator">*</span> image<span class="token punctuation">.</span>cols<span class="token punctuation">)</span><span class="token punctuation">;</span>
top <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">(</span>data<span class="token punctuation">[</span>i <span class="token operator">+</span> <span class="token number">4</span><span class="token punctuation">]</span> <span class="token operator">*</span> image<span class="token punctuation">.</span>rows<span class="token punctuation">)</span><span class="token punctuation">;</span>
right <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">(</span>data<span class="token punctuation">[</span>i <span class="token operator">+</span> <span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">*</span> image<span class="token punctuation">.</span>cols<span class="token punctuation">)</span><span class="token punctuation">;</span>
bottom <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">(</span>data<span class="token punctuation">[</span>i <span class="token operator">+</span> <span class="token number">6</span><span class="token punctuation">]</span> <span class="token operator">*</span> image<span class="token punctuation">.</span>rows<span class="token punctuation">)</span><span class="token punctuation">;</span>
width <span class="token operator">=</span> right <span class="token operator">-</span> left <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
height <span class="token operator">=</span> bottom <span class="token operator">-</span> top <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> idx <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">(</span>data<span class="token punctuation">[</span>i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token function">rectangle</span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> <span class="token function">Rect</span><span class="token punctuation">(</span>left<span class="token punctuation">,</span> top<span class="token punctuation">,</span> width<span class="token punctuation">,</span> height<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">putText</span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> <span class="token function">String</span><span class="token punctuation">(</span>class_names<span class="token punctuation">[</span>idx<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">Point</span><span class="token punctuation">(</span>left<span class="token punctuation">,</span> top<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2.0</span><span class="token punctuation">,</span> <span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">128</span><span class="token punctuation">,</span> <span class="token number">128</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">putText</span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> <span class="token function">String</span><span class="token punctuation">(</span><span class="token function">to_string</span><span class="token punctuation">(</span>confidence<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">Point</span><span class="token punctuation">(</span>left<span class="token punctuation">,</span> bottom<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2.0</span><span class="token punctuation">,</span> <span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">128</span><span class="token punctuation">,</span> <span class="token number">128</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>Ejecutando este código tendremos el siguiente resultado:<br />
<img src="https://lh3.googleusercontent.com/9GH_QCHyrWitw2hqV4bdjvlfnUiWCPlb-P7IkCOvIw5d91xiZUla1DnIaA3BAAb2sAE0swRu3BA" alt="OpenCV Tensorflow Deteccion de objetos"></p><p>En el siguiente enlace puedes descargar el modelo Tensorflow pre-entrenado: <a href="http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v2_coco_2018_03_29.tar.gz">frozen_inference_graph.pb</a> y el archivo de configuración aquí: <a href="https://github.com/opencv/opencv_extra/blob/master/testdata/dnn/ssd_mobilenet_v2_coco_2018_03_29.pbtxt">ssd_mobilenet_v2_coco_2018_03_29.pbtxt</a> debes copiarlo en la carpeta data o modificar el código para apuntar a este archivo.</p><ul><li>Descargar código: <a href="https://drive.google.com/file/d/1podoIQjUpO8CGQVgk_qwQ8AmNOAoEXe-/view?usp=sharing">OpenCV-Tensorflow.zip</a>.</li>
</ul>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2590617132675118769.post-65296500084692510822018-06-23T12:36:00.001-07:002018-06-23T12:54:59.962-07:00Detección de objetos planos<p>Seguimos aplicando los conocimientos adquiridos en <a href="http://acodigo.blogspot.com/2018/05/extraccion-de-puntos-caracteristicos.html" target="_blank">tutoriales anteriores</a>, esta vez aprenderemos a detectar un objeto plano conocido que se encuentre dentro de una imagen, para hacer esto requerimos extraer los puntos característicos de la imagen de referencia (el objeto que deseamos localizar) para luego ubicar estos puntos en la imagen de destino, luego usando homografía podemos obtener la posición de dicho objeto.</p><a name='more'></a> <p><a href="https://lh3.googleusercontent.com/-T93N15wPl-U/Wy6hJzcms5I/AAAAAAAAD_E/YSOz7z9dBZsW__OPMVp0eOYFj8BlJhNsACHMYCw/s1600-h/image332"><img title="Detección de objeto plano" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Detección de objeto plano" src="https://lh3.googleusercontent.com/-JWBMN-cRukg/Wy6hLAbXeuI/AAAAAAAAD_I/kud2WQTcDjkRAqj4hIJ8YiPKwa8_gCfOACHMYCw/image3_thumb31?imgmax=800" width="520" height="390" /></a></p><p>Lo primero que requerimos luego de crear nuestro proyecto es encontrar los <strong>key point</strong> de nuestra imagen de referencia como lo hicimos el los <a href="http://acodigo.blogspot.com/2018/05/extraccion-de-puntos-caracteristicos.html" target="_blank">tutoriales previos</a>, por supuesto también requerimos los de nuestra imagen en donde deseamos detectar nuestro objeto.</p><div class="code-painter"><pre><code>Ptr<span style="color: rgb(102, 102, 102);"><</span>Feature2D<span style="color: rgb(102, 102, 102);">></span> detector <span style="color: rgb(102, 102, 102);">=</span> BRISK<span style="color: rgb(102, 102, 102);">::</span>create();
Ptr<span style="color: rgb(102, 102, 102);"><</span>DescriptorMatcher<span style="color: rgb(102, 102, 102);">></span> matcher <span style="color: rgb(102, 102, 102);">=</span> BFMatcher<span style="color: rgb(102, 102, 102);">::</span>create(NORM_HAMMING, <span style="color: rgb(0, 128, 0);">true</span>);
<span style="color: rgb(64, 128, 128); font-style: italic;">// cargar la imagen de referencia, aquel objeto plano que deseamos localizar.</span>
Mat img_object <span style="color: rgb(102, 102, 102);">=</span> imread(<span style="color: rgb(186, 33, 33);">"image/img.jpg"</span>, IMREAD_GRAYSCALE);
Mat desc_object;
<span style="color: rgb(64, 128, 128); font-style: italic;">// cargar la imagen de la escena en donde buscaremos el objeto plano.</span>
Mat img_scene <span style="color: rgb(102, 102, 102);">=</span> imread(<span style="color: rgb(186, 33, 33);">"image/scene.jpg"</span>, IMREAD_GRAYSCALE);
Mat desc_scene;
<span style="color: rgb(64, 128, 128); font-style: italic;">// detectar y extraer los puntos de interes y sus respectivos descriptores.</span>
vector<span style="color: rgb(102, 102, 102);"><</span>KeyPoint<span style="color: rgb(102, 102, 102);">></span> kp_object;
detector<span style="color: rgb(102, 102, 102);">-></span>detectAndCompute(img_object, noArray(), kp_object, desc_object);
<span style="color: rgb(64, 128, 128); font-style: italic;">// detectar y extraer los puntos de interes y sus respectivos descriptores.</span>
vector<span style="color: rgb(102, 102, 102);"><</span>KeyPoint<span style="color: rgb(102, 102, 102);">></span> kp_scene;
detector<span style="color: rgb(102, 102, 102);">-></span>detectAndCompute(img_scene, noArray(), kp_scene, desc_scene);
</code></pre></div><p>Todo lo referente a este código lo estudiamos en el tutorial: <a href="http://acodigo.blogspot.com/2018/05/extraccion-de-puntos-caracteristicos.html" target="_blank">Detección y extracción de puntos clave</a>, lo siguiente que requerimos realizar es el pareo de puntos, es decir, intentar ubicar los puntos de la imagen A en la imagen B, este tema también lo hemos visto anteriormente, el código es el siguiente:</p><div class="code-painter"> <pre><code><span style="color: rgb(64, 128, 128); font-style: italic;">// hacer el pareo de los key points.</span>
vector<span style="color: rgb(102, 102, 102);"><</span>DMatch<span style="color: rgb(102, 102, 102);">></span> matches;
matcher<span style="color: rgb(102, 102, 102);">-></span>match(desc_object, desc_scene, matches);
<span style="color: rgb(64, 128, 128); font-style: italic;">// filtrar los mejores key points.</span>
sort(matches.begin(), matches.end());
matches.erase(matches.begin() <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">30</span>, matches.end());
</code></pre></div><p>Recordemos que podemos usar la función <code>cv::drawMatches(...)</code> para mostrar el pareo de puntos. </p><p><a href="https://lh3.googleusercontent.com/-jeH7BB6p_j8/Wy6hM33MwCI/AAAAAAAAD_M/T-rJ_jneBY0JNcXgeSBUcVE7fS8IWfHywCHMYCw/s1600-h/image610"><img title="Detectar y describir los puntos clave" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Detectar y describir los puntos clave" src="https://lh3.googleusercontent.com/-bG8DWcQGNiE/Wy6hOjLsiXI/AAAAAAAAD_Q/H84YiUrKJl4xSExtdxz165RxiF2O9pRhACHMYCw/image6_thumb9?imgmax=800" width="770" height="393" /></a></p><p>Antes de proceder con el siguiente paso será necesario obtener las coordenadas (x, y) de cada uno de los puntos, para ello recorremos el objeto <b>matches</b> el cual es una lista de objetos <code>DMatch</code> para cada uno de ellos podemos consultar el campo <b>queryIdx</b> y <b>trainIdx</b> para obtener el índice que corresponde al <code>KeyPoint</code> de la imagen de referencia y la imagen de escena respectivamente, luego obtenemos en campo <b>pt</b> que guarda la información que necesitamos.</p><div class="code-painter"> <pre><code>vector<span style="color: rgb(102, 102, 102);"><</span>Point2f<span style="color: rgb(102, 102, 102);">></span> pts_object, pts_scene;
vector<span style="color: rgb(102, 102, 102);"><</span>DMatch<span style="color: rgb(102, 102, 102);">></span> good_match;
<span style="color: rgb(64, 128, 128); font-style: italic;">// guardar los puntos correspondientes a cada uno de los key points.</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">for</span> (<span style="color: rgb(0, 128, 0); font-weight: bold;">auto</span><span style="color: rgb(102, 102, 102);">&</span> <span style="color: rgb(160, 160, 0);">m</span> : matches)
{
pts_object.push_back(kp_object[m.queryIdx].pt);
pts_scene.push_back(kp_scene[m.trainIdx].pt);
good_match.push_back(m);
}
</code></pre></div><p>Ahora podemos calcular la matriz de homografía usando los puntos previamente obtenidos, para esta tarea usamos la función OpenCV llamada <code>cv::findHomography(...)</code>, los primeros dos parámetros corresponden a los puntos de obtenidos en el paso anterior y el último indica el método a utilizar.</p><p>Con la matriz de homografía H podemos usar <code>cv::perspectiveTransform(...)</code> para transformar las coordenadas del la imagen de referencia, para nuestro caso estas coordenadas corresponden a cada una de las esquinas de la imagen, las almacenamos en el objeto <em>obj_corners</em>, las coordenadas transformadas se guardan en <em>scene_corners</em>. </p><div class="code-painter"> <pre><code><span style="color: rgb(64, 128, 128); font-style: italic;">// buscar la matriz de homografia que representa la tranformación entre los puntos del objeto y la escena.</span>
Mat H <span style="color: rgb(102, 102, 102);">=</span> findHomography(pts_object, pts_scene, CV_RANSAC);
<span style="color: rgb(0, 128, 0); font-weight: bold;">if</span> (<span style="color: rgb(102, 102, 102);">!</span>H.empty()) {
<span style="color: rgb(64, 128, 128); font-style: italic;">// obtener las coordenadas de la imagen de referencia, corresponde a las 4 esquinas de la imagen.</span>
std<span style="color: rgb(102, 102, 102);">::</span>vector<span style="color: rgb(102, 102, 102);"><</span>Point2f<span style="color: rgb(102, 102, 102);">></span> obj_corners(<span style="color: rgb(102, 102, 102);">4</span>);
obj_corners[<span style="color: rgb(102, 102, 102);">0</span>] <span style="color: rgb(102, 102, 102);">=</span> Point2f(<span style="color: rgb(102, 102, 102);">0</span>, <span style="color: rgb(102, 102, 102);">0</span>);
obj_corners[<span style="color: rgb(102, 102, 102);">1</span>] <span style="color: rgb(102, 102, 102);">=</span> Point2f((<span style="color: rgb(176, 0, 64);">float</span>)img_object.cols, <span style="color: rgb(102, 102, 102);">0</span>);
obj_corners[<span style="color: rgb(102, 102, 102);">2</span>] <span style="color: rgb(102, 102, 102);">=</span> Point2f((<span style="color: rgb(176, 0, 64);">float</span>)img_object.cols, (<span style="color: rgb(176, 0, 64);">float</span>)img_object.rows);
obj_corners[<span style="color: rgb(102, 102, 102);">3</span>] <span style="color: rgb(102, 102, 102);">=</span> Point2f(<span style="color: rgb(102, 102, 102);">0</span>, (<span style="color: rgb(176, 0, 64);">float</span>)img_object.rows);
<span style="color: rgb(64, 128, 128); font-style: italic;">// aplicar la tranformación a las corredenadas previas para obtener la posición de cada punto en la escena.</span>
std<span style="color: rgb(102, 102, 102);">::</span>vector<span style="color: rgb(102, 102, 102);"><</span>Point2f<span style="color: rgb(102, 102, 102);">></span> scene_corners(<span style="color: rgb(102, 102, 102);">4</span>);
perspectiveTransform(obj_corners, scene_corners, H);
Mat img_scene_dst;
cvtColor(img_scene, img_scene_dst, CV_GRAY2BGR);
<span style="color: rgb(64, 128, 128); font-style: italic;">// Dibujamos las coordenadas del objeto plano en la escena.</span>
line(img_scene_dst, scene_corners[<span style="color: rgb(102, 102, 102);">0</span>], scene_corners[<span style="color: rgb(102, 102, 102);">1</span>], Scalar(<span style="color: rgb(102, 102, 102);">0</span>, <span style="color: rgb(102, 102, 102);">255</span>, <span style="color: rgb(102, 102, 102);">0</span>), <span style="color: rgb(102, 102, 102);">3</span>, LINE_AA);
line(img_scene_dst, scene_corners[<span style="color: rgb(102, 102, 102);">1</span>], scene_corners[<span style="color: rgb(102, 102, 102);">2</span>], Scalar(<span style="color: rgb(102, 102, 102);">0</span>, <span style="color: rgb(102, 102, 102);">255</span>, <span style="color: rgb(102, 102, 102);">0</span>), <span style="color: rgb(102, 102, 102);">3</span>, LINE_AA);
line(img_scene_dst, scene_corners[<span style="color: rgb(102, 102, 102);">2</span>], scene_corners[<span style="color: rgb(102, 102, 102);">3</span>], Scalar(<span style="color: rgb(102, 102, 102);">0</span>, <span style="color: rgb(102, 102, 102);">255</span>, <span style="color: rgb(102, 102, 102);">0</span>), <span style="color: rgb(102, 102, 102);">3</span>, LINE_AA);
line(img_scene_dst, scene_corners[<span style="color: rgb(102, 102, 102);">3</span>], scene_corners[<span style="color: rgb(102, 102, 102);">0</span>], Scalar(<span style="color: rgb(102, 102, 102);">0</span>, <span style="color: rgb(102, 102, 102);">255</span>, <span style="color: rgb(102, 102, 102);">0</span>), <span style="color: rgb(102, 102, 102);">3</span>, LINE_AA);
imshow(<span style="color: rgb(186, 33, 33);">"Detected Object"</span>, img_scene_dst);
}
</code></pre></div><p>Con esto ya tenemos las coordenadas de nuestro objeto buscado, solo resta dibujarlas sobre la imagen para que podamos visualizarlas en nuestra aplicación, para ello las dibujamos con la función <code>cv::line(...)</code>, si deseas mas información puedes ver: <a href="http://acodigo.blogspot.com/2017/06/funciones-de-dibujo-opencv-python.html" target="_blank">Funciones de dibujo OpenCV</a>, las líneas que vamos a dibujar son para unir y marcar las 4 esquinas del objeto.</p><p>Hecho esto el resultado sería el siguiente:</p><p><a href="https://lh3.googleusercontent.com/-GlKxfvs8yIw/Wy6hQ_R0m7I/AAAAAAAAD_U/-XJzi7H_XZ0G_Lgo-273owgOs7EtuVyeACHMYCw/s1600-h/image7"><img title="Identificar un objeto plano con OpenCV" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Identificar un objeto plano con OpenCV" src="https://lh3.googleusercontent.com/-6uEPyFNQaMM/Wy6hSp6OpgI/AAAAAAAAD_Y/l-LjvUhXHR05VNY3JE-p5FC7lgYb4z4QgCHMYCw/image_thumb7?imgmax=800" width="770" height="393" /></a></p><p>Podemos utilizar esta técnica cuando deseemos ubicar objetos planos como: libros, tarjetas, señales de transito, entre otros, aunque de momento trabajamos con una imagen estática esto puede fácilmente ser aplicado a un video en tiempo real para, por ejemplo, estimar la posición del libro y dibujar una figura 3D sobre él, de este modo podríamos crear aplicaciones de realidad aumentada.</p><ul><li>Descargar código fuente: <a href="https://github.com/TutorProgramacion/tutoriales-programacion/raw/master/opencv/cpp/2018/opencv-planar_tracking.zip" target="_blank">opencv-planar-detector.zip</a> </li>
<li>Ver en GitHub: <a href="https://github.com/TutorProgramacion/tutoriales-opencv/tree/master/opencv-planar_tracking" target="_blank">OpenCV Detectar Objeto Plano</a></li>
</ul>Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-2590617132675118769.post-58005590020234524842018-05-11T13:48:00.001-07:002018-05-11T13:52:28.232-07:00Combinar imágenes con OpenCV<p>Dedicaremos este tutorial a tratar de aplicar los conocimientos adquiridos en la publicación anterior, <a href="http://acodigo.blogspot.com/2018/05/extraccion-de-puntos-caracteristicos.html" target="_blank">detección y descripción de puntos característicos</a>, lo que intentaremos hacer es combinar dos imágenes que tengan una porción en común, para ello localizaremos los <strong>keypoints</strong> de ambas y haremos el pareo para luego transformar la segunda imagen de modo que se combine con la primera haciendo coincidir los <strong>keypoints</strong>.</p><a name='more'></a> <p><a href="https://lh3.googleusercontent.com/-VIaKkeJ76yU/WvX_qy7o7cI/AAAAAAAAD-I/imteX3stJGMAHPx743jjrqyB_lsjXtYKQCHMYCw/s1600-h/image%255B3%255D"><img title="Combinar Imágenes OpenCV" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Combinar Imágenes OpenCV" src="https://lh3.googleusercontent.com/-PyFqSBUZ-AQ/WvYAQFPCgOI/AAAAAAAAD-Q/DPUglzUTcrYBCL5vRWK3dFHDLkz_GdS4ACHMYCw/image_thumb%255B1%255D?imgmax=800" width="1026" height="719" /></a></p><p>La mayor parte del código requerido lo desarrollamos en el <a href="http://acodigo.blogspot.com/2018/05/extraccion-de-puntos-caracteristicos.html" target="_blank">tutorial anterior</a>, cargamos las dos imágenes luego usamos el detector <code>BRISK</code> para localizar y describir los puntos de cada imagen, luego utilizamos <code>BFMatch</code> para hacer el pareo de los puntos, recordar que también filtramos los puntos para trabajar solo con los de mayor fiabilidad.</p><p>Por ahora el código que tenemos es el siguiente:</p><div class="code-painter"><pre><code>Ptr<span style="color: rgb(102, 102, 102);"><</span>Feature2D<span style="color: rgb(102, 102, 102);">></span> detect <span style="color: rgb(102, 102, 102);">=</span> BRISK<span style="color: rgb(102, 102, 102);">::</span>create();
vector<span style="color: rgb(102, 102, 102);"><</span>KeyPoint<span style="color: rgb(102, 102, 102);">></span> kpA, kpB;
Mat descA, descB;
detect<span style="color: rgb(102, 102, 102);">-></span>detectAndCompute(imageA, noArray(), kpA, descA);
detect<span style="color: rgb(102, 102, 102);">-></span>detectAndCompute(imageB, noArray(), kpB, descB);
vector<span style="color: rgb(102, 102, 102);"><</span>DMatch<span style="color: rgb(102, 102, 102);">></span> matches;
Ptr<span style="color: rgb(102, 102, 102);"><</span>DescriptorMatcher<span style="color: rgb(102, 102, 102);">></span> matcher <span style="color: rgb(102, 102, 102);">=</span> BFMatcher<span style="color: rgb(102, 102, 102);">::</span>create(NORM_HAMMING, <span style="color: rgb(0, 128, 0);">true</span>);
matcher<span style="color: rgb(102, 102, 102);">-></span>match(descA, descB, matches);
sort(matches.begin(), matches.end());
matches.erase(matches.begin() <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">30</span>, matches.end());
</code></pre></div><p>Al ejecutar hasta aquí tenemos el siguiente resultado:</p><p><a href="https://lh3.googleusercontent.com/-U71BJe3Hf9s/WvYBVXv5oVI/AAAAAAAAD-c/-7K2pgWy1k0iwaF0syV7M6zzZTobyE6cQCHMYCw/s1600-h/image8"><img title="Detección y pareo de puntos de interés" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Detección y pareo de puntos de interés" src="https://lh3.googleusercontent.com/-eQTeaCqEpCU/WvYBbIGKaXI/AAAAAAAAD-g/cx0rfrf2a2ES-7aEWvjGC0TioP75sw06QCHMYCw/image_thumb2?imgmax=800" width="1561" height="502" /></a></p><p>El siguiente paso es obtener el listado de coordenadas de cada uno de los puntos de ambas imágenes, para ello vamos a recorrer la lista de pareo <code>vector<DMatch></code> cada <code>DMatch</code> guarda el índice del <code>Keypoint</code> de la primera imagen en <samp>queryIdx</samp> y <samp>trainIdx</samp> almacena el índice correspondiente a la segunda.</p><div class="code-painter"> <pre><code>vector<span style="color: rgb(102, 102, 102);"><</span>Point2f<span style="color: rgb(102, 102, 102);">></span> pts1, pts2;
<span style="color: rgb(0, 128, 0); font-weight: bold;">for</span> (<span style="color: rgb(0, 128, 0); font-weight: bold;">auto</span><span style="color: rgb(102, 102, 102);">&</span> <span style="color: rgb(160, 160, 0);">m</span> : matches) {
pts1.push_back(kpA[m.queryIdx].pt);
pts2.push_back(kpB[m.trainIdx].pt);
}
</code></pre></div><p>Teniendo esta información podemos calcular la homografía, esta es una matriz que nos permitirá transformar la imagen de tal modo que ambos puntos coincidan.  </p><div class="code-painter"> <pre><code>Mat h <span style="color: rgb(102, 102, 102);">=</span> findHomography(pts2, pts1, noArray(), CV_RANSAC);
</code></pre></div><p>Con esto solo nos resta aplicar la transformación que acabamos de calcular, primero usaremos la función <code>cv::warpPerspective(...)</code> para ubicar la segunda imagen en la posición que le corresponde, luego usamos el método <code>copyTo(...)</code> para ubicar la primera imagen ya que esta no requiere ningún tipo de ajuste, recordemos que es la segunda imagen quien se ajusta a la primera.</p><div class="code-painter"> <pre><code>vector<span style="color: rgb(102, 102, 102);"><</span>Point2f<span style="color: rgb(102, 102, 102);">></span> box;
box.push_back(Point2f(<span style="color: rgb(102, 102, 102);">0</span>, <span style="color: rgb(102, 102, 102);">0</span>));
box.push_back(Point2f(imageB.cols, <span style="color: rgb(102, 102, 102);">0</span>));
box.push_back(Point2f(imageB.cols, imageB.rows));
box.push_back(Point2f(<span style="color: rgb(102, 102, 102);">0</span>, imageB.rows));
vector<span style="color: rgb(102, 102, 102);"><</span>Point2f<span style="color: rgb(102, 102, 102);">></span> box_dst;
perspectiveTransform(box, box_dst, h);
Rect rc <span style="color: rgb(102, 102, 102);">=</span> boundingRect(box_dst);
Mat dst;
warpPerspective(imageB, dst, h, Size(rc.width <span style="color: rgb(102, 102, 102);">+</span> rc.x, rc.height <span style="color: rgb(102, 102, 102);">+</span> rc.y));
imageA.copyTo(dst(Rect(Point(<span style="color: rgb(102, 102, 102);">0</span>, <span style="color: rgb(102, 102, 102);">0</span>), imageA.size())));
</code></pre></div><p>Algo que debes tener presente es que el tamaño del <code>Mat dst</code> en donde se guarda el resultado debe ser suficiente para contener a ambas imágenes cuando las mismas se combinen, en nuestro caso usamos funciones <code>cv::perspectiveTransform(...)</code> y <code>cv::boundingRect(...)</code> para calcular este tamaño.</p><p>El resultado final debe ser algo como esto:</p><p><a href="https://lh3.googleusercontent.com/-UfbkpNYQjvY/WvYBfyovlCI/AAAAAAAAD-k/zdHn9yyjnj8uXEwdDjb8gZo6QPwtc8uFQCHMYCw/s1600-h/image5"><img title="Imagen panorámica con OpenCV" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Imagen panorámica con OpenCV" src="https://lh3.googleusercontent.com/-6wkrjw8Ph6c/WvYBqGtz-OI/AAAAAAAAD-s/wujc_pdTLzY9natAjbPnbpqM8Oj3M1XxwCHMYCw/image_thumb1?imgmax=800" width="1026" height="719" /></a></p><p>Es importante mencionar que OpenCV ya cuenta con un módulo desarrollado para este tipo de tareas, para un ejemplo de ello puedes ver: <a href="http://acodigo.blogspot.com/2017/02/opencv-stitching.html" target="_blank">creación de imágenes panorámicas</a>. </p><p>Descargar proyecto: <a href="https://github.com/TutorProgramacion/tutoriales-programacion/raw/master/opencv/cpp/2018/opencv-panorama.zip" target="_blank">combinar-imágenes.zip</a></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2590617132675118769.post-70007841069518524392018-05-09T14:03:00.001-07:002018-05-09T14:16:22.995-07:00Extracción de puntos característicos (keypoint)<p>Los puntos característicos de una imagen, también llamados <em>keypoints</em> en inglés, son aquellas puntos que son fácilmente diferenciables en una imagen, para extraer dichos puntos OpenCV cuenta con diversas clases que implementan los algoritmos más conocidos que han sido desarrollados para este propósito, los mismos se encentran en el módulo <strong>cv::features2d</strong> algunas de ellas son AKAZE, BRISK, ORB, etc., otros algoritmos que requieren licencia los puedes encontrar en el módulo <samp>opencv_contrib</samp>, más específicamente <strong>cv::xfeatures2d</strong> podemos usar SURF, FREAK, SIFT, entre otros.</p><a name='more'></a> <p><a href="https://lh3.googleusercontent.com/-eApDT34Akrs/WvNh0Y9KEAI/AAAAAAAAD9A/w9F8PD3uSqA3CiJl6kF-rgKgYN8cWcZLgCHMYCw/s1600-h/deteccin-de-puntos-de-inters3"><img title="detección de puntos de interés" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="detección de puntos de interés" src="https://lh3.googleusercontent.com/-ogysFOhVscs/WvNh29qr-TI/AAAAAAAAD9E/hE03TF4FjkshyBCj9OH7cyQ6nIUmHupcACHMYCw/deteccin-de-puntos-de-inters_thumb1?imgmax=800" width="1051" height="557" /></a></p><p>Para facilitar el uso de estos algoritmos se utiliza la clase abstracta <code>cv::Features2D</code> la cual sirve de base para todos los algoritmos antes mencionados. </p><p><a href="https://lh3.googleusercontent.com/-Whi2xv3ckrM/WvNh31--biI/AAAAAAAAD9I/3_P9W-gt9UoRW0ifRDwNlINUBo9TRywowCHMYCw/s1600-h/clase-Feature2D-OpenCV3"><img title="clase Feature2D OpenCV" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="clase Feature2D OpenCV" src="https://lh3.googleusercontent.com/-cyhuJFtDZns/WvNh49hMOvI/AAAAAAAAD9M/aU_F1hXA2hM1uWgUjjYgqjQGYk6hF9OggCHMYCw/clase-Feature2D-OpenCV_thumb1?imgmax=800" width="964" height="436" /></a></p><p>Vemos nuestro primer código de ejemplo:</p><div class="code-painter"><pre><code><span style="color: rgb(188, 122, 0);">#include</span> <span style="color: rgb(64, 128, 128); font-style: italic;"><iostream></span><span style="color: rgb(188, 122, 0);"></span>
<span style="color: rgb(188, 122, 0);">#include</span> <span style="color: rgb(64, 128, 128); font-style: italic;"><opencv2\opencv.hpp></span><span style="color: rgb(188, 122, 0);"></span>
<span style="color: rgb(188, 122, 0);">#include</span> <span style="color: rgb(64, 128, 128); font-style: italic;"><opencv2\features2d.hpp></span><span style="color: rgb(188, 122, 0);"></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">using</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">namespace</span> cv;
<span style="color: rgb(0, 128, 0); font-weight: bold;">using</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">namespace</span> std;
<span style="color: rgb(176, 0, 64);">int</span> <span style="color: rgb(0, 0, 255);">main</span>(<span style="color: rgb(176, 0, 64);">int</span> argc, <span style="color: rgb(176, 0, 64);">char</span><span style="color: rgb(102, 102, 102);">**</span> argv )
{
Mat image <span style="color: rgb(102, 102, 102);">=</span> imread(<span style="color: rgb(186, 33, 33);">"../opencv-keypoints/lena.jpg"</span>, IMREAD_GRAYSCALE);
<span style="color: rgb(0, 128, 0); font-weight: bold;">if</span> (image.empty())
{
printf(<span style="color: rgb(186, 33, 33);">"No image data."</span>);
getchar();
<span style="color: rgb(0, 128, 0); font-weight: bold;">return</span> <span style="color: rgb(102, 102, 102);">-1</span>;
}
Ptr<span style="color: rgb(102, 102, 102);"><</span>Feature2D<span style="color: rgb(102, 102, 102);">></span> detect <span style="color: rgb(102, 102, 102);">=</span> BRISK<span style="color: rgb(102, 102, 102);">::</span>create();
vector<span style="color: rgb(102, 102, 102);"><</span>KeyPoint<span style="color: rgb(102, 102, 102);">></span> kp;
detect<span style="color: rgb(102, 102, 102);">-></span>detect(image, kp);
Mat result;
drawKeypoints(image, kp, result, Scalar<span style="color: rgb(102, 102, 102);">::</span>all(<span style="color: rgb(102, 102, 102);">-1</span>), DrawMatchesFlags<span style="color: rgb(102, 102, 102);">::</span>DRAW_RICH_KEYPOINTS);
imshow(<span style="color: rgb(186, 33, 33);">"OpenCV :: "</span> <span style="color: rgb(102, 102, 102);">+</span> detect<span style="color: rgb(102, 102, 102);">-></span>getDefaultName(), result);
waitKey(<span style="color: rgb(102, 102, 102);">0</span>);
<span style="color: rgb(0, 128, 0); font-weight: bold;">return</span> <span style="color: rgb(102, 102, 102);">0</span>;
}
</code></pre></div><p>Obtenemos un puntero a un objeto de la clase BRISK la cual implemente el algoritmo del mismo nombre, lo hacemos a través del método:</p><div class="code-painter"> <pre><code>Ptr<span style="color: rgb(102, 102, 102);"><</span>Feature2D<span style="color: rgb(102, 102, 102);">></span> detect <span style="color: rgb(102, 102, 102);">=</span> BRISK<span style="color: rgb(102, 102, 102);">::</span>create();
</code></pre></div><p>Luego usamos el método <code>detect(...)</code> para obtener el listado de los <code>KeyPoint</code> de nuestra imagen de entrada, esta clase guarda toda la información correspondiente a nuestro punto característico, coordenadas del punto, ángulo, etc.</p><div class="code-painter"> <pre><code>vector<span style="color: rgb(102, 102, 102);"><</span>KeyPoint<span style="color: rgb(102, 102, 102);">></span> kp;
detect<span style="color: rgb(102, 102, 102);">-></span>detect(image, kp);
</code></pre></div><p>Finalmente para visualizar los puntos encontrados usaremos la función <code>cv::drawKeypoints(...)</code> en la cual indicamos la imagen de entrada, el conjunto de puntos que deseamos dibujar, la imagen de salida, el color a utilizar (-1 indica colores aleatorios) y el modo como deseamos dibujar los puntos puedes probar las opciones de <code>DrawMatchesFlags</code>. </p><div class="code-painter"> <pre><code>Mat result;
drawKeypoints(image, kp, result, Scalar<span style="color: rgb(102, 102, 102);">::</span>all(<span style="color: rgb(102, 102, 102);">-1</span>), DrawMatchesFlags<span style="color: rgb(102, 102, 102);">::</span>DRAW_RICH_KEYPOINTS);
</code></pre></div><p>El resultado:</p><p><a href="https://lh3.googleusercontent.com/-Q8_Y5WYSYBs/WvNh61U1WFI/AAAAAAAAD9Q/RnkD0IhXQR0_-EqN1_OSxzzojTnkYOW-ACHMYCw/s1600-h/image2"><img title="OpenCV ORB" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="OpenCV ORB" src="https://lh3.googleusercontent.com/-JIEjXD1ZQyY/WvNh8pOYtWI/AAAAAAAAD9U/Jbl7cuh8Y_4SNZ24ooF5Bod_wtclonTDQCHMYCw/image_thumb?imgmax=800" width="531" height="559" /></a></p><p>Otro ejemplo, ahora con la clase AKAZE.</p><p><a href="https://lh3.googleusercontent.com/-Ke4BDVb8Log/WvNh_BReJXI/AAAAAAAAD9Y/MW5ZXtujAyoNii5KUzEIEPNJJD6xxfu0QCHMYCw/s1600-h/image5"><img title="OpenCV AKAZE" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="OpenCV AKAZE" src="https://lh3.googleusercontent.com/-Aw-0X5tp9tw/WvNiCj_hYSI/AAAAAAAAD9c/sWgPYFWTv4ktyCwtkkSz9euFYw933n73wCHMYCw/image_thumb1?imgmax=800" width="531" height="559" /></a></p><p>Puedes probar todas loas otras clases disponibles y ver los resultados.</p><h4>Pareo de Keypoints</h4><p>Una vez tenemos los puntos característicos de nuestra imagen podemos intentar localizar estos puntos en una segunda imagen, con ello podremos por ejemplo: combinar imágenes, realizar seguimiento y detección de una figura plana conocida, hacer aplicaciones de realidad aumentada, entre otras cosas.</p><p>Lo primero que necesitamos es obtener un descriptor para cada punto que hemos obtenido, este descriptor nos permite definir de manera sencilla un keypoint, luego de obtener los correspondientes descriptores solo los comparamos para obtener los más parecidos entre sí.</p><div class="code-painter"> <pre><code><span style="color: rgb(188, 122, 0);">#include</span> <span style="color: rgb(64, 128, 128); font-style: italic;"><iostream></span><span style="color: rgb(188, 122, 0);"></span>
<span style="color: rgb(188, 122, 0);">#include</span> <span style="color: rgb(64, 128, 128); font-style: italic;"><opencv2\opencv.hpp></span><span style="color: rgb(188, 122, 0);"></span>
<span style="color: rgb(188, 122, 0);">#include</span> <span style="color: rgb(64, 128, 128); font-style: italic;"><opencv2\features2d.hpp></span><span style="color: rgb(188, 122, 0);"></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">using</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">namespace</span> cv;
<span style="color: rgb(0, 128, 0); font-weight: bold;">using</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">namespace</span> std;
<span style="color: rgb(176, 0, 64);">int</span> <span style="color: rgb(0, 0, 255);">main</span>(<span style="color: rgb(176, 0, 64);">int</span> argc, <span style="color: rgb(176, 0, 64);">char</span><span style="color: rgb(102, 102, 102);">**</span> argv )
{
Mat imageA <span style="color: rgb(102, 102, 102);">=</span> imread(<span style="color: rgb(186, 33, 33);">"../opencv-keypoints/box.png"</span>, IMREAD_GRAYSCALE);
Mat imageB <span style="color: rgb(102, 102, 102);">=</span> imread(<span style="color: rgb(186, 33, 33);">"../opencv-keypoints/box_in_scene.png"</span>, IMREAD_GRAYSCALE);
<span style="color: rgb(0, 128, 0); font-weight: bold;">if</span> (imageA.empty() <span style="color: rgb(102, 102, 102);">||</span> imageB.empty())
{
printf(<span style="color: rgb(186, 33, 33);">"No image data."</span>);
getchar();
<span style="color: rgb(0, 128, 0); font-weight: bold;">return</span> <span style="color: rgb(102, 102, 102);">-1</span>;
}
Ptr<span style="color: rgb(102, 102, 102);"><</span>Feature2D<span style="color: rgb(102, 102, 102);">></span> detect <span style="color: rgb(102, 102, 102);">=</span> BRISK<span style="color: rgb(102, 102, 102);">::</span>create();
vector<span style="color: rgb(102, 102, 102);"><</span>KeyPoint<span style="color: rgb(102, 102, 102);">></span> kpA, kpB;
Mat descA, descB;
detect<span style="color: rgb(102, 102, 102);">-></span>detectAndCompute(imageA, noArray(), kpA, descA);
detect<span style="color: rgb(102, 102, 102);">-></span>detectAndCompute(imageB, noArray(), kpB, descB);
vector<span style="color: rgb(102, 102, 102);"><</span>DMatch<span style="color: rgb(102, 102, 102);">></span> matches;
Ptr<span style="color: rgb(102, 102, 102);"><</span>DescriptorMatcher<span style="color: rgb(102, 102, 102);">></span> matcher <span style="color: rgb(102, 102, 102);">=</span> BFMatcher<span style="color: rgb(102, 102, 102);">::</span>create(NORM_HAMMING, <span style="color: rgb(0, 128, 0);">true</span>);
matcher<span style="color: rgb(102, 102, 102);">-></span>match(descA, descB, matches);
sort(matches.begin(), matches.end());
matches.erase(matches.begin() <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">35</span>, matches.end());
Scalar color <span style="color: rgb(102, 102, 102);">=</span> Scalar<span style="color: rgb(102, 102, 102);">::</span>all(<span style="color: rgb(102, 102, 102);">-1</span>);
<span style="color: rgb(176, 0, 64);">int</span> flags <span style="color: rgb(102, 102, 102);">=</span> DrawMatchesFlags<span style="color: rgb(102, 102, 102);">::</span>NOT_DRAW_SINGLE_POINTS;
Mat result;
drawMatches(imageA, kpA, imageB, kpB, matches, result, color, color, vector<span style="color: rgb(102, 102, 102);"><</span><span style="color: rgb(176, 0, 64);">char</span><span style="color: rgb(102, 102, 102);">></span>(), flags);
imshow(<span style="color: rgb(186, 33, 33);">"OpenCV :: Match Keypoints"</span>, result);
waitKey(<span style="color: rgb(102, 102, 102);">0</span>);
<span style="color: rgb(0, 128, 0); font-weight: bold;">return</span> <span style="color: rgb(102, 102, 102);">0</span>;
}
</code></pre></div><p>Usaremos el método <code>detectAndCompute(...)</code> para detectar los puntos y generar los descriptores para cada uno de ellos, también puedes usar <code>detect(...)</code> para ubicar los puntos y luego <code>compute(...)</code> para calcular los respectivos descriptores. </p><div class="code-painter"> <pre><code>Ptr<span style="color: rgb(102, 102, 102);"><</span>Feature2D<span style="color: rgb(102, 102, 102);">></span> detect <span style="color: rgb(102, 102, 102);">=</span> BRISK<span style="color: rgb(102, 102, 102);">::</span>create();
vector<span style="color: rgb(102, 102, 102);"><</span>KeyPoint<span style="color: rgb(102, 102, 102);">></span> kpA, kpB;
Mat descA, descB;
detect<span style="color: rgb(102, 102, 102);">-></span>detectAndCompute(imageA, noArray(), kpA, descA);
detect<span style="color: rgb(102, 102, 102);">-></span>detectAndCompute(imageB, noArray(), kpB, descB);
</code></pre></div><p>Nótese que calculamos los puntos característicos y descriptores para ambas imágenes, los segundos son almacenados en un objeto <code>cv::Mat</code>.</p><p>Luego utilizamos <code>BFMatcher</code> (<strong>BruteForceMatcher</strong>) para comparar los descriptores de cada punto y obtener el pareo para cada uno de ellos, la clase base para los comparadores es <code>DescriptorMatcher</code>, al utilizar el método <code>match(...)</code> obtenemos una lista de <code>DMatch</code>. </p><div class="code-painter"> <pre><code>vector<span style="color: rgb(102, 102, 102);"><</span>DMatch<span style="color: rgb(102, 102, 102);">></span> matches;
Ptr<span style="color: rgb(102, 102, 102);"><</span>DescriptorMatcher<span style="color: rgb(102, 102, 102);">></span> matcher <span style="color: rgb(102, 102, 102);">=</span> BFMatcher<span style="color: rgb(102, 102, 102);">::</span>create(NORM_HAMMING, <span style="color: rgb(0, 128, 0);">true</span>);
matcher<span style="color: rgb(102, 102, 102);">-></span>match(descA, descB, matches);
</code></pre></div><p>Antes de visualizar el pareo vamos a tratar de filtrar aquellos que son correctos, para esto ordenamos en base al campo <code>DMatch.distance</code> de <code>DMatch</code>, el cual indica el nivel de similitud que existe entre un punto y su correspondiente, de modo que entre menor sea este valor mayor probabilidad de que sea bueno, por ello ordenamos y luego nos quedamos con los primeros 35 elementos.</p><div class="code-painter"> <pre><code>sort(matches.begin(), matches.end());
matches.erase(matches.begin() <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">35</span>, matches.end());
</code></pre></div><p>Ahora ya podemos visualizar el resultado de una mejor manera, para esta terea usamos el método <code>cv::drawMatches(...)</code> le indicamos la imagen inicial y sus puntos y luego la segundo con sus puntos, seguimos con el pareo y luego la imagen de salida, los últimos parámetros con para configurar la salida, colores y modo de dibujo.</p><div class="code-painter"> <pre><code>Scalar color <span style="color: rgb(102, 102, 102);">=</span> Scalar<span style="color: rgb(102, 102, 102);">::</span>all(<span style="color: rgb(102, 102, 102);">-1</span>);
<span style="color: rgb(176, 0, 64);">int</span> flags <span style="color: rgb(102, 102, 102);">=</span> DrawMatchesFlags<span style="color: rgb(102, 102, 102);">::</span>NOT_DRAW_SINGLE_POINTS;
Mat result;
drawMatches(imageA, kpA, imageB, kpB, matches, result, color, color, vector<span style="color: rgb(102, 102, 102);"><</span><span style="color: rgb(176, 0, 64);">char</span><span style="color: rgb(102, 102, 102);">></span>(), flags);
</code></pre></div><p>Con esto tenemos el siguiente resultado:</p><p><a href="https://lh3.googleusercontent.com/-yCQNytuMcmk/WvNiF_m1s4I/AAAAAAAAD9g/mU_Gzafs8wgxlCNXI1dvLTauFj4bUTo2wCHMYCw/s1600-h/image%255B3%255D"><img title="OpenCV BFMatch" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="OpenCV BFMatch" src="https://lh3.googleusercontent.com/-8t_KRZXSuWk/WvNiItpiVvI/AAAAAAAAD9s/u3GFhdMNiBMZy1lY2BlbIfJzykucWijMQCHMYCw/image_thumb%255B1%255D?imgmax=800" width="855" height="431" /></a></p><p>Con esto terminamos por hoy, en próximos tutoriales veremos algunas aplicaciones de lo aprendido, puede ser detección y seguimiento de objetos planos y realidad aumentada.</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2590617132675118769.post-4151523460399168672018-04-20T08:40:00.001-07:002018-04-20T08:47:15.514-07:00OpenCV4Android Detección de Objetos<p>Luego de haber creado nuestra primera aplicación Android OpenCV vamos a introducir conceptos un poco más avanzados y funcionales, en este tutorial aprenderemos a usar los clasificadores en cascada XML para detectar un objeto de nuestro interés, en este caso utilizaremos uno los clasificadores pre-entrenados que se incluyen en el SDK pero puedes entrenar tu propio clasificador que que detecte cualquier objeto que desees.</p><a name='more'></a> <p><a href="https://lh3.googleusercontent.com/-OWQoOlstar0/WtoJwqXp-pI/AAAAAAAAD8I/6cH_xim4WEco8iFCvzMiwgE5fV-QDcE4ACHMYCw/s1600-h/OpenCV4Android-Detector-Objetos%255B2%255D"><img title="OpenCV4Android-Detector-Objetos" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="OpenCV4Android-Detector-Objetos" src="https://lh3.googleusercontent.com/-CKzyqSjLewo/WtoJx0A3U3I/AAAAAAAAD8M/uIq0_2x2VdEdjYaqx42TooiI9CvQXZWagCHMYCw/OpenCV4Android-Detector-Objetos_thumb?imgmax=800" width="1276" height="716" /></a></p><p>El primer paso será crear nuestro proyecto y añadirle el SDK de OpenCV tal como lo hicimos en el tutorial anterior, puedes verlo en: <a href="http://acodigo.blogspot.com/2018/02/programacion-opencv-para-android.html" target="_blank">Creación de proyecto OpenCV Android</a>.</p><p>Una vez tengamos preparado nuestro proyecto añadiremos un componente <code>JavaCameraView</code> que nos permitirá visualizar la captura de la cámara, a diferencia del ejemplo anterior esta vez lo añadiremos directamente a nuestra <code>Activity</code>, veamos el código:</p><div class="code-painter"><pre><code><span style="color: rgb(170, 34, 255);">@Override</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">protected</span> <span style="color: rgb(176, 0, 64);">void</span> <span style="color: rgb(0, 0, 255);">onCreate</span><span style="color: rgb(102, 102, 102);">(</span>Bundle savedInstanceState<span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">{</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">super</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">onCreate</span><span style="color: rgb(102, 102, 102);">(</span>savedInstanceState<span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// solicitar permisos para utilizar la camara</span>
requestPermissions<span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> String<span style="color: rgb(102, 102, 102);">[]{</span> Manifest<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">permission</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">CAMERA</span> <span style="color: rgb(102, 102, 102);">},</span> <span style="color: rgb(102, 102, 102);">1);</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// crear el componente que muestra la captura de la camara</span>
cameraView <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> JavaCameraView<span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(0, 128, 0); font-weight: bold;">this</span><span style="color: rgb(102, 102, 102);">,</span> CameraBridgeViewBase<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">CAMERA_ID_FRONT</span><span style="color: rgb(102, 102, 102);">);</span>
cameraView<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">setVisibility</span><span style="color: rgb(102, 102, 102);">(</span>SurfaceView<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">VISIBLE</span><span style="color: rgb(102, 102, 102);">);</span>
cameraView<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">setCvCameraViewListener</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(0, 128, 0); font-weight: bold;">this</span><span style="color: rgb(102, 102, 102);">);</span>
cameraView<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">enableFpsMeter</span><span style="color: rgb(102, 102, 102);">();</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// añadir el componente a la actividad</span>
setContentView<span style="color: rgb(102, 102, 102);">(</span>cameraView<span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(102, 102, 102);">}</span>
</code></pre></div><p>El siguiente cambio que haremos con respecto a la versión anterior será el método usado para cargar la librería, esta vez utilizaremos la clase <code>OpenCVLoader</code> diseñada para tal propósito.</p><div class="code-painter"> <pre><code><span style="color: rgb(170, 34, 255);">@Override</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">protected</span> <span style="color: rgb(176, 0, 64);">void</span> <span style="color: rgb(0, 0, 255);">onResume</span><span style="color: rgb(102, 102, 102);">()</span> <span style="color: rgb(102, 102, 102);">{</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">super</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">onResume</span><span style="color: rgb(102, 102, 102);">();</span>
Log<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">i</span><span style="color: rgb(102, 102, 102);">(</span>TAG<span style="color: rgb(102, 102, 102);">,</span> <span style="color: rgb(186, 33, 33);">"Cargando librería .so incluida en proyecto..."</span><span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">if</span> <span style="color: rgb(102, 102, 102);">(!</span>OpenCVLoader<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">initDebug</span><span style="color: rgb(102, 102, 102);">())</span> <span style="color: rgb(102, 102, 102);">{</span>
Log<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">i</span><span style="color: rgb(102, 102, 102);">(</span>TAG<span style="color: rgb(102, 102, 102);">,</span> <span style="color: rgb(186, 33, 33);">"Cargando librería con OpenCV Manager..."</span><span style="color: rgb(102, 102, 102);">);</span>
OpenCVLoader<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">initAsync</span><span style="color: rgb(102, 102, 102);">(</span>OpenCVLoader<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">OPENCV_VERSION_3_0_0</span><span style="color: rgb(102, 102, 102);">,</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">this</span><span style="color: rgb(102, 102, 102);">,</span> ocvLoaderCallback<span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(102, 102, 102);">}</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">else</span> <span style="color: rgb(102, 102, 102);">{</span>
ocvLoaderCallback<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">onManagerConnected</span><span style="color: rgb(102, 102, 102);">(</span>LoaderCallbackInterface<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">SUCCESS</span><span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(102, 102, 102);">}</span>
</code></pre></div><p>Usando el método <code>initDebug()</code> inicializamos la librería de manera estática, esto es similar a lo que hicimos anteriormente recordemos que debemos tener la carpeta <b>jniLibs</b> con los archivos .so correspondientes a la arquitectura de CPU para la cual destinamos la aplicación. </p><p><a href="https://lh3.googleusercontent.com/-8qTc7ApAQiE/WtoJy7UJhEI/AAAAAAAAD8Q/HeiXieEZVxgVsYPXwJxLe3Z09U4b1ijawCHMYCw/s1600-h/image%255B14%255D"><img title="añadir opencv lib .so" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="añadir opencv lib .so" src="https://lh3.googleusercontent.com/-FDvARimtAtU/WtoJz-dshkI/AAAAAAAAD8U/7416WBiMdtIipRL4LR07wXo0RGrOVLsKACHMYCw/image_thumb%255B37%255D?imgmax=800" width="420" height="237" /></a></p><p>Debemos saber que este método esta diseñado solo para propósitos de desarrollo y pruebas, cuando nuestra app este lista debemos usar <code>initAsync()</code> la cual inicializa la librería de manera asíncrona, además no requiere que incluyamos los archivos .so en nuestra app lo que reduce su tamaño.</p><p>Este método hace uso de una aplicación externa llamada OpenCV Manager para administrar la librería nativa, si no la tienes instalada al momento de ejecutar se te pedirá hacerlo, puedes instalarla desde la tienda o desde los archivos .apk incluidos en el OpenCV4Android SDK se encuentran en la carpeta apk, recuerda instalar el adecuado a tu arquitectura.</p><p><a href="https://lh3.googleusercontent.com/-319selCCjR4/WtoJ0tHqe5I/AAAAAAAAD8Y/5O6klhO-ga0UaUyRQRk7vZsaWUjJYnrsQCHMYCw/s1600-h/image%255B9%255D"><img title="Instalar OpenCV Manager" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Instalar OpenCV Manager" src="https://lh3.googleusercontent.com/-nECczlpFvkI/WtoJ1rNnnUI/AAAAAAAAD8c/CnaJq8JVsLs689UGaa5Fzw5yPtZXGhBdACHMYCw/image_thumb%255B10%255D?imgmax=800" width="334" height="217" /></a></p><p>Al utilizar <code>OpenCVLoader.initAsync()</code> debemos indicar un callback, este recibirá la notificación de si se ha podido o no cargar la librería nativa, si todo está correcto aprovechamos para inicializar nuestro clasificador en cascada y habilitar la vista, de este modo:</p><div class="code-painter"> <pre><code><span style="color: rgb(0, 128, 0); font-weight: bold;">private</span> BaseLoaderCallback ocvLoaderCallback <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> BaseLoaderCallback<span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(0, 128, 0); font-weight: bold;">this</span><span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">{</span>
<span style="color: rgb(170, 34, 255);">@Override</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">public</span> <span style="color: rgb(176, 0, 64);">void</span> <span style="color: rgb(0, 0, 255);">onManagerConnected</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(176, 0, 64);">int</span> status<span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">{</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">switch</span> <span style="color: rgb(102, 102, 102);">(</span>status<span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">{</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">case</span> LoaderCallbackInterface<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">SUCCESS</span><span style="color: rgb(102, 102, 102);">:</span>
Log<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">i</span><span style="color: rgb(102, 102, 102);">(</span>TAG<span style="color: rgb(102, 102, 102);">,</span> <span style="color: rgb(186, 33, 33);">"Carga de OpenCV correcta..."</span><span style="color: rgb(102, 102, 102);">);</span>
cameraView<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">enableView</span><span style="color: rgb(102, 102, 102);">();</span>
String path <span style="color: rgb(102, 102, 102);">=</span> CascadeHelper<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">generateXmlPath</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(0, 128, 0); font-weight: bold;">this</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">mAppContext</span><span style="color: rgb(102, 102, 102);">,</span> R<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">raw</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">haarcascade_frontalface_alt2</span><span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">if</span> <span style="color: rgb(102, 102, 102);">(</span>path <span style="color: rgb(102, 102, 102);">!=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">null</span><span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">{</span>
detector <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> CascadeClassifier<span style="color: rgb(102, 102, 102);">(</span>path<span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">if</span> <span style="color: rgb(102, 102, 102);">(!</span>detector<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">empty</span><span style="color: rgb(102, 102, 102);">())</span> <span style="color: rgb(102, 102, 102);">{</span>
Log<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">i</span><span style="color: rgb(102, 102, 102);">(</span>TAG<span style="color: rgb(102, 102, 102);">,</span> <span style="color: rgb(186, 33, 33);">"Cargar clasificador .xml, archivo: "</span> <span style="color: rgb(102, 102, 102);">+</span> path<span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">break</span><span style="color: rgb(102, 102, 102);">;</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">default</span><span style="color: rgb(102, 102, 102);">:</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">super</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">onManagerConnected</span><span style="color: rgb(102, 102, 102);">(</span>status<span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">break</span><span style="color: rgb(102, 102, 102);">;</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(102, 102, 102);">};</span>
</code></pre></div><p>Antes que nada debemos tener el archivo XML del clasificador en la carpeta <samp>/res/raw/</samp> de nuestro proyecto, para este ejemplo vamos a probar con el clasificado HAAR entrenado para detectar rostros o caras frontales, puedes probar con cualquier otro.</p><p><a href="https://lh3.googleusercontent.com/-xMD1T4BJpgQ/WtoJ2nDq12I/AAAAAAAAD8g/3WDhhZtwy5EaHpXiKjVWQIFRMbpaPnXawCHMYCw/s1600-h/image%255B17%255D"><img title="Agregar clasificador en cascada .xml" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Agregar clasificador en cascada .xml" src="https://lh3.googleusercontent.com/-cGDm_jLpKGI/WtoJ3gfhqdI/AAAAAAAAD8k/gsxU37EEJBM05qIIpTha26asY4j8V-2aQCHMYCw/image_thumb%255B38%255D?imgmax=800" width="536" height="320" /></a></p><p>Para cargar y utilizar el clasificador usamos la clase <code>CascadeClassifier</code> debemos indicarle la ruta en donde se encuentra el respectivo archivo <samp>*.xml</samp> para este propósito usamos la clase <code>CascadeHelper</code> y su método <code>generateXmlPath()</code>, este se encarga de tomar el archivo indicado y copiarlo en un archivo temporal, luego se devuelve la ruta a este archivo.</p><p>Con esto tenemos todo preparado, ahora podemos agregar nuestro código OpenCV para detectar y mostrar los resultados en la pantalla, vemos como se hace:</p><div class="code-painter"> <pre><code><span style="color: rgb(170, 34, 255);">@Override</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">public</span> Mat <span style="color: rgb(0, 0, 255);">onCameraFrame</span><span style="color: rgb(102, 102, 102);">(</span>Mat src<span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">{</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// convertir a escala de grices y luego ecualizar histograma</span>
Imgproc<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">cvtColor</span><span style="color: rgb(102, 102, 102);">(</span>src<span style="color: rgb(102, 102, 102);">,</span> gray<span style="color: rgb(102, 102, 102);">,</span> Imgproc<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">COLOR_BGR2GRAY</span><span style="color: rgb(102, 102, 102);">);</span>
Imgproc<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">equalizeHist</span><span style="color: rgb(102, 102, 102);">(</span>gray<span style="color: rgb(102, 102, 102);">,</span> gray<span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// detectar los objetos presentes en la imagen de entrada</span>
MatOfRect faces <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> MatOfRect<span style="color: rgb(102, 102, 102);">();</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">if</span> <span style="color: rgb(102, 102, 102);">(</span>detector <span style="color: rgb(102, 102, 102);">!=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">null</span> <span style="color: rgb(102, 102, 102);">&&</span> <span style="color: rgb(102, 102, 102);">!</span>detector<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">empty</span><span style="color: rgb(102, 102, 102);">())</span> <span style="color: rgb(102, 102, 102);">{</span>
detector<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">detectMultiScale</span><span style="color: rgb(102, 102, 102);">(</span>gray<span style="color: rgb(102, 102, 102);">,</span> faces<span style="color: rgb(102, 102, 102);">,</span> <span style="color: rgb(102, 102, 102);">1.1,</span> <span style="color: rgb(102, 102, 102);">2,</span> <span style="color: rgb(102, 102, 102);">2,</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> Size<span style="color: rgb(102, 102, 102);">(200,</span> <span style="color: rgb(102, 102, 102);">200),</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> Size<span style="color: rgb(102, 102, 102);">());</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// dibujar un rectangulo sobre los objetos encontrado en el paso anterior</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">for</span> <span style="color: rgb(102, 102, 102);">(</span>Rect rc <span style="color: rgb(102, 102, 102);">:</span> faces<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">toList</span><span style="color: rgb(102, 102, 102);">())</span> <span style="color: rgb(102, 102, 102);">{</span>
Imgproc<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">rectangle</span><span style="color: rgb(102, 102, 102);">(</span>src<span style="color: rgb(102, 102, 102);">,</span> rc<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">tl</span><span style="color: rgb(102, 102, 102);">(),</span> rc<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">br</span><span style="color: rgb(102, 102, 102);">(),</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> Scalar<span style="color: rgb(102, 102, 102);">(0,</span> <span style="color: rgb(102, 102, 102);">255,</span> <span style="color: rgb(102, 102, 102);">0));</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">return</span> src<span style="color: rgb(102, 102, 102);">;</span>
<span style="color: rgb(102, 102, 102);">}</span>
</code></pre></div><p>Puedes tener más detalles sobre la <a href="http://acodigo.blogspot.com/2013/06/deteccion-de-rostros.html" target="_blank">detección de rostros con OpenCV</a> en el presente enlace, el lenguaje de programación no es Java pero la teoría es la misma, también puede ver como <a href="http://acodigo.blogspot.com/2015/12/entrenar-opencv-en-deteccion-de-objetos.html" target="_blank">entrenar un clasificador en cascada</a> para crear tu propio clasificador XML.</p><p>Recordemos que nuestra actividad debe implementar la interface <code>CvCameraViewListener</code>, el método mostrado arriba proviene de esta interface, el mismo recibe el objeto <code>Mat</code> que representa la imagen capturada por la cámara, la procesa y devuelve el resultado. </p><p>También debemos recordar que nuestro manifiesto debe contener los permisos para poder utilizar la cámara del dispositivo.</p><p>Descargar código: <a href="https://github.com/TutorProgramacion/tutoriales-programacion/raw/master/opencv/android/2018/Detector.zip" target="_blank">OpenCV4Android-Detector-Objetos.zip</a></p>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2590617132675118769.post-90466168674267160462018-04-17T13:09:00.001-07:002018-04-17T13:12:02.832-07:00Compilar Ninja sobre Windows con Visual Studio<p>El presente tutorial de dedicaremos al proceso requerido para construir el sistema Ninja, este es un sistema de construcción pequeño y muy rápido, actualmente Ninja se usa para construir Google Chrome, partes de Android, LLVM, y se puede usar en muchos otros proyectos debido al backend Ninja de CMake.</p><a name='more'></a> <p>Para realizar este procedimiento requerimos lo siguiente:</p><ul><li>Visual Studio 2015 o superior, la versión Community es suficiente.</li>
<li>Python, instalado y agregado al PATH.</li>
<li>Código fuente de Ninja, puedes obtenerlo de GitHub: <a title="https://github.com/ninja-build/ninja" href="https://github.com/ninja-build/ninja">https://github.com/ninja-build/ninja</a></li>
</ul><p>Debes saber que también puedes descargar los binarios pre-compilados por si no deseas realizar tu propia compilación, están disponibles en: <a title="https://github.com/ninja-build/ninja/releases" href="https://github.com/ninja-build/ninja/releases">https://github.com/ninja-build/ninja/releases</a>.</p><p>Luego de descargar el código fuente lo descomprimiremos en la carpeta de nuestra preferencia, para nuestro caso <samp>C:/developer/ninja</samp> luego abrimos el <strong>Developer Command Prompt</strong> de Visual Studio, esta es una ventana de comandos preparado para compilar con las herramientas de VS.</p><p>En la ventana de comandos usaremos cd <samp>C:/developer/ninja</samp> para ubicarnos en la carpeta respectiva.</p><p>Luego usaremos el siguiente comando <samp><b>python configure.py --bootstrap</b></samp></p><p><a href="https://lh3.googleusercontent.com/-pvKfT9k6m2Y/WtZUcgDDWBI/AAAAAAAAD70/8KXcoCwTe6QUbpDaXX7lYIBOFPxAQGWLwCHMYCw/s1600-h/image%255B2%255D"><img title="Compilar Ninja para Windows x86" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Compilar Ninja para Windows x86" src="https://lh3.googleusercontent.com/-PMUY-fCVAr0/WtZUdqe-4XI/AAAAAAAAD74/Nn8Tqf3pIiM21Y3X8dJvaZSQa7P1bv1RACHMYCw/image_thumb?imgmax=800" width="842" height="550" /></a></p><p>Al finalizar tendremos el archivo <samp>C:/developer/ninja/ninja.exe</samp> listo para ser utilizado, podemos probarlo de la siguiente manera:</p><p>Abrimos una ventana de comando y ejecutamos: <samp>C:/developer/ninja/ninja.exe --version</samp> si podemos ver la versión correspondiente es indicativo de que el proceso ha sido correcto.</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2590617132675118769.post-79489899568798664652018-04-09T08:35:00.001-07:002018-04-09T08:39:18.469-07:00Serializar objetos Java en formato binario<p>En tutoriales anteriores aprendimos como serializar objetos Java en formato JSON ya sea para enviarlos por la red o guardarlos en un archivo, para esta ocasión vamos a estudiar la librería <strong>msg-pack</strong> la cual nos permitirá serializar objetos Java o tipos primitivos en formato binario, al utilizar un archivo binario la lectura y la escritura es mucho más rápida, además el tamaño del archivo se reduce en comparación a un archivo que almacena JSON en formato texto plano.</p><a name='more'></a> <p><a href="https://lh3.googleusercontent.com/-vCrMZK6MMIo/WsuIQ2ufuWI/AAAAAAAAD7Y/EtipKi7h4WgFbSa-5rEsWMAnRAvR1e24gCHMYCw/s1600-h/msgpack%255B2%255D"><img title="msgpack" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="msgpack" src="https://lh3.googleusercontent.com/-FSJf79amvDo/WsuIUWWwpcI/AAAAAAAAD7c/A8_gC-zP72wuWfZji0Q6v7NiJfJO4lSywCHMYCw/msgpack_thumb?imgmax=800" width="935" height="462" /></a></p><p>Para utilizar esta librería en nuestro tutorial haremos uso de Maven, agregamos la siguiente dependencia a nuestro proyecto demostrativo:</p><div class="code-painter"><pre><code><span style="color: rgb(102, 102, 102);"><</span>dependency<span style="color: rgb(102, 102, 102);">></span>
<span style="color: rgb(102, 102, 102);"><</span>groupId<span style="color: rgb(102, 102, 102);">></span>org<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">msgpack</span><span style="color: rgb(102, 102, 102);"></</span>groupId<span style="color: rgb(102, 102, 102);">></span>
<span style="color: rgb(102, 102, 102);"><</span>artifactId<span style="color: rgb(102, 102, 102);">></span>msgpack<span style="color: rgb(102, 102, 102);">-</span>core<span style="color: rgb(102, 102, 102);"></</span>artifactId<span style="color: rgb(102, 102, 102);">></span>
<span style="color: rgb(102, 102, 102);"><</span>version<span style="color: rgb(102, 102, 102);">>0.8.14</</span>version<span style="color: rgb(102, 102, 102);">></span>
<span style="color: rgb(102, 102, 102);"></</span>dependency<span style="color: rgb(102, 102, 102);">></span>
</code></pre></div><h3>Guardar datos primitivos</h3><p>En este primer ejemplo veamos como podemos guardar los tipos primitivos usados por Java en formato binario, nos referimos a los tipos: <b>int</b>, <b>boolean</b>, <b>double</b>, etc.</p><div class="code-painter"> <pre><code><span style="color: rgb(64, 128, 128); font-style: italic;">// crear objeto MessagePacker (encoder) </span>
MessageBufferPacker packer <span style="color: rgb(102, 102, 102);">=</span> MessagePack<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">newDefaultBufferPacker</span><span style="color: rgb(102, 102, 102);">();</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// codificar los tipos primitivos</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packBoolean</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(0, 128, 0); font-weight: bold;">true</span><span style="color: rgb(102, 102, 102);">);</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packShort</span><span style="color: rgb(102, 102, 102);">((</span><span style="color: rgb(176, 0, 64);">short</span><span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">34);</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packInt</span><span style="color: rgb(102, 102, 102);">(1);</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packLong</span><span style="color: rgb(102, 102, 102);">(33000000000L);</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packFloat</span><span style="color: rgb(102, 102, 102);">(0.1f);</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packDouble</span><span style="color: rgb(102, 102, 102);">(3.14159263);</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packByte</span><span style="color: rgb(102, 102, 102);">((</span><span style="color: rgb(176, 0, 64);">byte</span><span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">0x80);</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// obtener el arreglo de bytes</span>
<span style="color: rgb(176, 0, 64);">byte</span><span style="color: rgb(102, 102, 102);">[]</span> out <span style="color: rgb(102, 102, 102);">=</span> packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">toByteArray</span><span style="color: rgb(102, 102, 102);">();</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// crear objeto MessageUnpaker (decoder)</span>
MessageUnpacker unpacker <span style="color: rgb(102, 102, 102);">=</span> MessagePack<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">newDefaultUnpacker</span><span style="color: rgb(102, 102, 102);">(</span>out<span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// decodificar los datos primitivos </span>
System<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">out</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">println</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(186, 33, 33);">"boolean: "</span> <span style="color: rgb(102, 102, 102);">+</span> unpacker<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">unpackBoolean</span><span style="color: rgb(102, 102, 102);">());</span>
System<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">out</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">println</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(186, 33, 33);">"short: "</span> <span style="color: rgb(102, 102, 102);">+</span> unpacker<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">unpackShort</span><span style="color: rgb(102, 102, 102);">());</span>
System<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">out</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">println</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(186, 33, 33);">"int "</span> <span style="color: rgb(102, 102, 102);">+</span> unpacker<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">unpackInt</span><span style="color: rgb(102, 102, 102);">());</span>
System<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">out</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">println</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(186, 33, 33);">"long: "</span> <span style="color: rgb(102, 102, 102);">+</span> unpacker<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">unpackLong</span><span style="color: rgb(102, 102, 102);">());</span>
</code></pre></div><p>Como se puede observar para codificar los datos primero debemos obtener una instancia <code>MessageBufferPacker</code> luego utilizar los respectivos métodos <code>packXXX()</code> para serializar los respectivos datos, usando el método <code>toByteArray()</code> obtenemos el arreglo de byte que representa nuestros datos serializados en formato binario.</p><p>De un modo similar pero al inverso, cuando deseemos leer los datos a partir de un arreglo de byte, usamos una instancia <code>MessageUnpacker</code> igual utilizaremos los métodos <code>unpackXXX()</code> para obtener los datos Java respectivos. </p><h3>Serializar String y Arreglos</h3><p>Podemos almacenar datos de tipo String, Arreglos y Map de manera similar, solo debemos tomar ciertas consideraciones, veamos un ejemplo:</p><div class="code-painter"> <pre><code><span style="color: rgb(64, 128, 128); font-style: italic;">// pack String</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packString</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(186, 33, 33);">"hello message pack!"</span><span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// pack arrays</span>
<span style="color: rgb(176, 0, 64);">int</span><span style="color: rgb(102, 102, 102);">[]</span> arr <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> <span style="color: rgb(176, 0, 64);">int</span><span style="color: rgb(102, 102, 102);">[]{1,</span> <span style="color: rgb(102, 102, 102);">2,</span> <span style="color: rgb(102, 102, 102);">3,</span> <span style="color: rgb(102, 102, 102);">4,</span> <span style="color: rgb(102, 102, 102);">5,</span> <span style="color: rgb(102, 102, 102);">6,</span> <span style="color: rgb(102, 102, 102);">7,</span> <span style="color: rgb(102, 102, 102);">8,</span> <span style="color: rgb(102, 102, 102);">9};</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packArrayHeader</span><span style="color: rgb(102, 102, 102);">(</span>arr<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">length</span><span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">for</span> <span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(176, 0, 64);">int</span> v <span style="color: rgb(102, 102, 102);">:</span> arr<span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">{</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packInt</span><span style="color: rgb(102, 102, 102);">(</span>v<span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(102, 102, 102);">}</span>
</code></pre></div><p>Primero vemos como guardar una cadena de texto, luego un arreglo de tipo entero, nótese que usamos el método <code>packArrayHeader(int)</code> para indicar la cantidad de elementos del arreglo, luego introducimos los elementos a través del método <code>packInt(int)</code>. </p><div class="code-painter"> <pre><code><span style="color: rgb(64, 128, 128); font-style: italic;">// pack Map, indicamos la cantidad de elementos</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packMapHeader</span><span style="color: rgb(102, 102, 102);">(2);</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// primer elemento del Map</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packString</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(186, 33, 33);">"apple"</span><span style="color: rgb(102, 102, 102);">);</span> <span style="color: rgb(64, 128, 128); font-style: italic;">// clave</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packInt</span><span style="color: rgb(102, 102, 102);">(1);</span> <span style="color: rgb(64, 128, 128); font-style: italic;">// valor</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// segundo elemento del Map</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packString</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(186, 33, 33);">"banana"</span><span style="color: rgb(102, 102, 102);">);</span> <span style="color: rgb(64, 128, 128); font-style: italic;">// clave</span>
packer<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">packInt</span><span style="color: rgb(102, 102, 102);">(2);</span> <span style="color: rgb(64, 128, 128); font-style: italic;">// valor</span>
</code></pre></div><p>De modo similar a un arreglo podemos también guardar un <code>Map</code> o arreglo asociativo, primero indicamos el la cantidad de elementos, luego por cada elemento introducimos primero la clave y luego el valor respectivo.</p><p>Cuando deseemos leer los datos recordamos primero leer la cantidad de elementos y luego usar los respectivos métodos <code>unpackXXX()</code> para obtener los valores deseados.</p><h3>Usar con Jackson</h3><p>En tutoriales anteriores vimos la <a href="http://acodigo.blogspot.com/2017/04/jackson-2-convertir-objeto-java-json.html" target="_blank">librería Jackson</a><b></b> que nos permite serializar objetos en formato JSON de manera sencilla, msgpack nos proporciona la librería <b>jackson-dataformat-msgpack</b> la cual nos permitirá seguir usando Jackson pero serializando los datos en formato binario.</p><div class="code-painter"> <pre><code><span style="color: rgb(0, 128, 0); font-weight: bold;"><dependency></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><groupId></span>org.msgpack<span style="color: rgb(0, 128, 0); font-weight: bold;"></groupId></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><artifactId></span>jackson-dataformat-msgpack<span style="color: rgb(0, 128, 0); font-weight: bold;"></artifactId></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><version></span>0.8.14<span style="color: rgb(0, 128, 0); font-weight: bold;"></version></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"></dependency></span>
</code></pre></div><p>Luego de agregar la dependencia solo hacemos lo siguiente:</p><div class="code-painter"> <pre><code><span style="color: rgb(64, 128, 128); font-style: italic;">// objeto a serializar</span>
Person p <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> Person<span style="color: rgb(102, 102, 102);">();</span>
p<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">setAge</span><span style="color: rgb(102, 102, 102);">(15);</span>
p<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">setGender</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(0, 128, 0); font-weight: bold;">true</span><span style="color: rgb(102, 102, 102);">);</span>
p<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">setName</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(186, 33, 33);">"Tutorial"</span><span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// archivo binario para crear </span>
File file <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> File<span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(186, 33, 33);">"binary.dat"</span><span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// jackson ObjectMapper</span>
ObjectMapper mapper <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> ObjectMapper<span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> MessagePackFactory<span style="color: rgb(102, 102, 102);">());</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// escribir el objeto Person</span>
mapper<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">writeValue</span><span style="color: rgb(102, 102, 102);">(</span>file<span style="color: rgb(102, 102, 102);">,</span> p<span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// leer el objeto Person</span>
Person person <span style="color: rgb(102, 102, 102);">=</span> mapper<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">readValue</span><span style="color: rgb(102, 102, 102);">(</span>file<span style="color: rgb(102, 102, 102);">,</span> Person<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">class</span><span style="color: rgb(102, 102, 102);">);</span>
</code></pre></div><p>Puedes ver que el modo para utilizar <code>Jackson</code> es muy similar al visto en el respectivo tutorial, lo único nuevo que añadimos es el objeto <code>MessagePackFactory()</code> puedes verificar que el archivo <samp>binary.dat</samp> se ha creado, este contiene el objeto <code>Person</code> serializado en formato binario. </p><p>Descargar código: <a href="https://github.com/TutorProgramacion/tutoriales-programacion/raw/master/java/varios/2018/test-msgpack.zip" target="_blank">serializar-binario.zip</a></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2590617132675118769.post-51470882993694722302018-02-19T05:58:00.001-08:002018-02-19T06:03:59.921-08:00Programación OpenCV para Android Introducción<p>Esta vez veremos el proceso requerido para desarrollar una App para el sistema Android utilizando la biblioteca OpenCV, aprenderemos como configurar nuestro entorno de programación y crearemos nuestra primera aplicación la cual nos permitirá capturar video accediendo a la cámara del dispositivo, dicho video será procesado en tiempo real para mostrar el detector de bordes Canny.</p><a name='more'></a> <p><a href="https://lh3.googleusercontent.com/-Eq0MisiLSJ4/WorX0oREJ2I/AAAAAAAAD4s/hLidx2CoC7IiynKwbaYJrcmSAdNU0k9YQCHMYCw/s1600-h/app-opencv2"><img title="app opencv" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="app opencv" src="https://lh3.googleusercontent.com/-aw51gEd428Q/WorX1pvGdCI/AAAAAAAAD4w/xLXueuramCMn7B8gQIfs7gTotPtK4XhKgCHMYCw/app-opencv_thumb?imgmax=800" width="960" height="540" /></a></p><p>Para empezar con este tutorial requerimos <a href="https://developer.android.com/studio/index.html?hl=es-419" target="_blank">Android Studio</a> 3.x además del <a href="https://opencv.org/releases.html" target="_blank">OpenCV4Android SDK</a> que puedes <a href="http://acodigo.blogspot.com/2018/02/compilar-el-sdk-opencv-para-android.html" target="_blank">compilar a partir del código</a> fuente como lo hicimos en la publicación anterior o simplemente puedes descargar los archivos pre-compilados, por supuesto también se requieren todas las herramientas destinadas a desarrollar aplicaciones Android, asumiremos que sabes como instalar y configurar el Android SDK y que haz desarrollado aplicaciones de este tipo anteriormente o por lo menos tienes los conocimientos básicos.</p><p>Lo primero que haremos será crear nuestro proyecto, de la siguiente manera:</p><p><a href="https://lh3.googleusercontent.com/-vRuShgjMEig/WorX2bkxliI/AAAAAAAAD40/atS3VxDJ7BkwDbAedFU6aTerEu5WLAsIgCHMYCw/s1600-h/image2"><img title="Android - Crear proyecto nuevo" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Android - Crear proyecto nuevo" src="https://lh3.googleusercontent.com/-kwsX9l-d6tw/WorX3KUyHgI/AAAAAAAAD44/kPxyybK839clKfsZpUGPWiM-RzDqFqhIACHMYCw/image_thumb?imgmax=800" width="918" height="696" /></a></p><p>Le damos una ubicación y nombre al proyecto.</p><p><a href="https://lh3.googleusercontent.com/-k5Y-Q24gRFg/WorX3vhMbHI/AAAAAAAAD48/xULpJq6FF-Ar-B7Lui4Ub-kxDwFkXXOBQCHMYCw/s1600-h/image5"><img title="Android - Seleccionar SDK" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Android - Seleccionar SDK" src="https://lh3.googleusercontent.com/-pej1Lazkmxo/WorX4f7V3oI/AAAAAAAAD5A/3wnOLE4PECAFtfm9ew0djNhe85MFk7UKACHMYCw/image_thumb1?imgmax=800" width="918" height="701" /></a></p><p>Establecemos el nivel de API mínimo aceptado por nuestra aplicación.</p><p><a href="https://lh3.googleusercontent.com/-pWmexn9IVk8/WorX5EsfJ_I/AAAAAAAAD5E/RSJw2d4_460EM9hOMxGXv-w56fC9mQ_pwCHMYCw/s1600-h/image8"><img title="Android Studio - agregar activity" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Android Studio - agregar activity" src="https://lh3.googleusercontent.com/-Jx3xzqhR8hg/WorX5ztW29I/AAAAAAAAD5I/ZottG_t5iNIzSqrMxRI9QMVa4a0hGQNpwCHMYCw/image_thumb2?imgmax=800" width="918" height="701" /></a></p><p>Creamos una actividad vacía.</p><p><a href="https://lh3.googleusercontent.com/-kIWHAIm5SOk/WorX6pIGBsI/AAAAAAAAD5M/43dV9dSIADktE06y-DTgzjROiSCV3IykQCHMYCw/s1600-h/image11"><img title="Android Studio - agregar nombre activity " style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Android Studio - agregar nombre activity " src="https://lh3.googleusercontent.com/-CXunu9z7OLQ/WorX7dgCySI/AAAAAAAAD5Q/O16GBCb7nQQ2Z9KJK4BQ5laV1K4PUhU1wCHMYCw/image_thumb3?imgmax=800" width="918" height="701" /></a></p><p>Le damos un nombre a la actividad y listo, tenemos nuestro proyecto.</p><h4>Agregar OpenCV4Android SDK a Android Studio IDE</h4><p>Para agregarlo debemos ir al menú principal <samp>File | New | Import Module...</samp>, debes localizar la carpeta en donde guardaste el <b>OpenCV4Android-SDK</b> dentro de él seleccionas la carpeta <samp>../sdk/java</samp> cuando lo hagas el nombre del módulo aparecerá automáticamente.</p><p>Recuerda que este SDK lo puedes obtener ya sea compilando desde código fuente y descargando el Zip comprimido que contiene los archivos pre-compilados. </p><p><a href="https://lh3.googleusercontent.com/-M7fZuWTBKl4/WorX8BoHYmI/AAAAAAAAD5U/r8pr8eVLABE7cmBr3jcddn7fKncVt9TswCHMYCw/s1600-h/image14"><img title="OpenCV4Android importar módulo" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="OpenCV4Android importar módulo" src="https://lh3.googleusercontent.com/-bwSOu3IdFXc/WorX81HbJFI/AAAAAAAAD5Y/NhmqPs92uBY-aTKWlqTtE2xkHX0C7bmTgCHMYCw/image_thumb4?imgmax=800" width="818" height="696" /></a></p><p>Al presionar Next se muestra la ventana de la imagen de abajo, quita todas las selecciones ya que no las necesitamos.</p><p><a href="https://lh3.googleusercontent.com/-atcRytSwZOs/WorX9Xv4HbI/AAAAAAAAD5c/stEyqS2PaQkGClyo6NM7yAVoLyXDZXG6gCHMYCw/s1600-h/image17"><img title="OpenCV4Android configurar módulo" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="OpenCV4Android configurar módulo" src="https://lh3.googleusercontent.com/-VN3jL0tqZXU/WorX-PvX1vI/AAAAAAAAD5g/AlRdpzyA3WsqagPA89zFFiKmCQjey1mKwCHMYCw/image_thumb5?imgmax=800" width="818" height="696" /></a></p><p>Para terminar solo debes presionar el botón Finish.</p><p>Lo siguiente que debemos hacer es editar el archivo <strong>build.gradle</strong> que corresponde al módulo que acabamos de agregar, puedes ubicarlo en la pestaña<em> Project</em> expandiendo el módulo correspondiente.</p><p>Observa que en la parte superior izquierda está seleccionada la opción <strong>Project</strong> si tienes otro selección el archivo puede aparecer en otro lugar o quizás no aparezca. </p><p><a href="https://lh3.googleusercontent.com/-vcWziy1FX5c/WorX-0u2_oI/AAAAAAAAD5k/uRAPMs6WnggpdtKxLC5iT7PNU9aeTsI_ACHMYCw/s1600-h/image20"><img title="Editar build.gradle" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Editar build.gradle" src="https://lh3.googleusercontent.com/-1GX04RMK9Mw/WorYAewZJDI/AAAAAAAAD5o/BIfRb_qFgfM4yOLDtT2otN6gSX5hNYDWwCHMYCw/image_thumb6?imgmax=800" width="505" height="587" /></a></p><p>Deberás cambiar la primera línea y también quitar la configuración <em>applicationId</em> el archivo debe quedar de este modo: </p><div class="code-painter"><pre><code>apply <span style="color: rgb(160, 160, 0);">plugin:</span> <span style="color: rgb(186, 33, 33);">'com.android.library'</span> <span style="color: rgb(64, 128, 128); font-style: italic;">// editar .application</span>
android <span style="color: rgb(102, 102, 102);">{</span>
compileSdkVersion <span style="color: rgb(102, 102, 102);">26</span>
buildToolsVersion <span style="color: rgb(186, 33, 33);">"26.0.2"</span>
defaultConfig <span style="color: rgb(102, 102, 102);">{</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// applicationId "org.opencv" // comentar</span>
minSdkVersion <span style="color: rgb(102, 102, 102);">8</span>
targetSdkVersion <span style="color: rgb(102, 102, 102);">21</span>
<span style="color: rgb(102, 102, 102);">}</span>
buildTypes <span style="color: rgb(102, 102, 102);">{</span>
release <span style="color: rgb(102, 102, 102);">{</span>
minifyEnabled <span style="color: rgb(0, 128, 0); font-weight: bold;">false</span>
proguardFiles <span style="color: rgb(0, 0, 255);">getDefaultProguardFile</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(186, 33, 33);">'proguard-android.txt'</span><span style="color: rgb(102, 102, 102);">),</span> <span style="color: rgb(186, 33, 33);">'proguard-rules.txt'</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(102, 102, 102);">}</span>
</code></pre></div><p>La versión del SDK de compilación y de las herramientas de construcción debe coincidir con las indicadas el archivo <em>build.gradle</em> de la aplicación, esto es solo si las haz cambiado si tienes la configuración por defecto todo estará correcto.</p><p>El siguiente paso es agregar el módulo openCVLibrary330 como una dependencia de nuestra aplicación, debes acceder al menú <em>File | Project Structure…</em> ubica app luego selecciona la pestaña Dependencies haz clic en icono + que se muestra en la parte superior derecha de la ventana y selecciona la opción 3, en la siguiente ventana selecciona el módulo indicado y presiona OK. </p><p><a href="https://lh3.googleusercontent.com/-DzDT-Rpshlk/WorYBPcCoMI/AAAAAAAAD5s/eYP7g7GdbMsj_b2OU2oTdIS8rPCCAF8SgCHMYCw/s1600-h/agregar-mdulo-opencv-a-android-studi%255B2%255D"><img title="agregar módulo opencv a android studio" style="margin: 0px auto; border-image: none; float: none; display: block; background-image: none;" border="0" alt="agregar módulo opencv a android studio" src="https://lh3.googleusercontent.com/-68JPw_sGsdI/WorYB3krRYI/AAAAAAAAD5w/L7A1W2InzC8uMsLNCxBKTrTlyh29Vjm_ACHMYCw/agregar-mdulo-opencv-a-android-studi?imgmax=800" width="1001" height="720" /></a></p><p>Hecho esto el siguiente paso el modificar el XML de nuestra actividad (<code>Activity</code>) lo que haremos será agregar un componente llamado <code>JavaCameraView</code> el cual nos permitirá visualizar en tiempo real el video capturado por la cámara del dispositivo. </p><div class="code-painter"> <pre><code><span style="color: rgb(188, 122, 0);"><?xml version="1.0" encoding="utf-8"?></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><android.support.constraint.ConstraintLayout</span> <span style="color: rgb(125, 144, 41);">xmlns:android=</span><span style="color: rgb(186, 33, 33);">"http://schemas.android.com/apk/res/android"</span>
<span style="color: rgb(125, 144, 41);">xmlns:app=</span><span style="color: rgb(186, 33, 33);">"http://schemas.android.com/apk/res-auto"</span>
<span style="color: rgb(125, 144, 41);">xmlns:opencv=</span><span style="color: rgb(186, 33, 33);">"http://schemas.android.com/apk/res-auto"</span>
<span style="color: rgb(125, 144, 41);">xmlns:tools=</span><span style="color: rgb(186, 33, 33);">"http://schemas.android.com/tools"</span>
<span style="color: rgb(125, 144, 41);">android:layout_width=</span><span style="color: rgb(186, 33, 33);">"match_parent"</span>
<span style="color: rgb(125, 144, 41);">android:layout_height=</span><span style="color: rgb(186, 33, 33);">"match_parent"</span>
<span style="color: rgb(125, 144, 41);">tools:context=</span><span style="color: rgb(186, 33, 33);">"programacion.tutor.opencvandroid.OpenCVActivity"</span><span style="color: rgb(0, 128, 0); font-weight: bold;">></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><org.opencv.android.JavaCameraView</span>
<span style="color: rgb(125, 144, 41);">android:id=</span><span style="color: rgb(186, 33, 33);">"@+id/cameraview"</span>
<span style="color: rgb(125, 144, 41);">android:layout_width=</span><span style="color: rgb(186, 33, 33);">"fill_parent"</span>
<span style="color: rgb(125, 144, 41);">android:layout_height=</span><span style="color: rgb(186, 33, 33);">"fill_parent"</span>
<span style="color: rgb(125, 144, 41);">android:visibility=</span><span style="color: rgb(186, 33, 33);">"gone"</span>
<span style="color: rgb(125, 144, 41);">opencv:camera_id=</span><span style="color: rgb(186, 33, 33);">"any"</span>
<span style="color: rgb(125, 144, 41);">opencv:show_fps=</span><span style="color: rgb(186, 33, 33);">"true"</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">/></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"></android.support.constraint.ConstraintLayout></span>
</code></pre></div><p>Ahora podemos modificar el código java de la actividad, utilizaremos el método estático <code>OpenCVLoader.initDebug()</code> para inicializar la librería y aprovecharemos los métodos <code>onResume()</code> y <code>onPause()</code> para habilitar o deshabilitar el componente, en el método <code>onCreate()</code> lo inicializamos. </p><div class="code-painter"> <pre><code><span style="color: rgb(0, 128, 0); font-weight: bold;">public</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">class</span> <span style="color: rgb(0, 0, 255); font-weight: bold;">OpenCVActivity</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">extends</span> AppCompatActivity
<span style="color: rgb(0, 128, 0); font-weight: bold;">implements</span> CameraBridgeViewBase<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">CvCameraViewListener2</span> <span style="color: rgb(102, 102, 102);">{</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">private</span> CameraBridgeViewBase cameraView <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">null</span><span style="color: rgb(102, 102, 102);">;</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">private</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">static</span> <span style="color: rgb(176, 0, 64);">boolean</span> initOpenCV <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">false</span><span style="color: rgb(102, 102, 102);">;</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">static</span> <span style="color: rgb(102, 102, 102);">{</span> initOpenCV <span style="color: rgb(102, 102, 102);">=</span> OpenCVLoader<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">initDebug</span><span style="color: rgb(102, 102, 102);">();</span> <span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(170, 34, 255);">@Override</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">protected</span> <span style="color: rgb(176, 0, 64);">void</span> <span style="color: rgb(0, 0, 255);">onCreate</span><span style="color: rgb(102, 102, 102);">(</span>Bundle savedInstanceState<span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">{</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">super</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">onCreate</span><span style="color: rgb(102, 102, 102);">(</span>savedInstanceState<span style="color: rgb(102, 102, 102);">);</span>
setContentView<span style="color: rgb(102, 102, 102);">(</span>R<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">layout</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">activity_open_cv</span><span style="color: rgb(102, 102, 102);">);</span>
cameraView <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(102, 102, 102);">(</span>CameraBridgeViewBase<span style="color: rgb(102, 102, 102);">)</span> findViewById<span style="color: rgb(102, 102, 102);">(</span>R<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">id</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">cameraview</span><span style="color: rgb(102, 102, 102);">);</span>
cameraView<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">setVisibility</span><span style="color: rgb(102, 102, 102);">(</span>SurfaceView<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">VISIBLE</span><span style="color: rgb(102, 102, 102);">);</span>
cameraView<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">setCvCameraViewListener</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(0, 128, 0); font-weight: bold;">this</span><span style="color: rgb(102, 102, 102);">);</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(170, 34, 255);">@Override</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">protected</span> <span style="color: rgb(176, 0, 64);">void</span> <span style="color: rgb(0, 0, 255);">onResume</span><span style="color: rgb(102, 102, 102);">()</span> <span style="color: rgb(102, 102, 102);">{</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">super</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">onResume</span><span style="color: rgb(102, 102, 102);">();</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">if</span> <span style="color: rgb(102, 102, 102);">(</span>initOpenCV<span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">{</span> cameraView<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">enableView</span><span style="color: rgb(102, 102, 102);">();</span> <span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(170, 34, 255);">@Override</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">public</span> <span style="color: rgb(176, 0, 64);">void</span> <span style="color: rgb(0, 0, 255);">onPause</span><span style="color: rgb(102, 102, 102);">()</span> <span style="color: rgb(102, 102, 102);">{</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">super</span><span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">onPause</span><span style="color: rgb(102, 102, 102);">();</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// Release the camera.</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">if</span> <span style="color: rgb(102, 102, 102);">(</span>cameraView <span style="color: rgb(102, 102, 102);">!=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">null</span><span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">{</span>
cameraView<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">disableView</span><span style="color: rgb(102, 102, 102);">();</span>
cameraView <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">null</span><span style="color: rgb(102, 102, 102);">;</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(170, 34, 255);">@Override</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">public</span> <span style="color: rgb(176, 0, 64);">void</span> <span style="color: rgb(0, 0, 255);">onCameraViewStarted</span><span style="color: rgb(102, 102, 102);">(</span><span style="color: rgb(176, 0, 64);">int</span> width<span style="color: rgb(102, 102, 102);">,</span> <span style="color: rgb(176, 0, 64);">int</span> height<span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">{</span> <span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(170, 34, 255);">@Override</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">public</span> <span style="color: rgb(176, 0, 64);">void</span> <span style="color: rgb(0, 0, 255);">onCameraViewStopped</span><span style="color: rgb(102, 102, 102);">()</span> <span style="color: rgb(102, 102, 102);">{</span> <span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(170, 34, 255);">@Override</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">public</span> Mat <span style="color: rgb(0, 0, 255);">onCameraFrame</span><span style="color: rgb(102, 102, 102);">(</span>CameraBridgeViewBase<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">CvCameraViewFrame</span> inputFrame<span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">{</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">return</span> inputFrame<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">rgba</span><span style="color: rgb(102, 102, 102);">();</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(102, 102, 102);">}</span>
</code></pre></div><p>Los tres últimos métodos que se observan arriba son requeridos por la interface <code>CvCameraViewListener2</code> nos sirven para detectar cuando la captura se inicia o se detiene, los primeros dos respetivamente, mientras que el tercero <code>onCameraFrame(...)</code> nos permitirá procesar cada cuadro capturado, en nuestro ejemplo usamos el método <code>inputFrame.rgba()</code> para devolver el objeto Mat original sin modificación.</p><p>Hagamos una modificación para hacer nuestra aplicación un poco más interesante:</p><div class="code-painter"> <pre><code><span style="color: rgb(0, 128, 0); font-weight: bold;">public</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">class</span> <span style="color: rgb(0, 0, 255); font-weight: bold;">OpenCVActivity</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">extends</span> AppCompatActivity
<span style="color: rgb(0, 128, 0); font-weight: bold;">implements</span> CameraBridgeViewBase<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">CvCameraViewListener2</span> <span style="color: rgb(102, 102, 102);">{</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">//...</span>
<span style="color: rgb(170, 34, 255);">@Override</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">public</span> Mat <span style="color: rgb(0, 0, 255);">onCameraFrame</span><span style="color: rgb(102, 102, 102);">(</span>CameraBridgeViewBase<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">CvCameraViewFrame</span> inputFrame<span style="color: rgb(102, 102, 102);">)</span> <span style="color: rgb(102, 102, 102);">{</span>
Mat src <span style="color: rgb(102, 102, 102);">=</span> inputFrame<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">gray</span><span style="color: rgb(102, 102, 102);">();</span> <span style="color: rgb(64, 128, 128); font-style: italic;">// convertir a escala de grises</span>
Mat cannyEdges <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> Mat<span style="color: rgb(102, 102, 102);">();</span> <span style="color: rgb(64, 128, 128); font-style: italic;">// objeto para almacenar el resultado</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// aplicar el algoritmo canny para detectar los bordes</span>
Imgproc<span style="color: rgb(102, 102, 102);">.</span><span style="color: rgb(125, 144, 41);">Canny</span><span style="color: rgb(102, 102, 102);">(</span>src<span style="color: rgb(102, 102, 102);">,</span> cannyEdges<span style="color: rgb(102, 102, 102);">,</span> <span style="color: rgb(102, 102, 102);">10,</span> <span style="color: rgb(102, 102, 102);">100);</span>
<span style="color: rgb(64, 128, 128); font-style: italic;">// devolver el objeto Mat procesado</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">return</span> cannyEdges<span style="color: rgb(102, 102, 102);">;</span>
<span style="color: rgb(102, 102, 102);">}</span>
<span style="color: rgb(102, 102, 102);">}</span>
</code></pre></div><p>Ahora obtendremos una imagen binaria que el resultado de aplicar el algoritmo Canny.</p><p>Para poder acceder a la cámara requerimos permisos por lo que debemos modificar el manifiesto de nuestra aplicación el cual quedara del siguiente modo:</p><div class="code-painter"> <pre><code><span style="color: rgb(188, 122, 0);"><?xml version="1.0" encoding="utf-8"?></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><manifest</span> <span style="color: rgb(125, 144, 41);">xmlns:android=</span><span style="color: rgb(186, 33, 33);">"http://schemas.android.com/apk/res/android"</span>
<span style="color: rgb(125, 144, 41);">package=</span><span style="color: rgb(186, 33, 33);">"programacion.tutor.opencvandroid"</span><span style="color: rgb(0, 128, 0); font-weight: bold;">></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><application</span>
<span style="color: rgb(125, 144, 41);">android:allowBackup=</span><span style="color: rgb(186, 33, 33);">"true"</span>
<span style="color: rgb(125, 144, 41);">android:icon=</span><span style="color: rgb(186, 33, 33);">"@mipmap/ic_launcher"</span>
<span style="color: rgb(125, 144, 41);">android:label=</span><span style="color: rgb(186, 33, 33);">"@string/app_name"</span>
<span style="color: rgb(125, 144, 41);">android:roundIcon=</span><span style="color: rgb(186, 33, 33);">"@mipmap/ic_launcher_round"</span>
<span style="color: rgb(125, 144, 41);">android:supportsRtl=</span><span style="color: rgb(186, 33, 33);">"true"</span>
<span style="color: rgb(125, 144, 41);">android:theme=</span><span style="color: rgb(186, 33, 33);">"@style/AppTheme"</span><span style="color: rgb(0, 128, 0); font-weight: bold;">></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><activity</span> <span style="color: rgb(125, 144, 41);">android:name=</span><span style="color: rgb(186, 33, 33);">".OpenCVActivity"</span><span style="color: rgb(0, 128, 0); font-weight: bold;">></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><intent-filter></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><action</span> <span style="color: rgb(125, 144, 41);">android:name=</span><span style="color: rgb(186, 33, 33);">"android.intent.action.MAIN"</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">/></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><category</span> <span style="color: rgb(125, 144, 41);">android:name=</span><span style="color: rgb(186, 33, 33);">"android.intent.category.LAUNCHER"</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">/></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"></intent-filter></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"></activity></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"></application></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><uses-permission</span> <span style="color: rgb(125, 144, 41);">android:name=</span><span style="color: rgb(186, 33, 33);">"android.permission.CAMERA"</span><span style="color: rgb(0, 128, 0); font-weight: bold;">/></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><uses-feature</span> <span style="color: rgb(125, 144, 41);">android:name=</span><span style="color: rgb(186, 33, 33);">"android.hardware.camera"</span> <span style="color: rgb(125, 144, 41);">android:required=</span><span style="color: rgb(186, 33, 33);">"false"</span><span style="color: rgb(0, 128, 0); font-weight: bold;">/></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><uses-feature</span> <span style="color: rgb(125, 144, 41);">android:name=</span><span style="color: rgb(186, 33, 33);">"android.hardware.camera.autofocus"</span> <span style="color: rgb(125, 144, 41);">android:required=</span><span style="color: rgb(186, 33, 33);">"false"</span><span style="color: rgb(0, 128, 0); font-weight: bold;">/></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><uses-feature</span> <span style="color: rgb(125, 144, 41);">android:name=</span><span style="color: rgb(186, 33, 33);">"android.hardware.camera.front"</span> <span style="color: rgb(125, 144, 41);">android:required=</span><span style="color: rgb(186, 33, 33);">"false"</span><span style="color: rgb(0, 128, 0); font-weight: bold;">/></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"><uses-feature</span> <span style="color: rgb(125, 144, 41);">android:name=</span><span style="color: rgb(186, 33, 33);">"android.hardware.camera.front.autofocus"</span> <span style="color: rgb(125, 144, 41);">android:required=</span><span style="color: rgb(186, 33, 33);">"false"</span><span style="color: rgb(0, 128, 0); font-weight: bold;">/></span>
<span style="color: rgb(0, 128, 0); font-weight: bold;"></manifest></span>
</code></pre></div><p>El último paso es copiar el contenido de la carpeta <samp>..\opencv4android\sdk\native\libs</samp> en nuestro proyecto debemos hacerlo en el siguiente directorio <samp>..\OpenCVAndroid\app\src\main\jniLibs</samp> puedes eliminar los archivo con extensión <b>.a</b> solo nos interesa el archivo <b>libopencv_java3.so</b> puedes copiar todas las carpetas o solo aquella que corresponde a la arquitectura de CPU para la cual esta destinada tu aplicación, ejemplos (arm64-v8a, armeabi-v7a, …).</p><p><a href="https://lh3.googleusercontent.com/-dzyKSa9pzgk/WorYCnS9-pI/AAAAAAAAD50/pgw86nY79z0ymeRJKB1HTtOe4NHEvXVqQCHMYCw/s1600-h/image26"><img title="Agregar libreria nativa" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Agregar libreria nativa" src="https://lh3.googleusercontent.com/-yo5PVqlJDfw/WorYDX-uA3I/AAAAAAAAD54/DliPxIo1PkQBuvEPyBrx7jSFVgNBP8A4QCHMYCw/image_thumb8?imgmax=800" width="547" height="313" /></a></p><p>Con esto ya puedes puedes probar tu aplicación en un dispositivo físico, debes recordar que el versiones actuales de la API de Android se requiera otorgar permisos en tiempo de ejecución para acceder a la cámara no hemos agregado este código para hacer lo más simple posible nuestro proyecto pero puedes otorgar el permiso desde tu dispositivo en: <samp>Ajustes | Aplicaciones | <NuestraApp> | Permisos</samp> activar la opción para la cámara.</p><p>Si no tienes el permiso verás un mensaje como este:</p><p><a href="https://lh3.googleusercontent.com/-xaAJkJLbtuw/WorYD3RMJXI/AAAAAAAAD58/5yi5q_KUKYoxKO1DCu-T1fqsXZBVtuutACHMYCw/s1600-h/sin-permiso-para-camara4"><img title="sin permiso para camara" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="sin permiso para camara" src="https://lh3.googleusercontent.com/-LfZ6FwFYwl4/WorYE6pWVpI/AAAAAAAAD6A/X_CdZTETNycG8nllIUrqAmCMAS8O2OHhgCHMYCw/sin-permiso-para-camara_thumb4?imgmax=800" width="220" height="98" /></a></p><p>Cuando ya tengas todo preparado para probar tu aplicación podrás ver algo como esto:</p><p><a href="https://lh3.googleusercontent.com/-L8xfWR2MqrE/WorYFQVpvgI/AAAAAAAAD6E/9H_Aw-eI2rUXf8i6wamJg1qTUa_TxUhqQCHMYCw/s1600-h/app%2Bopencv%255B7%255D"><img title="tutorial app opencv android" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="tutorial app opencv android" src="https://lh3.googleusercontent.com/-VvcHZsE4cLU/WorYGPsEGTI/AAAAAAAAD6I/wzTWaZWZdH0z7fFW3_M1E42jbwApS95QQCHMYCw/app%2Bopencv_thumb%255B7%255D?imgmax=800" width="960" height="540" /></a></p><p>En tiempo real se muestra la captura de la cámara del dispositivo, esta es procesada por al algoritmo de detección de bordes Canny implementado por OpenCV, debes tener presente que el componente <code>JavaCameraView</code> esta diseñado para trabajar en modo landscape.</p><p>Descargar código fuente: <a href="https://github.com/TutorProgramacion/tutoriales-programacion/raw/master/opencv/android/2018/OpenCVAndroid.zip" target="_blank">opencv-android.zip</a> (no están incluidas las librerías nativas en la carpeta jniLibs)</p>Unknownnoreply@blogger.com18tag:blogger.com,1999:blog-2590617132675118769.post-47633560215322390042018-02-16T12:44:00.001-08:002018-02-19T06:00:14.268-08:00Compilar el SDK OpenCV para Android<p>Dedicaremos este tutorial a conocer el proceso necesario para compilar la librería OpenCV para Android, al terminar obtendremos el OpenCV4Android SDK requerido para desarrollar aplicaciones de Visión por Computador destinadas a ser utilizadas en dispositivos móviles con sistema operativo Android, con este SDK podremos crear aplicaciones de reconocimiento de objetos, caras, etc., realidad aumentada, aprendizaje automático y otros.</p> <a name='more'></a> <p><a href="https://lh3.googleusercontent.com/-uZrHolQc090/WodCe2uBh2I/AAAAAAAAD3w/Ig0tibmUSVwaFMMg9NCNVAkeHB8LxIjvgCHMYCw/s1600-h/opencv4android%255B8%255D"><img title="opencv4android" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="opencv4android" src="https://lh3.googleusercontent.com/-TzUg7jfmvlE/WodCfhxmdYI/AAAAAAAAD30/JIn7TtyUAdYLvceH1JakBepm1tX5hoGiwCHMYCw/opencv4android_thumb%255B6%255D?imgmax=800" width="549" height="377" /></a></p> <p>Para empezar primero debemos instalar las herramientas necesarias para compilar en Windows:</p> <ul> <li><a href="https://opencv.org/releases.html" target="_blank">Código fuente</a> de OpenCV (para este tutorial usare la versión 3.3.0)</li> <li><a href="https://cmake.org/download/" target="_blank">CMake</a> (requerido para generar el proyecto, versión 3+)</li> <li>MinGW (puedes <a href="http://acodigo.blogspot.com/2017/05/instalar-compilador-gnu-gcc-en-windows.html" target="_blank">instalarlo vía msys2</a>, en mi caso uso las herramientas incluidas en Qt-5 asegúrate de agregar la carpeta <samp><mingw>/bin</samp> a la variable de entorno PATH) </li> <li><a href="http://ant.apache.org/bindownload.cgi?Prefer" target="_blank">Apache Ant</a> (agregar la variable de sistema ANT_HOME apuntando a la carpeta descomprimida <samp><ant></samp> también será necesario agregar la carpeta <samp><ant>/bin</samp> a la variable de entorno PATH)</li> <li><a href="http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html" target="_blank">Java JDK</a> (instalar y agregar la ruta a la variable de sistema PATH)</li> <li><a href="https://developer.android.com/ndk/downloads/index.html?hl=es-419" target="_blank">Android NDK</a> (agregar la variable de sistema ANDROID_NDK apuntando a la carpeta descomprimida)</li> <li><a href="https://www.python.org/downloads/" target="_blank">Python 2.x</a> (instalar y agregar la ruta a la variable de sistema PATH)</li> </ul> <p>Lo primero, luego de haber descargado he instalado las herramientas previamente mencionadas será abrir CMake he indicar mediante el botón <em>Browse Source…</em> la carpeta en la que descomprimimos el código fuente de OpenCV, también utilizaremos el <em>Browse Build…</em> para seleccionar la carpeta en donde se guardará el proyecto.</p> <p>Presionamos <em>Configure</em> y seleccionamos el generador <strong>MinGW Makefiles</strong> tambien nos aseguramos de activar la opción <strong>Specify toolchain file for cross-compiling</strong>.</p> <p><a href="https://lh3.googleusercontent.com/-oBfHUmyh4TE/WodCgf84wyI/AAAAAAAAD34/11GfS_qDOu0XWhRlelkZNGKkXaxgDUt-gCHMYCw/s1600-h/image2"><img title="OpenCV4Andriod SDK CMake" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="OpenCV4Andriod SDK CMake" src="https://lh3.googleusercontent.com/-BltEBL5Q53M/WodChHnU-oI/AAAAAAAAD38/-Ccmr0G7bLMCQidQg_A-8P3LMWiIHeO3ACHMYCw/image_thumb?imgmax=800" width="518" height="369" /></a></p> <p>El la siguiente ventana seleccionamos el archivo <strong>android.toolchain.cmake</strong> que se encuentra en la carpeta <samp>/opencv-3.3.0/platform/android/</samp> para finalizar presionamos el botón Finish.</p> <p><a href="https://lh3.googleusercontent.com/-jtdGCbBitvw/WodCh9e1rVI/AAAAAAAAD4A/jzkWZRuI63U_yQMDGnznMGQIa8awfVBhQCHMYCw/s1600-h/image5"><img title="OpenCV Android toolchain" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="OpenCV Android toolchain" src="https://lh3.googleusercontent.com/-28cr1EoL3Cw/WodCi_cf-GI/AAAAAAAAD4E/ixum2TwojS0mXMPHV6qQCQpRfBCh_nS0QCHMYCw/image_thumb1?imgmax=800" width="518" height="269" /></a></p> <p>Si todo esta correcto veremos el mensaje <em>Configuring done</em> al final, de ser así procedemos haciendo clic en el botón <strong>Generate</strong>, esperamos a que termine el proceso y abrimos la carpeta en donde indicamos se debía guardar el proyecto.</p> <p><a href="https://lh3.googleusercontent.com/-bEFJgFE74Fc/WodCjlHfwYI/AAAAAAAAD4I/tBRxj8V_1yIWxitrR3JtPp0G8XDaJcTOACHMYCw/s1600-h/image6"><img title="Generar OpenCV para Android" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Generar OpenCV para Android" src="https://lh3.googleusercontent.com/-gFn9Mc5cmGI/WodClzIgdsI/AAAAAAAAD4M/VzrzEL1lW0gTCZhgz6abNLu5sF3NIa4VgCHMYCw/image_thumb2?imgmax=800" width="787" height="530" /></a></p> <p>Si se muestra un mensaje de error indicando que no ha podido localizar alguna herramienta debes asegurarte de haberla agregado correctamente al PATH o también pueden indicarla manualmente a través de la GUI de CMake.</p> <p>El siguiente paso es dirigirse al la carpeta en donde se genero el proyecto, una vez en ella abres una ventana de comando CMD puedes hacer clic en el botón archivo ubicado en la parte superior derecha del explorador y seleccionar abrir ventana de comandos aquí, debes ejecutar el siguiente comando:</p> <div class="code-painter"> <pre><code>mingw32-make
</code></pre>
</div>
<p><a href="https://lh3.googleusercontent.com/-gPuo1pl7dHY/WodCmu5IedI/AAAAAAAAD4Q/cyhXDW4piuwaUlAeMFEaJsC9Ooa4Q4fKgCHMYCw/s1600-h/image%255B3%255D"><img title="Compilar OpenCV para Android" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Compilar OpenCV para Android" src="https://lh3.googleusercontent.com/-8vXuldqIt8E/WodCnvEBwYI/AAAAAAAAD4U/NlBAcBFL7YYtrrJNk4JVRIRwrN7iftjdQCHMYCw/image_thumb%255B1%255D?imgmax=800" width="942" height="570" /></a></p>
<p>Si todo finaliza de manera correcta ejecutamos en siguiente comando que nos permitirá generar la carpeta que contiene todos los archivos necesarios para programar aplicaciones OpenCV desde Android. </p>
<div class="code-painter">
<pre><code>mingw32-make install
</code></pre>
</div>
<p>Los resultados serán almacenados en la carpeta indicada en CMAKE_INSTALL_PREFIX por defecto es la carpeta <em>install</em> ubicada en la misma carpeta en donde indicaste se debía guardar el proyecto. </p>
<div class="code-painter">
<pre><code>-install
+-apk
+-sdk
+-LICENSE
+-README.android
</code></pre>
</div>
<p>Finalizamos por ahora, ya estamos preparados para utilizar OpenCV en Android pero eso será para la próxima.</p>
<p>Siguiente tutorial: <a href="http://acodigo.blogspot.com/2018/02/programacion-opencv-para-android.html" target="_blank">Mi primera aplicación Android OpenCV</a></p>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2590617132675118769.post-45449986399229913842018-01-29T07:46:00.001-08:002018-01-29T07:50:39.508-08:00Obtener esqueleto de imagen binaria<p>Se le llama <a href="https://es.wikipedia.org/wiki/C%C3%A1lculo_del_esqueleto" target="_blank">esqueleto</a> de una imagen a un conjunto de curvas centradas que surge de reducir la forma original. El cálculo del esqueleto es una herramienta de análisis no escalar de formas, que conserva las propiedades topológicas de la forma original así como las propiedades geométricas, según el método utilizado. El esqueleto también es conocido como eje medio y tiene diversas aplicaciones, por ejemplo: reconocimiento de letras, números o símbolos, identificación de huellas dactilares, y muchas otras.</p><a name='more'></a> <p>En color verde podemos ver el esqueleto de una estrella.</p><p><a href="https://lh3.googleusercontent.com/-Fcd2kNLTCxw/Wm9B0mQlJYI/AAAAAAAAD3M/YPPIivJJ4fUxF6rMEOtdstYgec31vgRdgCHMYCw/s1600-h/opencv%2Besqueleto%2Bo%2Beje%2Bmedio%255B2%255D"><img title="opencv esqueleto o eje medio" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="opencv esqueleto o eje medio" src="https://lh3.googleusercontent.com/-RIxdxRT_FxQ/Wm9B1RAAt2I/AAAAAAAAD3Q/4vupF2tTH2InbDpuhc8O5anaCGMAKuQkwCHMYCw/opencv%2Besqueleto%2Bo%2Beje%2Bmedio_thumb?imgmax=800" width="1182" height="542" /></a></p><p>Para esta tarea usaremos los algoritmos de adelgazamiento propuestos por Zhang Suen y Guo Hall ambos son similares con pequeñas variaciones, las implementaciones de dichos algoritmos las he tomado de el módulo <a href="https://github.com/opencv/opencv_contrib/tree/master/modules/ximgproc" target="_blank">ximgproc</a> por lo que si tienes este módulo compilado en tu versión OpenCV puedes usarlo directamente.</p><p>En esta web puedes encontrar una explicación del algoritmo de Zhang Suen: <a title="http://www.tecnohobby.net/ppal/index.php/vision-computacional/topicos-generales/2-algoritmo-de-zhang-suen" href="http://www.tecnohobby.net/ppal/index.php/vision-computacional/topicos-generales/2-algoritmo-de-zhang-suen">http://www.tecnohobby.net/ppal/index.php/vision-computacional/topicos-generales/2-algoritmo-de-zhang-suen</a></p><p>El código C++ para ambos algoritmos es el siguiente: </p><div class="code-painter"><pre><code><span style="color: rgb(64, 128, 128); font-style: italic;">// Applies a thinning iteration to a binary image</span>
<span style="color: rgb(0, 128, 0); font-weight: bold;">static</span> <span style="color: rgb(176, 0, 64);">void</span> <span style="color: rgb(0, 0, 255);">thinningIteration</span>(Mat img, <span style="color: rgb(176, 0, 64);">int</span> iter, <span style="color: rgb(176, 0, 64);">int</span> thinningType) {
Mat marker <span style="color: rgb(102, 102, 102);">=</span> Mat<span style="color: rgb(102, 102, 102);">::</span>zeros(img.size(), CV_8UC1);
<span style="color: rgb(0, 128, 0); font-weight: bold;">if</span> (thinningType <span style="color: rgb(102, 102, 102);">==</span> THINNING_ZHANGSUEN) {
<span style="color: rgb(0, 128, 0); font-weight: bold;">for</span> (<span style="color: rgb(176, 0, 64);">int</span> i <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(102, 102, 102);">1</span>; i <span style="color: rgb(102, 102, 102);"><</span> img.rows <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>; i<span style="color: rgb(102, 102, 102);">++</span>)
{
<span style="color: rgb(0, 128, 0); font-weight: bold;">for</span> (<span style="color: rgb(176, 0, 64);">int</span> j <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(102, 102, 102);">1</span>; j <span style="color: rgb(102, 102, 102);"><</span> img.cols <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>; j<span style="color: rgb(102, 102, 102);">++</span>)
{
uchar p2 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>, j);
uchar p3 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>, j <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">1</span>);
uchar p4 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i, j <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">1</span>);
uchar p5 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">1</span>, j <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">1</span>);
uchar p6 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">1</span>, j);
uchar p7 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">1</span>, j <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>);
uchar p8 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i, j <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>);
uchar p9 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>, j <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>);
<span style="color: rgb(176, 0, 64);">int</span> A <span style="color: rgb(102, 102, 102);">=</span> (p2 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">0</span> <span style="color: rgb(102, 102, 102);">&&</span> p3 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">1</span>) <span style="color: rgb(102, 102, 102);">+</span> (p3 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">0</span> <span style="color: rgb(102, 102, 102);">&&</span> p4 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">1</span>) <span style="color: rgb(102, 102, 102);">+</span>
(p4 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">0</span> <span style="color: rgb(102, 102, 102);">&&</span> p5 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">1</span>) <span style="color: rgb(102, 102, 102);">+</span> (p5 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">0</span> <span style="color: rgb(102, 102, 102);">&&</span> p6 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">1</span>) <span style="color: rgb(102, 102, 102);">+</span>
(p6 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">0</span> <span style="color: rgb(102, 102, 102);">&&</span> p7 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">1</span>) <span style="color: rgb(102, 102, 102);">+</span> (p7 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">0</span> <span style="color: rgb(102, 102, 102);">&&</span> p8 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">1</span>) <span style="color: rgb(102, 102, 102);">+</span>
(p8 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">0</span> <span style="color: rgb(102, 102, 102);">&&</span> p9 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">1</span>) <span style="color: rgb(102, 102, 102);">+</span> (p9 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">0</span> <span style="color: rgb(102, 102, 102);">&&</span> p2 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">1</span>);
<span style="color: rgb(176, 0, 64);">int</span> B <span style="color: rgb(102, 102, 102);">=</span> p2 <span style="color: rgb(102, 102, 102);">+</span> p3 <span style="color: rgb(102, 102, 102);">+</span> p4 <span style="color: rgb(102, 102, 102);">+</span> p5 <span style="color: rgb(102, 102, 102);">+</span> p6 <span style="color: rgb(102, 102, 102);">+</span> p7 <span style="color: rgb(102, 102, 102);">+</span> p8 <span style="color: rgb(102, 102, 102);">+</span> p9;
<span style="color: rgb(176, 0, 64);">int</span> m1 <span style="color: rgb(102, 102, 102);">=</span> iter <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">0</span> <span style="color: rgb(102, 102, 102);">?</span> (p2 <span style="color: rgb(102, 102, 102);">*</span> p4 <span style="color: rgb(102, 102, 102);">*</span> p6) <span style="color: rgb(102, 102, 102);">:</span> (p2 <span style="color: rgb(102, 102, 102);">*</span> p4 <span style="color: rgb(102, 102, 102);">*</span> p8);
<span style="color: rgb(176, 0, 64);">int</span> m2 <span style="color: rgb(102, 102, 102);">=</span> iter <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">0</span> <span style="color: rgb(102, 102, 102);">?</span> (p4 <span style="color: rgb(102, 102, 102);">*</span> p6 <span style="color: rgb(102, 102, 102);">*</span> p8) <span style="color: rgb(102, 102, 102);">:</span> (p2 <span style="color: rgb(102, 102, 102);">*</span> p6 <span style="color: rgb(102, 102, 102);">*</span> p8);
<span style="color: rgb(0, 128, 0); font-weight: bold;">if</span> (A <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">1</span> <span style="color: rgb(102, 102, 102);">&&</span> (B <span style="color: rgb(102, 102, 102);">>=</span> <span style="color: rgb(102, 102, 102);">2</span> <span style="color: rgb(102, 102, 102);">&&</span> B <span style="color: rgb(102, 102, 102);"><=</span> <span style="color: rgb(102, 102, 102);">6</span>) <span style="color: rgb(102, 102, 102);">&&</span> m1 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">0</span> <span style="color: rgb(102, 102, 102);">&&</span> m2 <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">0</span>)
marker.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i, j) <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(102, 102, 102);">1</span>;
}
}
}
<span style="color: rgb(0, 128, 0); font-weight: bold;">if</span> (thinningType <span style="color: rgb(102, 102, 102);">==</span> THINNING_GUOHALL) {
<span style="color: rgb(0, 128, 0); font-weight: bold;">for</span> (<span style="color: rgb(176, 0, 64);">int</span> i <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(102, 102, 102);">1</span>; i <span style="color: rgb(102, 102, 102);"><</span> img.rows <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>; i<span style="color: rgb(102, 102, 102);">++</span>)
{
<span style="color: rgb(0, 128, 0); font-weight: bold;">for</span> (<span style="color: rgb(176, 0, 64);">int</span> j <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(102, 102, 102);">1</span>; j <span style="color: rgb(102, 102, 102);"><</span> img.cols <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>; j<span style="color: rgb(102, 102, 102);">++</span>)
{
uchar p2 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>, j);
uchar p3 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>, j <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">1</span>);
uchar p4 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i, j <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">1</span>);
uchar p5 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">1</span>, j <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">1</span>);
uchar p6 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">1</span>, j);
uchar p7 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i <span style="color: rgb(102, 102, 102);">+</span> <span style="color: rgb(102, 102, 102);">1</span>, j <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>);
uchar p8 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i, j <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>);
uchar p9 <span style="color: rgb(102, 102, 102);">=</span> img.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>, j <span style="color: rgb(102, 102, 102);">-</span> <span style="color: rgb(102, 102, 102);">1</span>);
<span style="color: rgb(176, 0, 64);">int</span> C <span style="color: rgb(102, 102, 102);">=</span> ((<span style="color: rgb(102, 102, 102);">!</span>p2) <span style="color: rgb(102, 102, 102);">&</span> (p3 <span style="color: rgb(102, 102, 102);">|</span> p4)) <span style="color: rgb(102, 102, 102);">+</span> ((<span style="color: rgb(102, 102, 102);">!</span>p4) <span style="color: rgb(102, 102, 102);">&</span> (p5 <span style="color: rgb(102, 102, 102);">|</span> p6)) <span style="color: rgb(102, 102, 102);">+</span>
((<span style="color: rgb(102, 102, 102);">!</span>p6) <span style="color: rgb(102, 102, 102);">&</span> (p7 <span style="color: rgb(102, 102, 102);">|</span> p8)) <span style="color: rgb(102, 102, 102);">+</span> ((<span style="color: rgb(102, 102, 102);">!</span>p8) <span style="color: rgb(102, 102, 102);">&</span> (p9 <span style="color: rgb(102, 102, 102);">|</span> p2));
<span style="color: rgb(176, 0, 64);">int</span> N1 <span style="color: rgb(102, 102, 102);">=</span> (p9 <span style="color: rgb(102, 102, 102);">|</span> p2) <span style="color: rgb(102, 102, 102);">+</span> (p3 <span style="color: rgb(102, 102, 102);">|</span> p4) <span style="color: rgb(102, 102, 102);">+</span> (p5 <span style="color: rgb(102, 102, 102);">|</span> p6) <span style="color: rgb(102, 102, 102);">+</span> (p7 <span style="color: rgb(102, 102, 102);">|</span> p8);
<span style="color: rgb(176, 0, 64);">int</span> N2 <span style="color: rgb(102, 102, 102);">=</span> (p2 <span style="color: rgb(102, 102, 102);">|</span> p3) <span style="color: rgb(102, 102, 102);">+</span> (p4 <span style="color: rgb(102, 102, 102);">|</span> p5) <span style="color: rgb(102, 102, 102);">+</span> (p6 <span style="color: rgb(102, 102, 102);">|</span> p7) <span style="color: rgb(102, 102, 102);">+</span> (p8 <span style="color: rgb(102, 102, 102);">|</span> p9);
<span style="color: rgb(176, 0, 64);">int</span> N <span style="color: rgb(102, 102, 102);">=</span> N1 <span style="color: rgb(102, 102, 102);"><</span> N2 <span style="color: rgb(102, 102, 102);">?</span> <span style="color: rgb(160, 160, 0);">N1</span> : N2;
<span style="color: rgb(176, 0, 64);">int</span> m <span style="color: rgb(102, 102, 102);">=</span> iter <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">0</span> <span style="color: rgb(102, 102, 102);">?</span> ((p6 <span style="color: rgb(102, 102, 102);">|</span> p7 <span style="color: rgb(102, 102, 102);">|</span> (<span style="color: rgb(102, 102, 102);">!</span>p9)) <span style="color: rgb(102, 102, 102);">&</span> p8) <span style="color: rgb(102, 102, 102);">:</span> ((p2 <span style="color: rgb(102, 102, 102);">|</span> p3 <span style="color: rgb(102, 102, 102);">|</span> (<span style="color: rgb(102, 102, 102);">!</span>p5)) <span style="color: rgb(102, 102, 102);">&</span> p4);
<span style="color: rgb(0, 128, 0); font-weight: bold;">if</span> ((C <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">1</span>) <span style="color: rgb(102, 102, 102);">&&</span> ((N <span style="color: rgb(102, 102, 102);">>=</span> <span style="color: rgb(102, 102, 102);">2</span>) <span style="color: rgb(102, 102, 102);">&&</span> ((N <span style="color: rgb(102, 102, 102);"><=</span> <span style="color: rgb(102, 102, 102);">3</span>)) <span style="color: rgb(102, 102, 102);">&</span> (m <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">0</span>)))
marker.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(i, j) <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(102, 102, 102);">1</span>;
}
}
}
img <span style="color: rgb(102, 102, 102);">&=</span> <span style="color: rgb(102, 102, 102);">~</span>marker;
}
<span style="color: rgb(64, 128, 128); font-style: italic;">// Apply the thinning procedure to a given image</span>
<span style="color: rgb(176, 0, 64);">void</span> <span style="color: rgb(0, 0, 255);">thinning</span>(InputArray input, OutputArray output, <span style="color: rgb(176, 0, 64);">int</span> thinningType) {
Mat processed <span style="color: rgb(102, 102, 102);">=</span> input.getMat().clone();
<span style="color: rgb(64, 128, 128); font-style: italic;">// Enforce the range of the input image to be in between 0 - 255</span>
processed <span style="color: rgb(102, 102, 102);">/=</span> <span style="color: rgb(102, 102, 102);">255</span>;
Mat prev <span style="color: rgb(102, 102, 102);">=</span> Mat<span style="color: rgb(102, 102, 102);">::</span>zeros(processed.size(), CV_8UC1);
Mat diff;
<span style="color: rgb(0, 128, 0); font-weight: bold;">do</span> {
thinningIteration(processed, <span style="color: rgb(102, 102, 102);">0</span>, thinningType);
thinningIteration(processed, <span style="color: rgb(102, 102, 102);">1</span>, thinningType);
absdiff(processed, prev, diff);
processed.copyTo(prev);
} <span style="color: rgb(0, 128, 0); font-weight: bold;">while</span> (countNonZero(diff) <span style="color: rgb(102, 102, 102);">></span> <span style="color: rgb(102, 102, 102);">0</span>);
processed <span style="color: rgb(102, 102, 102);">*=</span> <span style="color: rgb(102, 102, 102);">255</span>;
output.assign(processed);
}
</code></pre></div><p>Como podemos ver y como se explica en la web antes mencionada este es un algoritmo iterativo que busca adelgazar la figura hasta obtener el respectivo esqueleto de grosor 1 pixel, para especificar el método a utilizar usamos la <var>thinningType</var> con valor igual a 1 usaremos Zhang Suen y con valor igual a 2 Guo Hall.</p><div class="code-painter"> <pre><code><span style="color: rgb(176, 0, 64);">int</span> <span style="color: rgb(0, 0, 255);">main</span>(<span style="color: rgb(176, 0, 64);">int</span> argc, <span style="color: rgb(176, 0, 64);">char</span><span style="color: rgb(102, 102, 102);">**</span> argv)
{
Mat image <span style="color: rgb(102, 102, 102);">=</span> imread(<span style="color: rgb(186, 33, 33);">"../star.jpg"</span>, CV_LOAD_IMAGE_GRAYSCALE);
<span style="color: rgb(64, 128, 128); font-style: italic;">// clonar imagen original</span>
Mat src <span style="color: rgb(102, 102, 102);">=</span> image.clone();
<span style="color: rgb(64, 128, 128); font-style: italic;">// obtener el esqueleto</span>
thinning(src, src, <span style="color: rgb(102, 102, 102);">2</span>);
<span style="color: rgb(64, 128, 128); font-style: italic;">// 1. dibujar el esqueleto a color verde sobre la imagen original</span>
cvtColor(image, image, CV_GRAY2BGR);
<span style="color: rgb(0, 128, 0); font-weight: bold;">for</span> (<span style="color: rgb(176, 0, 64);">int</span> i <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(102, 102, 102);">0</span>; i <span style="color: rgb(102, 102, 102);"><</span> image.cols; i<span style="color: rgb(102, 102, 102);">++</span>)
{
<span style="color: rgb(0, 128, 0); font-weight: bold;">for</span> (<span style="color: rgb(176, 0, 64);">int</span> j <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(102, 102, 102);">0</span>; j <span style="color: rgb(102, 102, 102);"><</span> image.rows; j<span style="color: rgb(102, 102, 102);">++</span>)
{
Scalar intensity <span style="color: rgb(102, 102, 102);">=</span> src.at<span style="color: rgb(102, 102, 102);"><</span>uchar<span style="color: rgb(102, 102, 102);">></span>(j, i);
<span style="color: rgb(0, 128, 0); font-weight: bold;">if</span> (intensity.val[<span style="color: rgb(102, 102, 102);">0</span>] <span style="color: rgb(102, 102, 102);">==</span> <span style="color: rgb(102, 102, 102);">255</span>) {
image.at<span style="color: rgb(102, 102, 102);"><</span>Vec3b<span style="color: rgb(102, 102, 102);">></span>(j, i) <span style="color: rgb(102, 102, 102);">=</span> Vec3b(<span style="color: rgb(102, 102, 102);">0</span>, <span style="color: rgb(102, 102, 102);">255</span>, <span style="color: rgb(102, 102, 102);">0</span>);
}
}
}
<span style="color: rgb(64, 128, 128); font-style: italic;">// end 1</span>
imshow(<span style="color: rgb(186, 33, 33);">"OpenCV Skeleton Final"</span>, src);
imshow(<span style="color: rgb(186, 33, 33);">"Original Skeleton Final"</span>, image);
waitKey(<span style="color: rgb(102, 102, 102);">0</span>);
<span style="color: rgb(0, 128, 0); font-weight: bold;">return</span> <span style="color: rgb(102, 102, 102);">0</span>;
}
</code></pre></div><p>El proceso de adelgazamiento para llegar al eje medio se puede apreciar en la siguiente animación:</p><p><a href="https://lh3.googleusercontent.com/-2750DPPlhwo/Wm9B2uew4oI/AAAAAAAAD3U/x4Izs92DTrUACRbHOask56cApWpZPtbAwCHMYCw/s1600-h/opencv-esqueleto%255B3%255D"><img title="opencv-esqueleto" style="margin-right: auto; margin-left: auto; float: none; display: block;" alt="opencv-esqueleto" src="https://lh3.googleusercontent.com/-8Kj87rOxqgA/Wm9B3yHF5QI/AAAAAAAAD3Y/1xVsprSe0wIEhrtZ4vjdrPGKPWRpDhrIQCHMYCw/opencv-esqueleto_thumb%255B1%255D?imgmax=800" width="360" height="270" /></a></p><p>Otro método utilizado para calcular el esqueleto de una imagen es mediante <a href="http://acodigo.blogspot.com/2017/04/opencv-operaciones-morfologicas.html" target="_blank">operaciones morfológicas</a> de erosión y dilatación, puedes ver el siguiente enlace: <a title="http://felix.abecassis.me/2011/09/opencv-morphological-skeleton/" href="http://felix.abecassis.me/2011/09/opencv-morphological-skeleton/">http://felix.abecassis.me/2011/09/opencv-morphological-skeleton/</a> </p><ul><li>Descargar código fuente: <a href="https://github.com/TutorProgramacion/tutoriales-programacion/raw/master/opencv/cpp/2018/opencv-esqueleto.zip" target="_blank">opencv-esqueleto.zip</a></li>
<li>Ver en GitHub: <a href="https://github.com/TutorProgramacion/tutoriales-opencv/tree/master/opencv-esqueleto" target="_blank">opencv-esqueleto-src</a></li>
</ul>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2590617132675118769.post-86907376150436772742018-01-25T06:56:00.001-08:002018-01-25T07:03:43.065-08:00Uso de la clase QSettings<p>La clase <code>QSettings</code> del framework <b>Qt</b> nos permitirá guardar las configuraciones de nuestra aplicación ya sea en el registro o en un archivo de configuración .ini, por ejemplo, podemos guardar el tamaño y posición de la ventana para que cuando el usuario abra nuevamente la aplicación esta se muestra en la misma posición y tamaño que el usuario había configurado posteriormente, del mismo modo podemos guardar todo tipo de información y recuperarla posteriormente.</p><a name='more'></a> <p>Para este tutorial vamos a construir una pequeña aplicación, la misma se verá de la siguiente manera:</p><a href="https://lh3.googleusercontent.com/-O_30gGsL2IM/WmnwJheiQOI/AAAAAAAAD2s/a-ZZTEfyOjgVcyAWpZycQOj_28dXt2I1wCHMYCw/s1600-h/image15"><img title="Qt5 uso de la clase QSettings" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Qt5 uso de la clase QSettings" src="https://lh3.googleusercontent.com/-TzgbzZBocsE/WmnwKxuLQJI/AAAAAAAAD2w/u09J0_O_Fukt-ugCRBlNjc7jh5bPT-m8wCHMYCw/image_thumb13?imgmax=800" width="648" height="424" /></a> <p>La idea es que podamos configurar la fuente del texto y guardar esta configuración antes de cerrar la aplicación de este modo cuando se abra la aplicación nuevamente recuperamos los datos y ponemos la configuración de la fuente al estado anterior. </p><p>El código que crea la GUI es el siguiente:</p><div class="code-painter"><pre><code>font <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> QFontComboBox;
font<span style="color: rgb(102, 102, 102);">-></span>setFontFilters(QFontComboBox<span style="color: rgb(102, 102, 102);">::</span>ScalableFonts);
size <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> QComboBox;
size<span style="color: rgb(102, 102, 102);">-></span>setMaximumWidth(<span style="color: rgb(102, 102, 102);">100</span>);
<span style="color: rgb(0, 128, 0); font-weight: bold;">for</span>(<span style="color: rgb(176, 0, 64);">int</span> n <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(102, 102, 102);">5</span>; n <span style="color: rgb(102, 102, 102);"><=</span> <span style="color: rgb(102, 102, 102);">100</span>; n <span style="color: rgb(102, 102, 102);">+=</span> <span style="color: rgb(102, 102, 102);">5</span>) size<span style="color: rgb(102, 102, 102);">-></span>addItem(QVariant(n).toString());
label <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> QLabel;
label<span style="color: rgb(102, 102, 102);">-></span>setText(<span style="color: rgb(186, 33, 33);">"Tutorial QSettings"</span>);
label<span style="color: rgb(102, 102, 102);">-></span>setAlignment(Qt<span style="color: rgb(102, 102, 102);">::</span>AlignCenter);
QHBoxLayout <span style="color: rgb(102, 102, 102);">*</span>fontLayout <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> QHBoxLayout;
fontLayout<span style="color: rgb(102, 102, 102);">-></span>addWidget(font);
fontLayout<span style="color: rgb(102, 102, 102);">-></span>addWidget(size);
QVBoxLayout <span style="color: rgb(102, 102, 102);">*</span>root <span style="color: rgb(102, 102, 102);">=</span> <span style="color: rgb(0, 128, 0); font-weight: bold;">new</span> QVBoxLayout;
root<span style="color: rgb(102, 102, 102);">-></span>addLayout(fontLayout);
root<span style="color: rgb(102, 102, 102);">-></span>addWidget(label);
<span style="color: rgb(0, 128, 0); font-weight: bold;">this</span><span style="color: rgb(102, 102, 102);">-></span>setLayout(root);
</code></pre></div><p>Usaremos tres widgets, un <code>QFontComboBox</code> cuya funcionalidad es mostrar las fuentes que tenemos disponibles en nuestro sistema, el <code>QComboBox</code> lo usaremos para cambiar el tamaño de fuente y el <code>QLabel</code> muestra el texto de ejemplo.</p><h4>Guardar configuración en .ini</h4><p>En nuestro ejemplo usaremos un archivo <samp>.ini</samp> para guardar nuestra configuración, aunque también se pueda guardar en el registro o en una ruta y formato personalizada.</p><p>El momento adecuado para guardar la configuración es antes de cerrar la aplicación para ello agregaremos un manejador para este evento y con la ayuda de la clase <code>QSettings</code> guardamos los datos deseados. </p><div class="code-painter"> <pre><code><span style="color: rgb(176, 0, 64);">void</span> Widget<span style="color: rgb(102, 102, 102);">::</span>closeEvent(QCloseEvent<span style="color: rgb(102, 102, 102);">*</span>)
{
QSettings settings(<span style="color: rgb(186, 33, 33);">"miapp.ini"</span>, QSettings<span style="color: rgb(102, 102, 102);">::</span>IniFormat);
settings.setValue(<span style="color: rgb(186, 33, 33);">"geometry"</span>, <span style="color: rgb(0, 128, 0); font-weight: bold;">this</span><span style="color: rgb(102, 102, 102);">-></span>geometry());
settings.setValue(<span style="color: rgb(186, 33, 33);">"font"</span>, <span style="color: rgb(0, 128, 0); font-weight: bold;">this</span><span style="color: rgb(102, 102, 102);">-></span>font<span style="color: rgb(102, 102, 102);">-></span>currentFont());
settings.setValue(<span style="color: rgb(186, 33, 33);">"fsize"</span>, <span style="color: rgb(0, 128, 0); font-weight: bold;">this</span><span style="color: rgb(102, 102, 102);">-></span>size<span style="color: rgb(102, 102, 102);">-></span>currentText());
}
</code></pre></div><p>En el constructor de la clase indicamos el nombre del archivo y el formato que deseamos utilizar, usando el método <code>setValue(...)</code> guardamos los datos que nos interesen, en nuestro caso guardaremos la fuente, el tamaño y el geometry, este ultimo nos sirve para obtener la posición y tamaño de la ventana.</p><p>Al ejecutar el programa, cambiar la fuente, el tamaño y posición de la ventana cuando cerremos la aplicación se creará un archivo con un contenido similar a este:</p><div class="code-painter"> <pre><code>[General]
geometry=@Rect(435 509 630 378)
font=@Variant(\0\0\0@\0\0\0\x10)
fsize=40
</code></pre></div><p>Ahora solo nos resta recuperar estos datos al momento de iniciar el programa, el proceso es similar salvo que ahora utilizaremos el método <code>value("nombre")</code> para recuperar los datos, solo debemos indicar el nombre del dato deseado y opcionalmente se puede indicar un valor por defecto en caso que de no se encuentre el datos solicitado, usaremos alguno de los métodos <code>toXxx()</code> para realizar la conversión al tipo requerido. </p><div class="code-painter"> <pre><code>QSettings <span style="color: rgb(0, 0, 255);">settings</span>(<span style="color: rgb(186, 33, 33);">"miapp.ini"</span>, QSettings<span style="color: rgb(102, 102, 102);">::</span>IniFormat);
QRect geo <span style="color: rgb(102, 102, 102);">=</span> settings.value(<span style="color: rgb(186, 33, 33);">"geometry"</span>, QRect(<span style="color: rgb(102, 102, 102);">20</span>, <span style="color: rgb(102, 102, 102);">20</span>, <span style="color: rgb(102, 102, 102);">200</span>, <span style="color: rgb(102, 102, 102);">100</span>)).toRect();
QFont fnt <span style="color: rgb(102, 102, 102);">=</span> settings.value(<span style="color: rgb(186, 33, 33);">"font"</span>).value<span style="color: rgb(102, 102, 102);"><</span>QFont<span style="color: rgb(102, 102, 102);">></span>();
QString fsize <span style="color: rgb(102, 102, 102);">=</span> settings.value(<span style="color: rgb(186, 33, 33);">"fsize"</span>).toString();
</code></pre></div><p>El dato <samp>geometry</samp> tiene asignado un valor por defecto, este se asignará al objeto geo en caso de que en el archivo <samp>.ini</samp> no se encuentre el dato correspondiente.</p><p>En caso de que tengamos un método <code>toXxx()</code> correspondiente, por ejemplo en el caso de la fuente <code>(QFont)</code> no existe <code>toFont()</code> por lo que podemos usar <code>value<QFont></code> para realizar la conversión.</p><h4>Guardar en registro de Windows</h4><p>Para almacenar los datos en el registro de Windows solo debemos usar una de las sobrecargas del constructor de la clase <code>QSettings</code> en ella indicaremos dos cadenas de texto, la primera usualmente indica en nombre de la compañía que desarrolla el software y el segundo en nombre del programa, por ejemplo: </p><div class="code-painter"> <pre><code>QSettings <span style="color: rgb(0, 0, 255);">settings</span>(<span style="color: rgb(186, 33, 33);">"TutorProgramacion"</span>, <span style="color: rgb(186, 33, 33);">"TutorialQt"</span>);
</code></pre></div><p>Con esto la configuración será almacenada en la clave de registro:</p><p><samp>HKEY_CURRENT_USER\Software\TutorProgramacion\Qt</samp></p><p><a href="https://lh3.googleusercontent.com/-MVTY3RL3eVw/WmnwMMMT2AI/AAAAAAAAD20/ASqnkUtQn_Y5_TPPZ5_jFt1iqXk-wWtqQCHMYCw/s1600-h/image3"><img title="Qt guardar datos en registro de windows" style="margin: 0px auto; border: 0px currentcolor; border-image: none; float: none; display: block; background-image: none;" border="0" alt="Qt guardar datos en registro de windows" src="https://lh3.googleusercontent.com/-1E3Kvp_Y-M0/WmnwMoTYVWI/AAAAAAAAD24/SlvYbUU94cEscTRkRLmYrLspkjkoZPuYgCHMYCw/image_thumb?imgmax=800" width="887" height="303" /></a></p><p>Todo lo demás queda exactamente igual.</p><p>Descargar código: <a href="https://github.com/TutorProgramacion/tutoriales-programacion/raw/master/qt/2018/tutorial-qsettings.zip" target="_blank">tutorial-qsettings</a></p>Unknownnoreply@blogger.com0