0% encontró este documento útil (0 votos)
331 vistas

OpenCV Python Tutorials Alexander Mordvintsev v1 SP

Este documento presenta una documentación sobre tutoriales de OpenCV-Python. Contiene 11 secciones que cubren introducción a OpenCV, características de la interfaz gráfica de usuario, operaciones básicas, procesamiento de imágenes, detección y descripción de características, análisis de video, calibración de cámara, aprendizaje automático, fotografía computacional, detección de objetos y enlaces de OpenCV-Python. Cada sección explica conceptos y funciones relacionadas con un tema específico de procesamiento

Cargado por

MAAR_naal
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
331 vistas

OpenCV Python Tutorials Alexander Mordvintsev v1 SP

Este documento presenta una documentación sobre tutoriales de OpenCV-Python. Contiene 11 secciones que cubren introducción a OpenCV, características de la interfaz gráfica de usuario, operaciones básicas, procesamiento de imágenes, detección y descripción de características, análisis de video, calibración de cámara, aprendizaje automático, fotografía computacional, detección de objetos y enlaces de OpenCV-Python. Cada sección explica conceptos y funciones relacionadas con un tema específico de procesamiento

Cargado por

MAAR_naal
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 273

Machine Translated by Google

Tutoriales  de  OpenCV­Python
Documentación
Lanzamiento  1

Alexander  Mordvintsev  y  Abid  K.

11  de  abril  de  2017
Machine Translated by Google
Machine Translated by Google

Contenido

1  Tutoriales  de  OpenCV­Python
1.1  Introducción  a  OpenCV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . .
1.2  Características  de  la  interfaz  gráfica  de  usuario  en  OpenCV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3  6 .  
1.3  Operaciones  principales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19  
1.4  Procesamiento  de  imágenes  en  OpenCV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 .  
1.5  Detección  y  descripción  de  características . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 .  
1.6  Análisis  de  vídeo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 .  189
1.7  Calibración  de  cámara  y  reconstrucción  3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  207
1.8  Aprendizaje  automático . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  225 .  
1.9  Fotografía  computacional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 .  
1.10  Detección  de   . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 .  
objetos  1.11  Enlaces  OpenCV­Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264

2  Índices  y  tablas 269

i
Machine Translated by Google

yo
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Contenido:

Contenido 1
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

2 Contenido
Machine Translated by Google

CAPÍTULO  1

Tutoriales  de  OpenCV­Python

•  Introducción  a  OpenCV

¡Aprenda  a  configurar  OpenCV­Python  en  su  computadora!

•  Características  de  la  interfaz  gráfica  de  usuario  en  OpenCV

Aquí  aprenderá  cómo  mostrar  y  guardar  imágenes  y  videos,  controlar  los  eventos  del  mouse  y  crear  
una  barra  de  seguimiento.

•  Operaciones  principales

En  esta  sección  aprenderá  operaciones  básicas  sobre  imágenes  como  edición  de  píxeles,  
transformaciones  geométricas,  optimización  de  código,  algunas  herramientas  matemáticas,  etc.

•  Procesamiento  de  imágenes  en  OpenCV

3
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

En  esta  sección  aprenderá  diferentes  funciones  de  procesamiento  de  imágenes  dentro  de  
OpenCV.

•  Detección  y  descripción  de  características

En  esta  sección  aprenderá  acerca  de  los  detectores  y  descriptores  de  características.

•  Análisis  de  vídeo

En  esta  sección  aprenderá  diferentes  técnicas  para  trabajar  con  videos  como  seguimiento  de  
objetos,  etc.

•  Calibración  de  cámara  y  reconstrucción  3D

En  esta  sección,  aprenderemos  sobre  la  calibración  de  la  cámara,  la  imagen  estéreo,  etc.

•  Aprendizaje  automático

En  esta  sección  aprenderá  diferentes  funciones  de  procesamiento  de  imágenes  dentro  de  
OpenCV.

•  Fotografía  Computacional

En  esta  sección,  aprenderá  diferentes  técnicas  de  fotografía  computacional,  como  eliminar  el  
ruido  de  la  imagen,  etc.

•  Detección  de  objetos

4 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

En  esta  sección,  aprenderá  técnicas  de  detección  de  objetos  como  la  detección  de  rostros,  etc.

•  Enlaces  OpenCV­Python

En  esta  sección,  veremos  cómo  se  generan  los  enlaces  OpenCV­Python

5
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Introducción  a  OpenCV

•  Tutoriales  de  Introducción  a  OpenCV­Python

Primeros  pasos  con  OpenCV­Python

•  Instalar  OpenCV­Python  en  Windows

Configurar  OpenCV­Python  en  Windows

•  Instalar  OpenCV­Python  en  Fedora

Configurar  OpenCV­Python  en  Fedora

6 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Tutoriales  de  Introducción  a  OpenCV­Python

OpenCV

OpenCV  se  inició  en  Intel  en  1999  por  Gary  Bradsky  y  el  primer  lanzamiento  salió  en  2000.  Vadim  Pisarevsky  se  unió  a  Gary  Bradsky  para  
administrar  el  equipo  OpenCV  de  software  ruso  de  Intel.  En  2005,  OpenCV  se  utilizó  en  Stanley,  el  vehículo  que  ganó  el  DARPA  Grand  
Challenge  de  2005.  Posteriormente,  su  desarrollo  activo  continuó  bajo  el  apoyo  de  Willow  Garage,  con  Gary  Bradsky  y  Vadim  Pisarevsky  al  
frente  del  proyecto.  En  este  momento,  OpenCV  admite  una  gran  cantidad  de  algoritmos  relacionados  con  la  visión  artificial  y  el  aprendizaje  
automático  y  se  está  expandiendo  día  a  día.

Actualmente,  OpenCV  admite  una  amplia  variedad  de  lenguajes  de  programación  como  C++,  Python,  Java,  etc.  y  está  disponible  en  
diferentes  plataformas,  incluidas  Windows,  Linux,  OS  X,  Android,  iOS,  etc.  Además,  las  interfaces  basadas  en  CUDA  y  OpenCL  también  
están  en  desarrollo  activo  para  alta  ­Velocidad  de  las  operaciones  de  la  GPU.

OpenCV­Python  es  la  API  Python  de  OpenCV.  Combina  las  mejores  cualidades  de  la  API  C++  de  OpenCV  y  el  lenguaje  Python.

OpenCV­Python

Python  es  un  lenguaje  de  programación  de  propósito  general  iniciado  por  Guido  van  Rossum,  que  se  hizo  muy  popular  en  poco  tiempo  
principalmente  debido  a  su  simplicidad  y  legibilidad  del  código.  Permite  al  programador  expresar  sus  ideas  en  menos  líneas  de  código  sin  
reducir  la  legibilidad.

Comparado  con  otros  lenguajes  como  C/C++,  Python  es  más  lento.  Pero  otra  característica  importante  de  Python  es  que  se  puede  ampliar  
fácilmente  con  C/C++.  Esta  característica  nos  ayuda  a  escribir  códigos  computacionalmente  intensivos  en  C/C++  y  crear  un  envoltorio  de  
Python  para  que  podamos  usar  estos  envoltorios  como  módulos  de  Python.  Esto  nos  da  dos  ventajas:  primero,  nuestro  código  es  tan  rápido  
como  el  código  C/C++  original  (ya  que  es  el  código  C++  real  trabajando  en  segundo  plano)  y  segundo,  es  muy  fácil  codificar  en  Python.  Así  
es  como  funciona  OpenCV­Python,  es  un  contenedor  de  Python  alrededor  de  la  implementación  original  de  C++.

Y  el  soporte  de  Numpy  facilita  la  tarea.  Numpy  es  una  biblioteca  altamente  optimizada  para  operaciones  numéricas.
Proporciona  una  sintaxis  de  estilo  MATLAB.  Todas  las  estructuras  de  arreglos  de  OpenCV  se  convierten  a  y  desde  arreglos  Numpy.  
Entonces,  independientemente  de  las  operaciones  que  pueda  hacer  en  Numpy,  puede  combinarlas  con  OpenCV,  lo  que  aumenta  la  
cantidad  de  armas  en  su  arsenal.  Además  de  eso,  varias  otras  bibliotecas  como  SciPy,  Matplotlib  que  admite  Numpy  se  pueden  usar  con  esto.

Por  lo  tanto,  OpenCV­Python  es  una  herramienta  adecuada  para  la  creación  rápida  de  prototipos  de  problemas  de  visión  por  computadora.

Tutoriales  de  OpenCV­Python

OpenCV  presenta  un  nuevo  conjunto  de  tutoriales  que  lo  guiarán  a  través  de  varias  funciones  disponibles  en  OpenCV­Python.
Esta  guía  se  centra  principalmente  en  la  versión  OpenCV  3.x  (aunque  la  mayoría  de  los  tutoriales  también  funcionarán  con  OpenCV  2.x).

Se  requiere  un  conocimiento  previo  de  Python  y  Numpy  antes  de  comenzar  porque  no  se  tratarán  en  esta  guía.
Especialmente,  se  debe  tener  un  buen  conocimiento  de  Numpy  para  escribir  códigos  optimizados  en  OpenCV­Python.

Este  tutorial  lo  inició  Abid  Rahman  K.  como  parte  del  programa  Google  Summer  of  Code  2013,  bajo  la  dirección  de  Alexander  Mordvintsev.

¡OpenCV  te  necesita!

Dado  que  OpenCV  es  una  iniciativa  de  código  abierto,  todos  son  bienvenidos  a  hacer  contribuciones  a  esta  biblioteca.  Y  es  lo  mismo  para  
este  tutorial  también.

Por  lo  tanto,  si  encuentra  algún  error  en  este  tutorial  (ya  sea  un  pequeño  error  de  ortografía  o  un  gran  error  en  el  código  o  los  conceptos,  lo  
que  sea),  siéntase  libre  de  corregirlo.

1.1.  Introducción  a  OpenCV 7
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Y  esa  será  una  buena  tarea  para  los  principiantes  que  comienzan  a  contribuir  con  proyectos  de  código  abierto.  Simplemente  bifurque  OpenCV  en  
github,  haga  las  correcciones  necesarias  y  envíe  una  solicitud  de  extracción  a  OpenCV.  Los  desarrolladores  de  OpenCV  verificarán  su  solicitud  de  
extracción,  le  brindarán  comentarios  importantes  y,  una  vez  que  pase  la  aprobación  del  revisor,  se  fusionará  con  OpenCV.
Entonces  te  conviertes  en  un  colaborador  de  código  abierto.  Similar  es  el  caso  con  otros  tutoriales,  documentación,  etc.

A  medida  que  se  agreguen  nuevos  módulos  a  OpenCV­Python,  este  tutorial  deberá  ampliarse.  Entonces,  aquellos  que  conocen  un  algoritmo  en  
particular  pueden  escribir  un  tutorial  que  incluya  una  teoría  básica  del  algoritmo  y  un  código  que  muestre  el  uso  básico  del  algoritmo  y  enviarlo  a  
OpenCV.

Recuerda,  juntos  podemos  hacer  de  este  proyecto  un  gran  éxito!!!

Colaboradores

A  continuación  se  muestra  la  lista  de  colaboradores  que  enviaron  tutoriales  a  OpenCV­Python.

1.  Alexander  Mordvintsev  (mentor  de  GSoC­2013)

2.  Abid  Rahman  K.  (pasante  de  GSoC­2013)

Recursos  adicionales

1.  Una  guía  rápida  de  Python:  un  byte  de  Python

2.  Tutoriales  básicos  de  Numpy

3.  Lista  de  ejemplos  Numpy

4.  Documentación  OpenCV

5.  Foro  OpenCV

Instalar  OpenCV­Python  en  Windows

Objetivos

En  este  tutorial

•  Aprenderemos  a  configurar  OpenCV­Python  en  su  sistema  Windows.

Los  pasos  a  continuación  se  prueban  en  una  máquina  con  Windows  7  a  64  bits  con  Visual  Studio  2010  y  Visual  Studio  2012.  Las  capturas  de  pantalla  
muestran  VS2012.

Instalación  de  OpenCV  desde  binarios  precompilados

1.  Los  siguientes  paquetes  de  Python  deben  descargarse  e  instalarse  en  sus  ubicaciones  predeterminadas.

1.1.  Python­2.7.x.

1.2.  entumecido

1.3.  matplotlib  (Matplotlib  es  opcional,  pero  recomendado  ya  que  lo  usamos  mucho  en  nuestros  tutoriales).

2.  Instale  todos  los  paquetes  en  sus  ubicaciones  predeterminadas.  Python  se  instalará  en  C:/Python27/.

3.  Después  de  la  instalación,  abra  Python  IDLE.  Ingrese  import  numpy  y  asegúrese  de  que  Numpy  funcione  bien.

4.  Descargue  la  última  versión  de  OpenCV  del  sitio  de  sourceforge  y  haga  doble  clic  para  extraerlo.

7.  Vaya  a  la  carpeta  opencv/build/python/2.7 .

8 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

8.  Copie  cv2.pyd  en  C:/Python27/lib/site­packeges.

9.  Abra  Python  IDLE  y  escriba  los  siguientes  códigos  en  la  terminal  de  Python.

>>>  importar  cv2  
>>>  imprimir  cv2.__versión__

Si  los  resultados  se  imprimen  sin  errores,  ¡felicidades!  Ha  instalado  OpenCV­Python  con  éxito.

Construyendo  OpenCV  desde  la  fuente

1.  Descargue  e  instale  Visual  Studio  y  CMake.

1.1.  estudio  visual  2012

1.2.  CHacer

2.  Descargue  e  instale  los  paquetes  de  Python  necesarios  en  sus  ubicaciones  predeterminadas

2.1.  Pitón  2.7.x

2.2.  entumecido

2.3.  matplotlib  (Matplotlib  es  opcional,  pero  recomendado  ya  que  lo  usamos  mucho  en  nuestros  tutoriales).

Nota:  En  este  caso,  estamos  usando  binarios  de  32  bits  de  paquetes  de  Python.  Pero  si  desea  utilizar  OpenCV  para  x64,  se  deben  instalar  
paquetes  binarios  de  Python  de  64  bits.  El  problema  es  que  no  hay  archivos  binarios  oficiales  de  64  bits  de  Numpy.  Tienes  que  construirlo  por  tu  
cuenta.  Para  eso,  debe  usar  el  mismo  compilador  que  se  usó  para  compilar  Python.  Cuando  inicia  Python  IDLE,  muestra  los  detalles  del  
compilador.  Puede  obtener  más  información  aquí.  Por  lo  tanto,  su  sistema  debe  tener  la  misma  versión  de  Visual  Studio  y  compilar  Numpy  desde  
la  fuente.

Nota:  Otro  método  para  tener  paquetes  de  Python  de  64  bits  es  usar  distribuciones  de  Python  listas  para  usar  de  terceros  como  Anaconda,  
pensado  etc.  Será  más  grande  en  tamaño,  pero  tendrá  todo  lo  que  necesita.  Todo  en  un  solo  caparazón.
También  puede  descargar  versiones  de  32  bits  también.

3.  Asegúrese  de  que  Python  y  Numpy  funcionen  bien.

4.  Descargue  la  fuente  de  OpenCV.  Puede  ser  de  Sourceforge  (para  la  versión  de  lanzamiento  oficial)  o  de  Github  (para  la  última
fuente).

5.  Extráigalo  a  una  carpeta,  abra  CV  y  cree  una  nueva  compilación  de  carpeta  en  él.

6.  Abra  CMake­gui  (Inicio  >  Todos  los  programas  >  CMake­gui)

7.  Complete  los  campos  de  la  siguiente  manera  (vea  la  imagen  a  continuación):

7.1.  Haga  clic  en  Examinar  fuente...  y  localice  la  carpeta  opencv.

7.2.  Haga  clic  en  Examinar  compilación...  y  localice  la  carpeta  de  compilación  que  creamos.

7.3.  Haga  clic  en  Configurar.

1.1.  Introducción  a  OpenCV 9
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

7.4.  Se  abrirá  una  nueva  ventana  para  seleccionar  el  compilador.  Elija  el  compilador  adecuado  (aquí,  Visual  Studio  11)  y  haga  
clic  en  Finalizar.

7.5.  Espere  hasta  que  finalice  el  análisis.

8.  Verás  que  todos  los  campos  están  marcados  en  rojo.  Haga  clic  en  el  campo  CON  para  expandirlo.  Decide  qué  características  adicionales
necesitas.  Así  que  marque  los  campos  apropiados.  Vea  la  imagen  de  abajo:

10 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

9.  Ahora  haga  clic  en  el  campo  CONSTRUIR  para  expandirlo.  Los  primeros  campos  configuran  el  método  de  compilación.  Vea  la  imagen  de  abajo:

1.1.  Introducción  a  OpenCV 11
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

10.  Los  campos  restantes  especifican  qué  módulos  se  van  a  construir.  Dado  que  los  módulos  de  GPU  aún  no  son  compatibles  con  
OpenCV  Python,  puede  evitarlos  por  completo  para  ahorrar  tiempo  (pero  si  trabaja  con  ellos,  manténgalo  allí).  Vea  la  imagen  a  
continuación:

12 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

11.  Ahora  haga  clic  en  el  campo  HABILITAR  para  expandirlo.  Asegúrese  de  que  ENABLE_SOLUTION_FOLDERS  no  esté  marcado  (así  que
Las  carpetas  de  solución  no  son  compatibles  con  la  edición  Visual  Studio  Express).  Vea  la  imagen  a  continuación:

1.1.  Introducción  a  OpenCV 13
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

12.  También  asegúrese  de  que  en  el  campo  PYTHON ,  todo  esté  lleno.  (Ignorar  PYTHON_DEBUG_LIBRARY).  Ver
imagen  a  continuación:

13.  Finalmente  haga  clic  en  el  botón  Generar .

14.  Ahora  ve  a  nuestra  carpeta  opencv/build .  Allí  encontrará  el  archivo  OpenCV.sln .  Ábralo  con  Visual  Studio.

15.  Marque  el  modo  de  compilación  como  Lanzamiento  en  lugar  de  Depuración.

16.  En  el  explorador  de  soluciones,  haga  clic  con  el  botón  derecho  en  la  solución  (o  ALL_BUILD)  y  constrúyala.  Tomará  algún  tiempo  para
finalizar.

17.  Nuevamente,  haga  clic  derecho  en  INSTALAR  y  constrúyalo.  Ahora  se  instalará  OpenCV­Python.

14 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

18.  Abra  Python  IDLE  e  ingrese  import  cv2.  Si  no  hay  error,  está  instalado  correctamente.

Nota:  Lo  hemos  instalado  sin  ningún  otro  soporte  como  TBB,  Eigen,  Qt,  Documentación,  etc.  Sería  difícil  explicarlo  aquí.  Pronto  se  agregará  
un  video  más  detallado  o  simplemente  puede  piratear.

Recursos  adicionales

Ejercicios

1.  Si  tiene  una  máquina  con  Windows,  compile  OpenCV  desde  la  fuente.  Haz  todo  tipo  de  trucos.  Si  te  encuentras  con  alguno
problema,  visite  el  foro  de  OpenCV  y  explique  su  problema.

Instalar  OpenCV­Python  en  Fedora

Objetivos

En  este  tutorial

•  Aprenderemos  a  configurar  OpenCV­Python  en  su  sistema  Fedora.  Los  pasos  a  continuación  se  prueban  para  Fedora  18  (64  
bits)  y  Fedora  19  (32  bits).

Introducción

OpenCV­Python  se  puede  instalar  en  Fedora  de  dos  maneras:  1)  Instalar  desde  archivos  binarios  preconstruidos  disponibles  en  los  
repositorios  de  Fedora,  2)  Compilar  desde  la  fuente.  En  esta  sección,  veremos  ambos.

Otra  cosa  importante  son  las  bibliotecas  adicionales  requeridas.  OpenCV­Python  requiere  solo  Numpy  (además  de  otras  dependencias,  que  
veremos  más  adelante).  Pero  en  estos  tutoriales,  también  usamos  Matplotlib  para  algunos  propósitos  de  trazado  fáciles  y  agradables  (que  
me  siento  mucho  mejor  en  comparación  con  OpenCV).  Matplotlib  es  opcional,  pero  muy  recomendable.
De  igual  forma  también  veremos  IPython,  una  Terminal  de  Python  Interactiva,  que  también  es  muy  recomendable.

Instalación  de  OpenCV­Python  desde  binarios  prediseñados

Instale  todos  los  paquetes  con  el  siguiente  comando  en  la  terminal  como  root.

$  yum  instalar  numpy  opencv*

Abra  Python  IDLE  (o  IPython)  y  escriba  los  siguientes  códigos  en  la  terminal  de  Python.

>>>  importar  cv2  >>>  
imprimir  cv2.__versión__

Si  los  resultados  se  imprimen  sin  errores,  ¡felicidades!  Ha  instalado  OpenCV­Python  con  éxito.

Es  bastante  fácil.  Pero  hay  un  problema  con  esto.  Los  repositorios  de  Yum  pueden  no  contener  siempre  la  última  versión  de  OpenCV.  Por  
ejemplo,  al  momento  de  escribir  este  tutorial,  el  repositorio  de  yum  contiene  2.4.5  mientras  que  la  última  versión  de  OpenCV  es  2.4.6.  Con  
respecto  a  la  API  de  Python,  la  última  versión  siempre  tendrá  un  soporte  mucho  mejor.  Además,  puede  haber  problemas  con  el  soporte  de  la  
cámara,  la  reproducción  de  video,  etc.  dependiendo  de  los  controladores,  ffmpeg,  paquetes  gstreamer  presentes,  etc.

Así  que  mi  preferencia  personal  es  el  siguiente  método,  es  decir,  compilar  desde  la  fuente.  También  en  algún  momento,  si  desea  contribuir  
con  OpenCV,  necesitará  esto.

1.1.  Introducción  a  OpenCV 15
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Instalar  OpenCV  desde  la  fuente

Compilar  desde  el  código  fuente  puede  parecer  un  poco  complicado  al  principio,  pero  una  vez  que  lo  lograste,  no  hay  nada  complicado.

Primero  instalaremos  algunas  dependencias.  Algunos  son  obligatorios,  otros  son  opcionales.  Dependencias  opcionales,  puedes  dejarlas  si  
no  quieres.

Dependencias  Obligatorias

Necesitamos  CMake  para  configurar  la  instalación,  GCC  para  la  compilación,  Python­devel  y  Numpy  para  crear  extensiones  de  Python,  etc.

yum  install  cmake  yum  
install  python­devel  numpy  yum  install  gcc  gcc­
c++

A  continuación,  necesitamos  compatibilidad  con  GTK  para  funciones  de  GUI,  compatibilidad  con  cámara  (libdc1394,  libv4l),  compatibilidad  con  medios  (ffmpeg,  gstreamer),  
etc.

yum  install  gtk2­devel  yum  install  
libdc1394­devel  yum  install  libv4l­devel  
yum  install  ffmpeg­devel  yum  install  
gstreamer­plugins­base­devel

Dependencias  opcionales

Las  dependencias  anteriores  son  suficientes  para  instalar  OpenCV  en  su  máquina  fedora.  Pero  dependiendo  de  sus  requisitos,  es  posible  
que  necesite  algunas  dependencias  adicionales.  A  continuación  se  proporciona  una  lista  de  dichas  dependencias  opcionales.  Puedes  
dejarlo  o  instalarlo,  tu  llamada :)

OpenCV  viene  con  archivos  de  soporte  para  formatos  de  imagen  como  PNG,  JPEG,  JPEG2000,  TIFF,  WebP,  etc.  Pero  puede  ser  un  poco  
antiguo.  Si  desea  obtener  las  bibliotecas  más  recientes,  puede  instalar  archivos  de  desarrollo  para  estos  formatos.

yum  install  libpng­devel  yum  install  
libjpeg­turbo­devel  yum  install  jasper­devel  yum  
install  openexr­devel  yum  install  libtiff­
devel  yum  install  libwebp­devel

Varias  funciones  de  OpenCV  están  en  paralelo  con  Threading  Building  Blocks  (TBB)  de  Intel.  Pero  si  desea  habilitarlo,  primero  debe  
instalar  TBB.  (Además,  al  configurar  la  instalación  con  CMake,  no  olvide  pasar  ­D  WITH_TBB=ON.  Más  detalles  a  continuación).

yum  instalar  tbb­devel

OpenCV  usa  otra  biblioteca  Eigen  para  operaciones  matemáticas  optimizadas.  Entonces,  si  tiene  Eigen  instalado  en  su  sistema,  puede  
explotarlo.  (Además,  al  configurar  la  instalación  con  CMake,  no  olvide  pasar  ­D  WITH_EIGEN=ON.
Más  detalles  a  continuación.)

yum  instalar  eigen3­devel

dieciséis
Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Si  desea  crear  documentación  (Sí,  puede  crear  una  versión  fuera  de  línea  de  la  documentación  oficial  completa  de  OpenCV  en  su  sistema  en  
HTML  con  función  de  búsqueda  completa  para  que  no  necesite  acceder  a  Internet  siempre  si  tiene  alguna  pregunta,  ¡y  es  bastante  RÁPIDO!),  
necesita  instalar  Sphinx  (una  herramienta  de  generación  de  documentación)  y  pdflatex  (si  desea  crear  una  versión  en  PDF).  (Además,  mientras  
configura  la  instalación  con  CMake,  no  olvide  pasar  ­D  BUILD_DOCS=ON.
Más  detalles  a  continuación.)

yum  instalar  python­sphinx  yum  instalar  
texlive

Descargando  OpenCV

A  continuación  tenemos  que  descargar  OpenCV.  Puede  descargar  la  última  versión  de  OpenCV  desde  el  sitio  de  sourceforge.  Luego  extraiga  la  
carpeta.

O  puede  descargar  la  fuente  más  reciente  del  repositorio  github  de  OpenCV.  (Si  desea  contribuir  con  OpenCV,  elija  esto.  Siempre  mantiene  su  
OpenCV  actualizado).  Para  eso,  primero  debes  instalar  Git .

yum  instala  git  git  clon  
https://github.com/Itseez/opencv.git

Creará  una  carpeta  OpenCV  en  el  directorio  de  inicio  (o  el  directorio  que  especifique).  La  clonación  puede  tardar  algún  tiempo  dependiendo  de  
su  conexión  a  Internet.

Ahora  abra  una  ventana  de  terminal  y  navegue  hasta  la  carpeta  OpenCV  descargada.  Cree  una  nueva  carpeta  de  compilación  y  navegue  hasta  
ella.

construir  mkdir
compilación  de  CD

Configuración  e  instalación

Ahora  que  hemos  instalado  todas  las  dependencias  requeridas,  instalemos  OpenCV.  La  instalación  debe  configurarse  con  CMake.  Especifica  
qué  módulos  se  instalarán,  la  ruta  de  instalación,  qué  bibliotecas  adicionales  se  utilizarán,  si  la  documentación  y  los  ejemplos  se  compilarán,  etc.  
El  siguiente  comando  se  usa  normalmente  para  la  configuración  (ejecutado  desde  la  carpeta  de  compilación).

cmake  ­D  CMAKE_BUILD_TYPE=LIBERAR  ­D  CMAKE_INSTALL_PREFIX=/usr/local ..

Especifica  que  el  tipo  de  compilación  es  "Modo  de  lanzamiento"  y  la  ruta  de  instalación  es /usr/local.  Observe  la  ­D  antes  de  cada  opción  y
.. al  final.  En  resumen,  este  es  el  formato:

cmake  [­D  <bandera>]  [­D  <bandera>] ..

Puede  especificar  tantos  indicadores  como  desee,  pero  cada  indicador  debe  estar  precedido  por  ­D.

Entonces,  en  este  tutorial,  estamos  instalando  OpenCV  con  soporte  TBB  y  Eigen.  También  creamos  la  documentación,  pero  excluimos  las  pruebas  
de  rendimiento  y  las  muestras  de  construcción.  También  deshabilitamos  los  módulos  relacionados  con  GPU  (dado  que  usamos  OpenCV­Python,  
no  necesitamos  módulos  relacionados  con  GPU.  Nos  ahorra  algo  de  tiempo).

(Todos  los  comandos  a  continuación  se  pueden  hacer  en  una  sola  instrucción  cmake,  pero  se  divide  aquí  para  una  mejor  comprensión).

•  Habilite  la  compatibilidad  con  TBB  y  Eigen:

cmake  ­D  CON_TBB=ENCENDIDO  ­D  CON_EIGEN=ENCENDIDO ..

1.1.  Introducción  a  OpenCV 17
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

•  Habilitar  documentación  y  deshabilitar  pruebas  y  muestras

cmake  ­D  BUILD_DOCS=ON  ­D  BUILD_TESTS=OFF  ­D  BUILD_PERF_TESTS=OFF  ­D   →BUILD_EXAMPLES=OFF ..

•  Deshabilite  todos  los  módulos  relacionados  con  la  GPU.

cmake  ­D  WITH_OPENCL=OFF  ­D  WITH_CUDA=OFF  ­D  BUILD_opencv_gpu=OFF  ­D  
→BUILD_opencv_gpuarithm=OFF  ­D  BUILD_opencv_gpubgsegm=OFF  ­D  BUILD_  
→opencv_gpucodec=OFF  ­D  BUILD_opencv_gpufeatures2d=OFF  ­D  BUILD_opencv_  
→gpufilters=DESACTIVADO  ­  D  BUILD_opencv_gpuimgproc=DESACTIVADO  ­D  BUILD_opencv_  
→gpulegacy=DESACTIVADO  ­D  BUILD_opencv_gpuoptflow=DESACTIVADO  ­D  BUILD_opencv_  
→gpustereo=DESACTIVADO  ­D  BUILD_opencv_gpuwarping=DESACTIVADO ..

•  Establecer  la  ruta  de  instalación  y  el  tipo  de  compilación

cmake  ­D  CMAKE_BUILD_TYPE=LIBERAR  ­D  CMAKE_INSTALL_PREFIX=/usr/local ..

Cada  vez  que  ingresa  la  declaración  cmake,  imprime  la  configuración  resultante.  En  la  configuración  final  que  obtuvo,  asegúrese  de  que  los  
siguientes  campos  estén  completos  (a  continuación  se  muestran  algunas  partes  importantes  de  la  configuración  que  obtuve).  Estos  campos  
también  deben  completarse  adecuadamente  en  su  sistema.  De  lo  contrario,  ha  ocurrido  algún  problema.  Por  lo  tanto,  compruebe  si  ha  realizado  
correctamente  los  pasos  anteriores.

­­  Interfaz  gráfica  de  usuario:

­­
GTK+  2.x: SÍ  (versión  2.24.19)
­­
Hilo: SÍ  (versión  2.36.3)

­­  E/S  de  vídeo:  DC1394  2.x:
­­
SÍ  (versión  2.2.0)
­­
FFMPEG: SÍ
­­
códec: SÍ  (versión  54.92.100)
­­
formato: SÍ  (versión  54.63.104)
­­
útil: SÍ  (versión  52.18.100)
­­
swescala: SÍ  (versión  2.2.100)
­­
estilo  gentoo: SÍ
­­
GStreamer:
­­
base: SÍ  (versión  0.10.36)
­­
video: SÍ  (versión  0.10.36)
­­
SÍ  (versión  0.10.36)
­­
aplicación:  riff: SÍ  (versión  0.10.36)
­­
butilo: SÍ  (versión  0.10.36)

­­
V4L/V4L2: Usando  libv4l  (ver  1.0.0)

­­  Otras  bibliotecas  de  terceros:
­­
Usar  propio: SÍ  (versión  3.1.4)
­­
Usar  TBB: SÍ  (ver  4.0  interfaz  6004)

­­  Pitón:
­­
Intérprete: /usr/bin/python2  (versión  2.7.5) /lib/libpython2.7.so  
­­
Bibliotecas: (versión  2.7.5) /usr/lib/python2.7/site­packages/numpy/
­­
numpy:  
→core/include  (ver  1.7.1)  ruta  de  
­­
paquetes: lib/python2.7/paquetes  del  sitio

­­  Documentación:
­­
Documentación  de  compilación: SÍ
­­
Esfinge: /usr/bin/sphinx­build  (versión  1.1.3)

18 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

­­
Compilador  PdfLaTeX: /usr/bin/pdflatex
­­

­­  Pruebas  y  muestras:
­­
Pruebas: NO
­­
Pruebas  de  rendimiento: NO
­­
Ejemplos  de  C/C++: NO

Muchas  otras  banderas  y  configuraciones  están  ahí.  Se  deja  para  usted  para  una  mayor  exploración.

Ahora  construyes  los  archivos  usando  el  comando  make  e  instálalos  usando  el  comando  make  install.  make  install  debe  ejecutarse  como  root.

hacer
son
hacer  instalar

La  instalación  ha  terminado.  Todos  los  archivos  se  instalan  en  la  carpeta /usr/local/.  Pero  para  usarlo,  su  Python  debería  poder  encontrar  el  módulo  
OpenCV.  Tienes  dos  opciones  para  eso.

1.  Mueva  el  módulo  a  cualquier  carpeta  en  Python  Path :  la  ruta  de  Python  se  puede  encontrar  ingresando  import  sys;print  sys.path  en  la  terminal  
de  Python.  Imprimirá  muchas  ubicaciones.  Mueva /usr/local/lib/python2.7/site­packages/cv2.so  a  cualquiera  de  esta  carpeta.  Por  ejemplo,

su  mv /usr/local/lib/python2.7/site­packages/cv2.so /usr/lib/python2.7/   →site­packages

Pero  tendrás  que  hacer  esto  cada  vez  que  instales  OpenCV.

2.  Agregue  ''/usr/local/lib/python2.7/site­packages''  a  PYTHON_PATH:  se  debe  hacer  solo  una  vez.  Simplemente  abra  ~/.bashrc  y  agregue  la  
siguiente  línea,  luego  cierre  la  sesión  y  regrese.

exportar  PYTHONPATH=$PYTHONPATH:/usr/local/lib/python2.7/site­packages

Así  finaliza  la  instalación  de  OpenCV.  Abra  una  terminal  e  intente  importar  cv2.

Para  construir  la  documentación,  simplemente  ingrese  los  siguientes  comandos:

hacer  documentos

hacer  html_docs

Luego  abra  opencv/build/doc/_html/index.html  y  márquelo  como  favorito  en  el  navegador.

Recursos  adicionales

Ejercicios

1.  Compile  OpenCV  desde  la  fuente  en  su  máquina  Fedora.

Características  de  la  interfaz  gráfica  de  usuario  en  OpenCV

•  Introducción  a  las  imágenes

1.2.  Características  de  la  interfaz  gráfica  de  usuario  en  OpenCV 19
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Aprende  a  cargar  una  imagen,  mostrarla  y  guardarla  de  nuevo

•  Introducción  a  los  vídeos

Aprenda  a  reproducir  videos,  capturar  videos  desde  la  cámara  y  escribirlos  como  un  video

•  Funciones  de  dibujo  en  OpenCV

Aprende  a  dibujar  líneas,  rectángulos,  elipses,  círculos,  etc.  con  OpenCV

•  Ratón  como  pincel

Dibuja  cosas  con  tu  mouse

•  Trackbar  como  paleta  de  colores

Crear  trackbar  para  controlar  ciertos  parámetros

20 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Introducción  a  las  imágenes
Objetivos

•  Aquí,  aprenderá  cómo  leer  una  imagen,  cómo  mostrarla  y  cómo  volver  a  guardarla

•  Aprenderá  estas  funciones:  cv2.imread(),  cv2.imshow() ,  cv2.imwrite()

•  Opcionalmente,  aprenderá  a  mostrar  imágenes  con  Matplotlib

Usando  OpenCV

leer  una  imagen

Utilice  la  función  cv2.imread()  para  leer  una  imagen.  La  imagen  debe  estar  en  el  directorio  de  trabajo  o  se  debe  proporcionar  una  ruta  completa  de  la  imagen.

El  segundo  argumento  es  una  bandera  que  especifica  la  forma  en  que  se  debe  leer  la  imagen.

•  cv2.IMREAD_COLOR :  Carga  una  imagen  a  color.  Se  descuidará  cualquier  transparencia  de  la  imagen.  es  el  predeterminado
bandera.

•  cv2.IMREAD_GRAYSCALE :  Carga  la  imagen  en  modo  de  escala  de  grises

•  cv2.IMREAD_UNCHANGED:  Carga  la  imagen  como  tal,  incluido  el  canal  alfa

Nota:  En  lugar  de  estas  tres  banderas,  simplemente  puede  pasar  los  números  enteros  1,  0  o  ­1  respectivamente.

Vea  el  código  a  continuación:

importar  numpy  como  np  
importar  cv2

#  Cargar  una  imagen  a  color  en  escala  de  grises  img  
=  cv2.imread('messi5.jpg',0)

Advertencia:  incluso  si  la  ruta  de  la  imagen  es  incorrecta,  no  arrojará  ningún  error,  pero  imprimir  img  le  dará  Ninguno

mostrar  una  imagen

Utilice  la  función  cv2.imshow()  para  mostrar  una  imagen  en  una  ventana.  La  ventana  se  ajusta  automáticamente  al  tamaño  de  la  imagen.

El  primer  argumento  es  un  nombre  de  ventana  que  es  una  cadena.  El  segundo  argumento  es  nuestra  imagen.  Puede  crear  tantas  ventanas  como  desee,  pero  
con  diferentes  nombres  de  ventana.

cv2.imshow('imagen',img)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

Una  captura  de  pantalla  de  la  ventana  se  verá  así  (en  la  máquina  Fedora­Gnome):

1.2.  Características  de  la  interfaz  gráfica  de  usuario  en  OpenCV 21
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

cv2.waitKey()  es  una  función  de  enlace  de  teclado.  Su  argumento  es  el  tiempo  en  milisegundos.  La  función  espera  los  milisegundos  especificados  para  
cualquier  evento  de  teclado.  Si  presiona  cualquier  tecla  en  ese  tiempo,  el  programa  continúa.  Si  se  pasa  0 ,  espera  indefinidamente  una  pulsación  de  
tecla.  También  se  puede  configurar  para  detectar  pulsaciones  de  teclas  específicas,  como  si  se  presiona  la  tecla  a,  etc.,  que  discutiremos  a  continuación.

cv2.destroyAllWindows()  simplemente  destruye  todas  las  ventanas  que  creamos.  Si  desea  destruir  una  ventana  específica,  use  la  función  
cv2.destroyWindow()  donde  pasa  el  nombre  exacto  de  la  ventana  como  argumento.

Nota:  Existe  un  caso  especial  en  el  que  ya  puede  crear  una  ventana  y  cargarle  una  imagen  más  tarde.  En  ese  caso,  puede  especificar  si  la  ventana  es  
redimensionable  o  no.  Se  hace  con  la  función  cv2.namedWindow().  De  forma  predeterminada,  el  indicador  es  cv2.WINDOW_AUTOSIZE.  Pero  si  
especifica  que  el  indicador  sea  cv2.WINDOW_NORMAL,  puede  cambiar  el  tamaño  de  la  ventana.  Será  útil  cuando  la  imagen  tenga  una  dimensión  
demasiado  grande  y  agregue  una  barra  de  seguimiento  a  las  ventanas.

Vea  el  código  a  continuación:

cv2.namedWindow('imagen',  cv2.VENTANA_NORMAL)  
cv2.imshow('imagen',img)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

escribir  una  imagen

Utilice  la  función  cv2.imwrite()  para  guardar  una  imagen.

El  primer  argumento  es  el  nombre  del  archivo,  el  segundo  argumento  es  la  imagen  que  desea  guardar.

cv2.imwrite('messigray.png',img)

Esto  guardará  la  imagen  en  formato  PNG  en  el  directorio  de  trabajo.

22 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Añádelo

El  siguiente  programa  carga  una  imagen  en  escala  de  grises,  la  muestra,  guarda  la  imagen  si  presiona  's'  y  sale,  o  simplemente  sale  sin  
guardar  si  presiona  la  tecla  ESC.

importar  numpy  como  np  
importar  cv2

img  =  cv2.imread('messi5.jpg',0)  
cv2.imshow('imagen',img)  k  =  
cv2.waitKey(0)  if  k  ==  27:
#  espere  a  que  la  tecla  ESC  salga  de  
cv2.destroyAllWindows()  elif  k  ==  
ord('s'):  #  espere  a  que  la  tecla  's'  guarde  y  salga  de  cv2.imwrite('messigray.png',img)  
cv2.destroyAllWindows( )

Advertencia:  si  está  utilizando  una  máquina  de  64  bits,  deberá  modificar  la  línea  k  =  cv2.waitKey(0)  de  la  siguiente  manera:  k  =  
cv2.waitKey(0)  &  0xFF

Usando  Matplotlib

Matplotlib  es  una  biblioteca  de  trazado  para  Python  que  le  brinda  una  amplia  variedad  de  métodos  de  trazado.  Los  verás  en  próximos  
artículos.  Aquí,  aprenderá  cómo  mostrar  imágenes  con  Matplotlib.  Puede  hacer  zoom  en  las  imágenes,  guardarlas,  etc.  usando  Matplotlib.

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('messi5.jpg',0)  plt.imshow(img,  
cmap  =  'gray',  interpolation  =  'bicubic')  plt.xticks([]),  plt.yticks([])  #  para  ocultar  marque  los  
valores  en  los  ejes  X  e  Y  plt.show()

Una  captura  de  pantalla  de  la  ventana  se  verá  así:

1.2.  Características  de  la  interfaz  gráfica  de  usuario  en  OpenCV 23
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Ver  también:

Hay  muchas  opciones  de  trazado  disponibles  en  Matplotlib.  Consulte  los  documentos  de  Matplotlib  para  obtener  más  detalles.  Algunos,  los  
veremos  en  el  camino.

Advertencia:  la  imagen  en  color  cargada  por  OpenCV  está  en  modo  BGR.  Pero  Matplotlib  se  muestra  en  modo  RGB.  Por  lo  tanto,  las  
imágenes  en  color  no  se  mostrarán  correctamente  en  Matplotlib  si  la  imagen  se  lee  con  OpenCV.  Por  favor  vea  los  ejercicios  para  más  
detalles.

Recursos  adicionales

1.  Estilos  y  características  de  trazado  de  Matplotlib

Ejercicios

1.  Hay  algún  problema  cuando  intenta  cargar  una  imagen  en  color  en  OpenCV  y  mostrarla  en  Matplotlib.  lee  esto
discusión  y  entenderlo.

Introducción  a  los  vídeos

24 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Meta

•  Aprenda  a  leer  videos,  mostrar  videos  y  guardar  videos.

•  Aprenda  a  capturar  desde  la  cámara  y  mostrarlo.

•  Aprenderá  estas  funciones:  cv2.VideoCapture(),  cv2.VideoWriter()

Capturar  video  desde  la  cámara

A  menudo,  tenemos  que  capturar  la  transmisión  en  vivo  con  la  cámara.  OpenCV  proporciona  una  interfaz  muy  simple  para  esto.  Capturemos  un  
video  de  la  cámara  (estoy  usando  la  cámara  web  incorporada  de  mi  computadora  portátil),  conviértalo  en  un  video  en  escala  de  grises  y  visualícelo.
Solo  una  tarea  simple  para  comenzar.

Para  capturar  un  video,  debe  crear  un  objeto  VideoCapture .  Su  argumento  puede  ser  el  índice  del  dispositivo  o  el  nombre  de  un  archivo  de  video.  
El  índice  del  dispositivo  es  solo  el  número  para  especificar  qué  cámara.  Normalmente  se  conectará  una  cámara  (como  en  mi  caso).  Así  que  
simplemente  paso  0  (o  ­1).  Puede  seleccionar  la  segunda  cámara  pasando  1  y  así  sucesivamente.  Después  de  eso,  puede  capturar  cuadro  por  
cuadro.  Pero  al  final,  no  olvides  soltar  la  captura.

importar  numpy  como  np  
importar  cv2

tapa  =  cv2.VideoCapture(0)

mientras  (Verdadero):
#  Captura  cuadro  por  cuadro  ret,  
cuadro  =  cap.read()

#  Nuestras  operaciones  en  el  cuadro  vienen  aquí  gris  =  
cv2.cvtColor(cuadro,  cv2.COLOR_BGR2GRAY)

#  Muestra  el  marco  resultante  
cv2.imshow('frame',gray)  if  
cv2.waitKey(1)  &  0xFF  ==  ord('q'):  break

#  Cuando  todo  esté  listo,  suelte  la  captura  cap.release()  
cv2.destroyAllWindows()

cap.read()  devuelve  un  bool  (Verdadero/Falso).  Si  el  marco  se  lee  correctamente,  será  Verdadero.  Entonces  puede  verificar  el  final  del  video  al  
verificar  este  valor  de  retorno.

A  veces,  es  posible  que  cap  no  haya  inicializado  la  captura.  En  ese  caso,  este  código  muestra  un  error.  Puede  comprobar  si  está  inicializado  o  no  
mediante  el  método  cap.isOpened().  Si  es  cierto,  está  bien.  De  lo  contrario,  ábralo  usando  cap.open().

También  puede  acceder  a  algunas  de  las  funciones  de  este  video  usando  el  método  cap.get( propId)  donde  propId  es  un  número  del  0  al  18.  Cada  
número  denota  una  propiedad  del  video  (si  es  aplicable  a  ese  video)  y  los  detalles  completos  pueden  ser  visto  aquí:  Identificador  de  Propiedad.  
Algunos  de  estos  valores  se  pueden  modificar  usando  cap.set(propId,  value).  El  valor  es  el  nuevo  valor  que  desea.

Por  ejemplo,  puedo  verificar  el  ancho  y  la  altura  del  marco  con  cap.get(3)  y  cap.get(4).  Me  da  640x480  por  defecto.  Pero  quiero  modificarlo  a  
320x240.  Simplemente  use  ret  =  cap.set(3,320)  y  ret  =  cap.set(4,240).

Nota:  si  recibe  un  error,  asegúrese  de  que  la  cámara  funcione  bien  con  cualquier  otra  aplicación  de  cámara  (como  Cheese  en  Linux).

1.2.  Características  de  la  interfaz  gráfica  de  usuario  en  OpenCV 25
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Reproducción  de  video  desde  archivo

Es  lo  mismo  que  capturar  desde  la  cámara,  simplemente  cambie  el  índice  de  la  cámara  con  el  nombre  del  archivo  de  video.  Además,  mientras  
muestra  el  marco,  use  el  tiempo  apropiado  para  cv2.waitKey().  Si  es  demasiado  bajo,  el  video  será  muy  rápido  y  si  es  demasiado  alto,  el  video  será  
lento  (Bueno,  así  es  como  puedes  mostrar  videos  en  cámara  lenta).  25  milisegundos  estarán  bien  en  casos  normales.

importar  numpy  como  np  
importar  cv2

tapa  =  cv2.VideoCapture('vtest.avi')

while(cap.isOpened()):
derecha,  cuadro  =  cap.read()

gris  =  cv2.cvtColor(marco,  cv2.COLOR_BGR2GRAY)

cv2.imshow('frame',gray)  if  
cv2.waitKey(1)  &  0xFF  ==  ord('q'):  break

cap.release()  
cv2.destroyAllWindows()

Nota:  Asegúrese  de  que  estén  instaladas  las  versiones  adecuadas  de  ffmpeg  o  gstreamer.  A  veces,  es  un  dolor  de  cabeza  trabajar  con  Video  
Capture,  principalmente  debido  a  una  instalación  incorrecta  de  ffmpeg/gstreamer.

Guardar  un  video

Así  que  capturamos  un  video,  lo  procesamos  cuadro  por  cuadro  y  queremos  guardar  ese  video.  Para  imágenes,  es  muy  simple,  solo  use  cv2.imwrite().  
Aquí  se  requiere  un  poco  más  de  trabajo.

Esta  vez  creamos  un  objeto  VideoWriter .  Deberíamos  especificar  el  nombre  del  archivo  de  salida  (por  ejemplo:  salida.avi).  Luego  debemos  
especificar  el  código  FourCC  (detalles  en  el  siguiente  párrafo).  Luego  se  debe  pasar  el  número  de  cuadros  por  segundo  (fps)  y  el  tamaño  del  cuadro.  
Y  el  último  es  la  bandera  isColor .  Si  es  True,  el  codificador  espera  un  marco  de  color;  de  lo  contrario,  funciona  con  un  marco  en  escala  de  grises.

cuatrocc  es  un  código  de  4  bytes  que  se  utiliza  para  especificar  el  códec  de  vídeo.  La  lista  de  códigos  disponibles  se  puede  encontrar  en  fourcc.org.  
Depende  de  la  plataforma.  Los  siguientes  códecs  funcionan  bien  para  mí.

•  En  Fedora:  DIVX,  XVID,  MJPG,  X264,  WMV1,  WMV2.  (XVID  es  más  preferible.  MJPG  da  como  resultado  un  tamaño  alto
video.  X264  da  video  de  tamaño  muy  pequeño)

•  En  Windows:  DIVX  (más  por  probar  y  agregar)

•  En  OSX:  (No  tengo  acceso  a  OSX.  ¿Alguien  puede  llenar  esto?)

El  código  FourCC  se  pasa  como  cv2.VideoWriter_fourcc('M','J','P','G')  o  cv2.
VideoWriter_fourcc(*'MJPG)  para  MJPG.

Debajo  de  la  captura  de  código  de  una  cámara,  voltee  cada  cuadro  en  dirección  vertical  y  guárdelo.

importar  numpy  como  np  
importar  cv2

tapa  =  cv2.VideoCapture(0)

#  Definir  el  códec  y  crear  el  objeto  VideoWriter

26 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

fourcc  =  cv2.VideoWriter_fourcc(*'XVID')  out  =  
cv2.VideoWriter('output.avi',fourcc,  20.0,  (640,480))

while(cap.isOpened()):
ret,  marco  =  cap.read()  si  
ret==Verdadero:
cuadro  =  cv2.flip(cuadro,0)

#  escribe  el  marco  invertido.write(frame)

cv2.imshow('marco',marco)  si  
cv2.waitKey(1)  &  0xFF  ==  ord('q'):  descanso

demás:
romper

#  Liberar  todo  si  el  trabajo  ha  terminado  cap.release()  
out.release()  
cv2.destroyAllWindows()

Recursos  adicionales

Ejercicios

Funciones  de  dibujo  en  OpenCV

Meta

•  Aprende  a  dibujar  diferentes  formas  geométricas  con  OpenCV

•  Aprenderá  estas  funciones:  cv2.line(),  cv2.circle() ,  cv2.rectangle(),  cv2.ellipse(),  cv2.putText()  etc.

Código

En  todas  las  funciones  anteriores,  verá  algunos  argumentos  comunes  como  se  indica  a  continuación:

•  img :  La  imagen  donde  quieres  dibujar  las  formas

•  color :  Color  de  la  forma.  para  BGR,  páselo  como  una  tupla,  por  ejemplo:  (255,0,0)  para  azul.  Para  la  escala  de  grises,  simplemente  pase  el
valor  escalar.

•  grosor:  Grosor  de  la  línea  o  círculo,  etc.  Si  se  pasa  ­1  para  figuras  cerradas  como  círculos,  se  rellenará  la  forma.
grosor  predeterminado  =  1

•  lineType :  tipo  de  línea,  ya  sea  conectada  en  8,  línea  suavizada,  etc.  Por  defecto,  es  conectada  en  8.  cv2.LINE_AA  proporciona  una  línea  
suavizada  que  se  ve  muy  bien  para  las  curvas.

línea  de  dibujo

Para  dibujar  una  línea,  debe  pasar  las  coordenadas  de  inicio  y  finalización  de  la  línea.  Crearemos  una  imagen  negra  y  dibujaremos  una  línea  azul  sobre  ella  
desde  la  esquina  superior  izquierda  hasta  la  esquina  inferior  derecha.

1.2.  Características  de  la  interfaz  gráfica  de  usuario  en  OpenCV 27
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

importar  numpy  como  np  
importar  cv2

#  Crea  una  imagen  negra  img  =  
np.zeros((512,512,3),  np.uint8)

#  Dibuja  una  línea  diagonal  azul  con  un  grosor  de  5  px  img  =  cv2.line(img,(0,0),
(511,511),(255,0,0),5)

Rectángulo  de  dibujo

Para  dibujar  un  rectángulo,  necesita  la  esquina  superior  izquierda  y  la  esquina  inferior  derecha  del  rectángulo.  Esta  vez  dibujaremos  un  rectángulo  
verde  en  la  esquina  superior  derecha  de  la  imagen.

img  =  cv2.rectangle(img,(384,0),(510,128),(0,255,0),3)

círculo  de  dibujo

Para  dibujar  un  círculo,  necesitas  las  coordenadas  de  su  centro  y  su  radio.  Dibujaremos  un  círculo  dentro  del  rectángulo  dibujado  arriba.

img  =  cv2.circle(img,(447,63),  63,  (0,0,255),  ­1)

Dibujar  elipse

Para  dibujar  la  elipse,  necesitamos  pasar  varios  argumentos.  Un  argumento  es  la  ubicación  central  (x,y).  El  siguiente  argumento  son  las  
longitudes  de  los  ejes  (longitud  del  eje  mayor,  longitud  del  eje  menor).  ángulo  es  el  ángulo  de  rotación  de  la  elipse  en  sentido  antihorario.  
startAngle  y  endAngle  indican  el  inicio  y  el  final  del  arco  de  elipse  medido  en  el  sentido  de  las  agujas  del  reloj  desde  el  eje  principal.  es  
decir,  dar  valores  0  y  360  da  la  elipse  completa.  Para  más  detalles,  consulte  la  documentación  de  cv2.ellipse().  El  siguiente  ejemplo  dibuja  
una  media  elipse  en  el  centro  de  la  imagen.

imagen  =  cv2.elipse(imagen,(256,256),(100,50),0,0,180,255,­1)

Dibujar  polígono

Para  dibujar  un  polígono,  primero  necesitas  las  coordenadas  de  los  vértices.  Convierta  esos  puntos  en  una  matriz  de  forma  ROWSx1x2  
donde  ROWS  es  el  número  de  vértices  y  debe  ser  de  tipo  int32.  Aquí  dibujamos  un  pequeño  polígono  de  cuatro  vértices  en  color  amarillo.

puntos  =  np.matriz([[10,5],[20,30],[70,20],[50,10]],  np.int32)  puntos  =  puntos.reformar((­1,1,2) )  
img  =  cv2.polylines(img,[pts],Verdadero,
(0,255,255))

Nota:  si  el  tercer  argumento  es  Falso,  obtendrá  polilíneas  que  unen  todos  los  puntos,  no  una  forma  cerrada.

Nota:  cv2.polylines()  se  puede  usar  para  dibujar  varias  líneas.  Simplemente  cree  una  lista  de  todas  las  líneas  que  desea  dibujar  y  pásela  
a  la  función.  Todas  las  líneas  se  dibujarán  individualmente.  Es  una  forma  más  mejor  y  más  rápida  de  dibujar  un  grupo  de

28 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

líneas  que  llamar  a  cv2.line()  para  cada  línea.

Agregar  texto  a  las  imágenes:

Para  poner  textos  en  imágenes,  necesita  especificar  las  siguientes  cosas.

•  Datos  de  texto  que  desea  escribir

•  Coordenadas  de  posición  donde  desea  colocarlo  (es  decir,  esquina  inferior  izquierda  donde  comienzan  los  datos).

•  Tipo  de  fuente  (consulte  los  documentos  de  cv2.putText()  para  conocer  las  fuentes  admitidas)

•  Escala  de  fuente  (especifica  el  tamaño  de  la  fuente)

•  cosas  regulares  como  color,  grosor,  tipo  de  línea,  etc.  Para  una  mejor  apariencia,  lineType  =  cv2.LINE_AA  es
recomendado.

Escribiremos  OpenCV  sobre  nuestra  imagen  en  color  blanco.

fuente  =  cv2.FONT_HERSHEY_SIMPLEX  
cv2.putText(img,'OpenCV',(10,500),  fuente,  4,(255,255,255),2,cv2.LINE_AA)

Resultado

Así  que  es  hora  de  ver  el  resultado  final  de  nuestro  dibujo.  Como  estudiaste  en  artículos  anteriores,  despliega  la  imagen  para  verla.

1.2.  Características  de  la  interfaz  gráfica  de  usuario  en  OpenCV 29
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

1.  Los  ángulos  usados  en  la  función  de  elipse  no  son  nuestros  ángulos  circulares.  Para  más  detalles,  visite  esta  discusión.

Ejercicios

1.  Intente  crear  el  logotipo  de  OpenCV  usando  las  funciones  de  dibujo  disponibles  en  OpenCV

Ratón  como  pincel

Meta

•  Aprenda  a  manejar  eventos  de  mouse  en  OpenCV

•  Aprenderá  estas  funciones:  cv2.setMouseCallback()

30 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Demostración  sencilla

Aquí,  creamos  una  aplicación  simple  que  dibuja  un  círculo  en  una  imagen  cada  vez  que  hacemos  doble  clic  en  ella.

Primero  creamos  una  función  de  devolución  de  llamada  del  mouse  que  se  ejecuta  cuando  ocurre  un  evento  del  mouse.  El  evento  del  mouse  puede  ser  cualquier  cosa  
relacionada  con  el  mouse,  como  presionar  el  botón  izquierdo,  presionar  el  botón  izquierdo,  hacer  doble  clic  con  el  botón  izquierdo,  etc.  Nos  da  las  coordenadas  (x,  y)  para  
cada  evento  del  mouse.  Con  este  evento  y  ubicación,  podemos  hacer  lo  que  queramos.  Para  enumerar  todos  los  eventos  disponibles  disponibles,  ejecute  el  siguiente  
código  en  la  terminal  de  Python:

>>>  importar  cv2  >>>  
eventos  =  [i  for  i  in  dir(cv2)  if  'EVENT'  in  i]  >>>  imprimir  eventos

La  creación  de  la  función  de  devolución  de  llamada  del  mouse  tiene  un  formato  específico  que  es  el  mismo  en  todas  partes.  Sólo  difiere  en  lo  que  hace  la  función.  
Entonces,  nuestra  función  de  devolución  de  llamada  del  mouse  hace  una  cosa,  dibuja  un  círculo  donde  hacemos  doble  clic.  Así  que  mira  el  código  a  continuación.
El  código  se  explica  por  sí  mismo  a  partir  de  los  comentarios:

importar  cv2  
importar  numpy  como  np

#  función  de  devolución  de  llamada  del  
mouse  def  draw_circle  (event,  x,  y,  flags,  param):
si  evento  ==  cv2.EVENT_LBUTTONDBLCLK:
cv2.círculo(img,(x,y),100,(255,0,0),­1)

#  Cree  una  imagen  negra,  una  ventana  y  vincule  la  función  a  la  ventana  img  =  np.zeros((512,512,3),  np.uint8)  
cv2.namedWindow('image')  
cv2.setMouseCallback('image',draw_circle)

while(1):  
cv2.imshow('imagen',img)  if  
cv2.waitKey(20)  &  0xFF  ==  27:  romper

cv2.destroyAllWindows()

Demostración  más  avanzada

Ahora  vamos  por  mucho  más  mejor  aplicación.  En  esto,  dibujamos  rectángulos  o  círculos  (según  el  modo  que  seleccionemos)  arrastrando  el  mouse  como  lo  hacemos  en  
la  aplicación  Paint.  Entonces,  nuestra  función  de  devolución  de  llamada  del  mouse  tiene  dos  partes,  una  para  dibujar  un  rectángulo  y  otra  para  dibujar  los  círculos.  Este  
ejemplo  específico  será  realmente  útil  para  crear  y  comprender  algunas  aplicaciones  interactivas  como  el  seguimiento  de  objetos,  la  segmentación  de  imágenes,  etc.

importar  cv2  
importar  numpy  como  np

dibujo  =  Falso  #  verdadero  si  el  mouse  está  presionado  modo  =  
Verdadero  #  si  es  Verdadero,  dibuja  un  rectángulo.  Presione  'm'  para  cambiar  a  la  curva  ix,iy  =  ­1,­1

#  función  de  devolución  de  llamada  del  mouse
def  dibujar_circulo(evento,x,y,banderas,parámetro):  global  
ix,iy,dibujo,modo

si  evento  ==  cv2.EVENT_LBUTTONDOWN:
dibujo  =  Verdadero

1.2.  Características  de  la  interfaz  gráfica  de  usuario  en  OpenCV 31
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

ix,iy  =  x,y

elif  evento  ==  cv2.EVENT_MOUSEMOVE:  si  dibujo  ==  
Verdadero:
si  modo  ==  Verdadero:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),­1)
demás:
cv2.círculo(img,(x,y),5,(0,0,255),­1)

evento  elif  ==  cv2.EVENT_LBUTTONUP:
dibujo  =  Falso  si  modo  
==  Verdadero:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),­1)  más:

cv2.círculo(img,(x,y),5,(0,0,255),­1)

A  continuación,  tenemos  que  vincular  esta  función  de  devolución  de  llamada  del  mouse  a  la  ventana  de  OpenCV.  En  el  ciclo  principal,  debemos  establecer  
un  enlace  de  teclado  para  la  tecla  'm'  para  alternar  entre  rectángulo  y  círculo.

img  =  np.zeros((512,512,3),  np.uint8)  cv2.namedWindow('imagen')  
cv2.setMouseCallback('imagen',draw_circle)

mientras(1):
cv2.imshow('imagen',img)  k  =  
cv2.waitKey(1)  &  0xFF  si  k  ==  ord('m'):

modo  =  no  modo
elif  k  ==  27:
romper

cv2.destroyAllWindows()

Recursos  adicionales

Ejercicios

1.  En  nuestro  último  ejemplo,  dibujamos  un  rectángulo  relleno.  Modificas  el  código  para  dibujar  un  rectángulo  vacío.

Trackbar  como  paleta  de  colores

Meta

•  Aprenda  a  vincular  la  barra  de  seguimiento  a  las  ventanas  de  OpenCV

•  Aprenderá  estas  funciones:  cv2.getTrackbarPos(),  cv2.createTrackbar()  etc.

Demostración  de  código

Aquí  crearemos  una  aplicación  simple  que  muestra  el  color  que  especifique.  Tiene  una  ventana  que  muestra  el  color  y  tres  barras  de  
seguimiento  para  especificar  cada  uno  de  los  colores  B,  G,  R.  Deslizas  la  barra  de  seguimiento  y,  en  consecuencia,  cambia  el  color  de  la  
ventana.  De  forma  predeterminada,  el  color  inicial  se  establecerá  en  negro.

32 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Para  la  función  cv2.getTrackbarPos(),  el  primer  argumento  es  el  nombre  de  la  barra  de  seguimiento,  el  segundo  es  el  nombre  de  la  ventana  a  la  que  está  
adjunta,  el  tercer  argumento  es  el  valor  predeterminado,  el  cuarto  es  el  valor  máximo  y  el  quinto  es  la  función  de  devolución  de  llamada  que  se  ejecuta  
cada  vez  que  cambia  el  valor  de  la  barra  de  seguimiento.  La  función  de  devolución  de  llamada  siempre  tiene  un  argumento  predeterminado  que  es  la  
posición  de  la  barra  de  seguimiento.  En  nuestro  caso,  la  función  no  hace  nada,  así  que  simplemente  pasamos.

Otra  aplicación  importante  de  la  barra  de  seguimiento  es  usarla  como  botón  o  interruptor.  OpenCV,  por  defecto,  no  tiene  funcionalidad  de  botón.  Entonces  
puede  usar  la  barra  de  seguimiento  para  obtener  dicha  funcionalidad.  En  nuestra  aplicación,  hemos  creado  un  interruptor  en  el  que  la  aplicación  funciona  
solo  si  el  interruptor  está  ENCENDIDO;  de  lo  contrario,  la  pantalla  siempre  está  en  negro.

importar  cv2  
importar  numpy  como  np

definitivamente  nada(x):
aprobar

#  Crear  una  imagen  negra,  una  ventana  img  =  
np.zeros((300,512,3),  np.uint8)  cv2.namedWindow('imagen')

#  crear  barras  de  seguimiento  para  el  cambio  de  color  
cv2.createTrackbar('R','imagen',0,255,nada)  
cv2.createTrackbar('G','imagen',0,255,nada)  
cv2.createTrackbar('B','imagen',  0,255,  nada)

#  crear  el  interruptor  para  la  funcionalidad  ON/OFF  switch  =  '0 :  
OFF  \n1 :  ON'  cv2.createTrackbar(switch,  
'image',0,1,nothing)

while(1):  
cv2.imshow('imagen',img)  k  =  
cv2.waitKey(1)  &  0xFF  si  k  ==  27:

romper

#  obtener  las  posiciones  actuales  de  cuatro  trackbars  r  =  
cv2.getTrackbarPos('R','image')  g  =  
cv2.getTrackbarPos('G','image')  b  =  
cv2.getTrackbarPos('B','image')  s  =  
cv2.getTrackbarPos(cambiar,'imagen')

si  s  ==  0:
img[:]  =  0  más:

img[:]  =  [b,  g,  r]

cv2.destroyAllWindows()

La  captura  de  pantalla  de  la  aplicación  se  ve  a  continuación:

1.2.  Características  de  la  interfaz  gráfica  de  usuario  en  OpenCV 33
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Ejercicios

1.  Cree  una  aplicación  Paint  con  colores  ajustables  y  radio  de  pincel  usando  las  barras  de  seguimiento.  Para  el  dibujo,  consulte  el  anterior
Tutorial  sobre  el  manejo  del  ratón.

Operaciones  principales

•  Operaciones  básicas  en  imágenes

Aprenda  a  leer  y  editar  valores  de  píxeles,  trabajar  con  ROI  de  imágenes  y  otras  operaciones  
básicas.

•  Operaciones  aritméticas  en  imágenes

34 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Realizar  operaciones  aritméticas  en  imágenes.

•  Técnicas  de  Medición  y  Mejora  del  Desempeño

Conseguir  una  solución  es  importante.  Pero  conseguirlo  de  la  manera  más  rápida  es  más  
importante.  Aprende  a  verificar  la  velocidad  de  tu  código,  optimizar  el  código,  etc.

•  Herramientas  Matemáticas  en  OpenCV

Aprenda  algunas  de  las  herramientas  matemáticas  proporcionadas  por  OpenCV  como  PCA,  SVD
etc.

1.3.  Operaciones  principales 35
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Operaciones  básicas  en  imágenes

Meta

Aprender  a:

•  Acceder  a  valores  de  píxeles  y  modificarlos

•  Acceder  a  las  propiedades  de  la  imagen

•  Configuración  de  la  región  de  la  imagen  (ROI)

•  División  y  fusión  de  imágenes

Casi  todas  las  operaciones  en  esta  sección  están  relacionadas  principalmente  con  Numpy  en  lugar  de  OpenCV.  Se  requiere  un  buen  conocimiento  
de  Numpy  para  escribir  código  mejor  optimizado  con  OpenCV.

(Los  ejemplos  se  mostrarán  en  la  terminal  de  Python,  ya  que  la  mayoría  de  ellos  son  solo  códigos  de  una  sola  línea)

Acceso  y  modificación  de  valores  de  píxeles

Primero  carguemos  una  imagen  en  color:

>>>  importar  cv2  >>>  
importar  numpy  como  np

>>>  img  =  cv2.imread('messi5.jpg')

Puede  acceder  a  un  valor  de  píxel  por  sus  coordenadas  de  fila  y  columna.  Para  la  imagen  BGR,  devuelve  una  matriz  de  valores  azul,  verde  y  rojo.  Para  la  imagen  
en  escala  de  grises,  solo  se  devuelve  la  intensidad  correspondiente.

>>>  píxeles  =  imagen  [100,100]  
>>>  imprimir  
píxeles  [157  166  200]

#  accediendo  solo  al  píxel  azul  >>>  blue  =  
img[100,100,0]  >>>  print  blue  157

Puede  modificar  los  valores  de  píxel  de  la  misma  manera.

>>>  imagen[100,100]  =  [255,255,255]  >>>  imprimir  
imagen[100,100]  [255  255  255]

Advertencia:  Numpy  es  una  biblioteca  optimizada  para  cálculos  de  matrices  rápidos.  Por  lo  tanto,  simplemente  acceder  a  todos  y  cada  uno  de  los  valores  de  
píxel  y  modificarlos  será  muy  lento  y  no  se  recomienda.

Nota:  el  método  mencionado  anteriormente  se  usa  normalmente  para  seleccionar  una  región  de  matriz,  digamos  las  primeras  5  filas  y  las  últimas  3  columnas  así.  
Para  el  acceso  de  píxeles  individuales,  los  métodos  de  matriz  Numpy,  array.item()  y  array.itemset()  se  consideran  mejores.  Pero  siempre  devuelve  un  escalar.  
Entonces,  si  desea  acceder  a  todos  los  valores  B,  G,  R,  debe  llamar  a  array.item()  por  separado  para  todos.

Mejor  método  de  acceso  y  edición  de  píxeles:

36 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

#  accediendo  al  valor  ROJO  >>>  
img.item(10,10,2)  59

#  modificando  el  valor  ROJO  
>>>  img.itemset((10,10,2),100)  >>>  
img.item(10,10,2)
100

Acceso  a  las  propiedades  de  la  imagen

Las  propiedades  de  la  imagen  incluyen  el  número  de  filas,  columnas  y  canales,  el  tipo  de  datos  de  la  imagen,  el  número  de  píxeles,  etc.

Se  accede  a  la  forma  de  la  imagen  mediante  img.shape.  Devuelve  una  tupla  de  número  de  filas,  columnas  y  canales  (si  la  imagen  es  color):

>>>  imprimir  img.forma  (342,  
548,  3)

Nota:  si  la  imagen  está  en  escala  de  grises,  la  tupla  devuelta  contiene  solo  un  número  de  filas  y  columnas.  Por  lo  tanto,  es  un  buen  método  para  verificar  si  la  
imagen  cargada  es  una  imagen  en  escala  de  grises  o  en  color.

Se  accede  al  número  total  de  píxeles  mediante  img.size:

>>>  imprimir  img.tamaño  
562248

El  tipo  de  datos  de  la  imagen  se  obtiene  mediante  img.dtype:

>>>  imprimir  img.dtype  uint8

Nota:  img.dtype  es  muy  importante  durante  la  depuración  porque  una  gran  cantidad  de  errores  en  el  código  OpenCV­Python  son  causados  por  tipos  de  datos  
no  válidos.

Retorno  de  la  inversión  de  la  imagen

A  veces,  tendrás  que  jugar  con  cierta  región  de  imágenes.  Para  la  detección  de  ojos  en  imágenes,  primero  realice  la  detección  de  rostros  sobre  la  imagen  hasta  
que  se  encuentre  el  rostro,  luego  busque  ojos  dentro  de  la  región  del  rostro.  Este  enfoque  mejora  la  precisión  (porque  los  ojos  siempre  están  en  las  caras :D)  y  
el  rendimiento  (porque  buscamos  un  área  pequeña).

El  ROI  se  obtiene  nuevamente  utilizando  la  indexación  de  Numpy.  Aquí  estoy  seleccionando  la  pelota  y  copiándola  en  otra  región  de  la  imagen:

>>>  pelota  =  img[280:340,  330:390]  >>>  
img[273:333,  100:160]  =  pelota

Compruebe  los  resultados  a  continuación:

1.3.  Operaciones  principales 37
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Dividir  y  fusionar  canales  de  imagen

Los  canales  B,  G,  R  de  una  imagen  se  pueden  dividir  en  sus  planos  individuales  cuando  sea  necesario.  Luego,  los  canales  individuales  
se  pueden  volver  a  fusionar  para  formar  una  imagen  BGR  nuevamente.  Esto  puede  ser  realizado  por:

>>>  b,g,r  =  cv2.dividir(img)  >>>  img  =  
cv2.merge((b,g,r))

>>>  b  =  imagen[:,:,0]

Supongamos  que  quiere  hacer  que  todos  los  píxeles  rojos  sean  cero,  no  necesita  dividirlos  así  y  ponerlos  a  cero.  Simplemente  puede  
usar  la  indexación  de  Numpy,  que  es  más  rápida.

>>>  imagen[:,:,2]  =  0

Advertencia:  cv2.split()  es  una  operación  costosa  (en  términos  de  tiempo),  así  que  utilícela  solo  si  es  necesario.  La  indexación  numpy  
es  mucho  más  eficiente  y  debe  usarse  si  es  posible.

Creación  de  bordes  para  imágenes  (relleno)

Si  desea  crear  un  borde  alrededor  de  la  imagen,  algo  así  como  un  marco  de  fotos,  puede  usar  la  función  cv2.copyMakeBorder() .  Pero  
tiene  más  aplicaciones  para  operaciones  de  convolución,  relleno  de  ceros,  etc.  Esta  función  toma  los  siguientes  argumentos:

•  src  ­  imagen  de  entrada

•  arriba,  abajo,  izquierda,  derecha :  ancho  del  borde  en  número  de  píxeles  en  las  direcciones  correspondientes

38 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

•  borderType:  indicador  que  define  qué  tipo  de  borde  se  agregará.  Puede  ser  de  los  siguientes  tipos:

–  cv2.BORDER_CONSTANT :  agrega  un  borde  de  color  constante.  El  valor  debe  ser  dado  como  sigue
argumento.

–  cv2.BORDER_REFLECT  ­  El  borde  será  un  reflejo  especular  de  los  elementos  del  borde,  así:  fed  cba|abcdefgh|hgfedcb

–  cv2.BORDER_REFLECT_101  o  cv2.BORDER_DEFAULT  ­  Igual  que  el  anterior,  pero  con  un  ligero
cambiar,  así:  gfedcb|abcdefgh|gfedcba

–  cv2.BORDER_REPLICATE  ­  El  último  elemento  se  replica  completamente,  así:
aaaaaaa|abcdefgh|hhhhhh

–  cv2.BORDER_WRAP  ­  No  puedo  explicarlo,  se  verá  así:  cdefgh|abcdefgh|abcdefg

•  valor :  color  del  borde  si  el  tipo  de  borde  es  cv2.BORDER_CONSTANT

A  continuación  se  muestra  un  código  de  muestra  que  demuestra  todos  estos  tipos  de  borde  para  una  mejor  comprensión:

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

AZUL  =  [255,0,0]

img1  =  cv2.imread('opencv_logo.png')

replicate  =  cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REPLICATE)  reflect  =  
cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT)  reflect101  =  cv2.copyMakeBorder(img1,10,  
10,10,10,cv2.BORDER_REFLECT_101)  wrap  =  cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_WRAP)  
constante=  cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_CONSTANT,  valor=AZUL)

plt.subplot(231),plt.imshow(img1,'gris'),plt.title('ORIGINAL')  plt.subplot  
(232),plt.imshow(replicar,'gris'),plt.title('REPLICAR  ')  plt.subplot(233),plt.imshow(reflejar,'gris'),plt.title('REFLECT')  
plt.subplot  (234),plt.imshow(reflect101,'gris'),plt.title( 'REFLECT_101')  
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')  plt.subplot  (236),plt.imshow(constante,'gray'),plt.  
titulo('CONSTANTE')

plt.mostrar()

Vea  el  resultado  a  continuación.  (La  imagen  se  muestra  con  matplotlib.  Entonces,  los  planos  ROJO  y  AZUL  se  intercambiarán):

1.3.  Operaciones  principales 39
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

Ejercicios

Operaciones  aritméticas  en  imágenes

Meta

•  Aprenda  varias  operaciones  aritméticas  en  imágenes  como  sumas,  restas,  operaciones  bit  a  bit,  etc.

•  Aprenderá  estas  funciones:  cv2.add(),  cv2.addWeighted()  etc.

Adición  de  imagen

Puede  agregar  dos  imágenes  mediante  la  función  OpenCV,  cv2.add()  o  simplemente  mediante  una  operación  numérica,  res  =  img1  +  img2.
Ambas  imágenes  deben  tener  la  misma  profundidad  y  tipo,  o  la  segunda  imagen  puede  ser  simplemente  un  valor  escalar.

Nota:  Hay  una  diferencia  entre  la  adición  de  OpenCV  y  la  adición  de  Numpy.  La  adición  de  OpenCV  es  una  operación  saturada,  mientras  
que  la  adición  de  Numpy  es  una  operación  de  módulo.

40 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Por  ejemplo,  considere  la  siguiente  muestra:

>>>  x  =  np.uint8([250])  >>>  y  =  
np.uint8([10])

>>>  imprimir  cv2.add(x,y)  #  250+10  =  260  =>  255  [[255]]

>>>  imprime  x+y  [4] #  250+10  =  260  %  256  =  4

Será  más  visible  cuando  agregue  dos  imágenes.  La  función  OpenCV  proporcionará  un  mejor  resultado.  Así  que  siempre  es  mejor  ceñirse  a  
las  funciones  de  OpenCV.

Fusión  de  imágenes

Esto  también  es  una  adición  de  imágenes,  pero  se  les  da  diferentes  pesos  a  las  imágenes  para  que  den  una  sensación  de  fusión  o  
transparencia.  Las  imágenes  se  agregan  según  la  siguiente  ecuación:

( )  =  (1  − )  0( )  +  1( )

Al  variar  de  0  →  1,  puede  realizar  una  transición  genial  entre  una  imagen  y  otra.

Aquí  tomé  dos  imágenes  para  mezclarlas.  La  primera  imagen  tiene  un  peso  de  0,7  y  la  segunda  imagen  tiene  un  peso  de  0,3.  
cv2.addWeighted()  aplica  la  siguiente  ecuación  en  la  imagen.

=  ∙ 1  +  ∙ 2  +

Aquí  se  toma  como  cero.

img1  =  cv2.imread('ml.png')  img2  =  
cv2.imread('opencv_logo.jpg')

dst  =  cv2.addWeighted(img1,0.7,img2,0.3,0)

cv2.imshow('dst',dst)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

Compruebe  el  resultado  a  continuación:

1.3.  Operaciones  principales 41
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Operaciones  bit  a  bit

Esto  incluye  operaciones  bit  a  bit  AND,  OR,  NOT  y  XOR.  Serán  muy  útiles  al  extraer  cualquier  parte  de  la  imagen  (como  
veremos  en  los  próximos  capítulos),  definir  y  trabajar  con  ROI  no  rectangular,  etc.  A  continuación,  veremos  un  ejemplo  
sobre  cómo  cambiar  una  región  particular  de  una  imagen.

Quiero  poner  el  logotipo  de  OpenCV  encima  de  una  imagen.  Si  agrego  dos  imágenes,  cambiará  de  color.  Si  lo  difumino,  obtengo  un  efecto  transparente.  
Pero  quiero  que  sea  opaco.  Si  fuera  una  región  rectangular,  podría  usar  el  ROI  como  lo  hicimos  en  el  último  capítulo.  Pero  el  logotipo  de  OpenCV  no  
tiene  forma  rectangular.  Entonces  puede  hacerlo  con  operaciones  bit  a  bit  como  se  muestra  a  continuación:

#  Cargar  dos  imágenes  
img1  =  cv2.imread('messi5.jpg')  img2  =  
cv2.imread('opencv_logo.png')

#  Quiero  poner  el  logotipo  en  la  esquina  superior  izquierda,  así  que  creo  un  ROI  
filas,columnas,canales  =  img2.shape  roi  =  
img1[0:filas,  0:columnas]

#  Ahora  crea  una  máscara  de  logo  y  crea  también  su  máscara  inversa  img2gray  =  
cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)  ret,  mask  =  
cv2.threshold(img2gray,  10,  255,  cv2.THRESH_BINARY)  mask_inv  =  cv2.bitwise_not(mask )

#  Ahora  oscurezca  el  área  del  logotipo  en  ROI  img1_bg  =  
cv2.bitwise_and(roi,roi,mask  =  mask_inv)

#  Tomar  solo  la  región  del  logotipo  de  la  imagen  del  logotipo.  
img2_fg  =  cv2.bitwise_and(img2,img2,máscara  =  máscara)

#  Poner  logo  en  ROI  y  modificar  la  imagen  principal  dst  =  
cv2.add(img1_bg,img2_fg)  img1[0:rows,  
0:cols ]  =  dst

cv2.imshow('res',img1)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

Vea  el  resultado  a  continuación.  La  imagen  de  la  izquierda  muestra  la  máscara  que  creamos.  La  imagen  de  la  derecha  muestra  el  resultado  final.  Para  
una  mayor  comprensión,  muestre  todas  las  imágenes  intermedias  en  el  código  anterior,  especialmente  img1_bg  e  img2_fg.

42 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

Ejercicios

1.  Cree  una  presentación  de  diapositivas  de  imágenes  en  una  carpeta  con  una  transición  suave  entre  imágenes  usando  cv2.addWeighted
función

Técnicas  de  Medición  y  Mejora  del  Desempeño

Meta

En  el  procesamiento  de  imágenes,  dado  que  se  trata  de  una  gran  cantidad  de  operaciones  por  segundo,  es  obligatorio  que  su  código  no  solo  
proporcione  la  solución  correcta,  sino  también  de  la  manera  más  rápida.  Entonces,  en  este  capítulo,  aprenderá

•  Para  medir  el  rendimiento  de  su  código.

•  Algunos  consejos  para  mejorar  el  rendimiento  de  su  código.

•  Verá  estas  funciones:  cv2.getTickCount,  cv2.getTickFrequency ,  etc.

Además  de  OpenCV,  Python  también  proporciona  un  tiempo  de  módulo  que  es  útil  para  medir  el  tiempo  de  ejecución.  Otro  perfil  de  módulo  
ayuda  a  obtener  un  informe  detallado  sobre  el  código,  como  cuánto  tiempo  tomó  cada  función  en  el  código,  cuántas  veces  se  llamó  a  la  
función,  etc.  Pero,  si  está  utilizando  IPython,  todas  estas  funciones  están  integradas  en  un  fácil  de  usar  manera.  Veremos  algunos  importantes  
y,  para  obtener  más  detalles,  consulte  los  enlaces  en  la  sección  Recursos  adicionales .

Medición  del  rendimiento  con  OpenCV

La  función  cv2.getTickCount  devuelve  el  número  de  ciclos  de  reloj  después  de  un  evento  de  referencia  (como  el  momento  en  que  se  encendió  
la  máquina)  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.

La  función  cv2.getTickFrequency  devuelve  la  frecuencia  de  los  ciclos  de  reloj,  o  el  número  de  ciclos  de  reloj  por  segundo.  Entonces,  para  
encontrar  el  tiempo  de  ejecución  en  segundos,  puede  hacer  lo  siguiente:

e1  =  cv2.getTickCount()  #  la  
ejecución  de  su  código  e2  =  
cv2.getTickCount()  time  =  (e2  ­  e1)/  
cv2.getTickFrequency()

Lo  demostraremos  con  el  siguiente  ejemplo.  El  siguiente  ejemplo  aplica  el  filtrado  mediano  con  un  núcleo  de  tamaño  impar  que  va  de  5  a  49.  
(No  se  preocupe  por  cómo  se  verá  el  resultado,  ese  no  es  nuestro  objetivo):

img1  =  cv2.imread('messi5.jpg')

e1  =  cv2.getTickCount()  for  i  in  
xrange(5,49,2):  img1  =  
cv2.medianBlur(img1,i)  e2  =  cv2.getTickCount()  
t  =  (e2  ­  e1)/cv2.getTickFrequency()  
print  t

#  El  resultado  que  obtuve  es  0.521107655  segundos

1.3.  Operaciones  principales 43
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Nota:  Puedes  hacer  lo  mismo  con  el  módulo  de  tiempo.  En  lugar  de  cv2.getTickCount,  use  la  función  time.time().
Luego  toma  la  diferencia  de  dos  veces.

Optimización  por  defecto  en  OpenCV

Muchas  de  las  funciones  de  OpenCV  están  optimizadas  usando  SSE2,  AVX,  etc.  También  contiene  código  no  optimizado.  Entonces,  si  
nuestro  sistema  admite  estas  características,  deberíamos  explotarlas  (casi  todos  los  procesadores  modernos  las  admiten).  Está  habilitado  
por  defecto  durante  la  compilación.  Entonces,  OpenCV  ejecuta  el  código  optimizado  si  está  habilitado;  de  lo  contrario,  ejecuta  el  código  no  optimizado.
Puede  usar  cv2.useOptimized()  para  verificar  si  está  habilitado/deshabilitado  y  cv2.setUseOptimized()  para  habilitarlo/deshabilitarlo.
Veamos  un  ejemplo  sencillo.

#  verificar  si  la  optimización  está  habilitada  En  [5]:  
cv2.useOptimized()
Salida[5]:  Verdadero

En  [6]:  %timeit  res  =  cv2.medianBlur(img,49)  10  bucles,  lo  mejor  de  3:  
34,9  ms  por  bucle

#  Deshabilitarlo
En  [7]:  cv2.setUseOptimized(Falso)

En  [8]:  cv2.useOptimized()
Salida[8]:  Falso

En  [9]:  %timeit  res  =  cv2.medianBlur(img,49)  10  bucles,  lo  mejor  de  3:  
64,1  ms  por  bucle

Verá,  el  filtrado  medio  optimizado  es  ~2  veces  más  rápido  que  la  versión  no  optimizada.  Si  verifica  su  fuente,  puede  ver  que  el  filtrado  medio  está  
optimizado  para  SIMD.  Entonces  puede  usar  esto  para  habilitar  la  optimización  en  la  parte  superior  de  su  código  (recuerde  que  está  habilitado  de  
manera  predeterminada).

Medición  del  rendimiento  en  IPython

A  veces,  es  posible  que  necesite  comparar  el  rendimiento  de  dos  operaciones  similares.  IPython  le  da  un  comando  mágico  %timeit  para  
realizar  esto.  Ejecuta  el  código  varias  veces  para  obtener  resultados  más  precisos.  Una  vez  más,  son  adecuados  para  medir  códigos  de  una  
sola  línea.

Por  ejemplo,  ¿sabes  cuál  de  las  siguientes  operaciones  de  suma  es  mejor,  x  =  5;  y  =  x**2,  x  =  5;  y  =  x*x,  x  =  np.uint8([5]);  y  =  x*x  o  y  =  
np.square(x) ?  Lo  encontraremos  con  %timeit  en  el  shell  de  IPython.

En  [10]:  x  =  5

En  [11]:  %timeit  y=x**2  10000000  
bucles,  lo  mejor  de  3:  73  ns  por  bucle

En  [12]:  %timeit  y=x*x  10000000  
bucles,  lo  mejor  de  3:  58,3  ns  por  bucle

En  [15]:  z  =  np.uint8([5])

En  [17]:  %timeit  y=z*z  1000000  
bucles,  lo  mejor  de  3:  1,25  us  por  bucle

44 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

En  [19]:  %timeit  y=np.square(z)  1000000  bucles,  
lo  mejor  de  3:  1,16  us  por  bucle

Puedes  ver  que,  x  =  5;  y  =  x*x  es  más  rápido  y  es  alrededor  de  20  veces  más  rápido  en  comparación  con  Numpy.  Si  también  considera  la  creación  de  
matrices,  puede  alcanzar  hasta  100  veces  más  rápido.  ¿Guay,  verdad?  (Los  desarrolladores  de  Numpy  están  trabajando  en  este  problema)

Nota:  Las  operaciones  escalares  de  Python  son  más  rápidas  que  las  operaciones  escalares  de  Numpy.  Entonces,  para  operaciones  que  incluyen  uno  o  
dos  elementos,  Python  escalar  es  mejor  que  las  matrices  Numpy.  Numpy  se  aprovecha  cuando  el  tamaño  de  la  matriz  es  un  poco  más  grande.

Probaremos  un  ejemplo  más.  Esta  vez,  compararemos  el  rendimiento  de  cv2.countNonZero()  y  np.count_nonzero()  para  la  misma  imagen.

En  [35]:  %timeit  z  =  cv2.countNonZero(img)  100000  bucles,  lo  
mejor  de  3:  15,8  us  por  bucle

En  [36]:  %timeit  z  =  np.count_nonzero(img)  1000  bucles,  lo  mejor  
de  3:  370  us  por  bucle

Mira,  la  función  OpenCV  es  casi  25  veces  más  rápida  que  la  función  Numpy.

Nota:  Normalmente,  las  funciones  de  OpenCV  son  más  rápidas  que  las  funciones  de  Numpy.  Entonces,  para  la  misma  operación,  se  prefieren  las  funciones  
de  OpenCV.  Pero  puede  haber  excepciones,  especialmente  cuando  Numpy  trabaja  con  vistas  en  lugar  de  copias.

Más  comandos  mágicos  de  IPython

Hay  varios  otros  comandos  mágicos  para  medir  el  rendimiento,  perfilado,  perfilado  de  línea,  medición  de  memoria,  etc.  Todos  ellos  están  bien  
documentados.  Por  lo  tanto,  aquí  solo  se  proporcionan  enlaces  a  esos  documentos.  Se  recomienda  a  los  lectores  interesados  que  los  prueben.

Técnicas  de  optimización  del  rendimiento

Existen  varias  técnicas  y  métodos  de  codificación  para  aprovechar  al  máximo  el  rendimiento  de  Python  y  Numpy.  Aquí  solo  se  mencionan  los  relevantes  y  
se  brindan  enlaces  a  fuentes  importantes.  Lo  principal  a  tener  en  cuenta  aquí  es  que,  primero  intente  implementar  el  algoritmo  de  una  manera  simple.  Una  
vez  que  esté  funcionando,  perfilarlo,  encontrar  los  cuellos  de  botella  y  optimizarlos.

1.  Evite  usar  bucles  en  Python  en  la  medida  de  lo  posible,  especialmente  bucles  dobles/triples,  etc.  Son  inherentemente  lentos.

2.  Vectorice  el  algoritmo/código  en  la  mayor  medida  posible  porque  Numpy  y  OpenCV  están  optimizados  para
operaciones  vectoriales.

3.  Explotar  la  coherencia  de  caché.

4.  Nunca  haga  copias  de  la  matriz  a  menos  que  sea  necesario.  Trate  de  usar  vistas  en  su  lugar.  La  copia  de  matriz  es  una  operación  costosa.

Incluso  después  de  realizar  todas  estas  operaciones,  si  su  código  aún  es  lento  o  si  el  uso  de  bucles  grandes  es  inevitable,  use  bibliotecas  adicionales  como  
Cython  para  hacerlo  más  rápido.

Recursos  adicionales

1.  Técnicas  de  optimización  de  Python

2.  Notas  de  clase  de  Scipy  ­  Numpy  avanzado

1.3.  Operaciones  principales 45
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

3.  Temporización  y  creación  de  perfiles  en  IPython

Ejercicios

Herramientas  Matemáticas  en  OpenCV

Procesamiento  de  imágenes  en  OpenCV

•  Cambio  de  espacios  de  color

Aprende  a  cambiar  imágenes  entre  diferentes  espacios  de  color.
Además,  aprenda  a  rastrear  un  objeto  de  color  en  un  video.

•  Transformaciones  Geométricas  de  Imágenes

Aprenda  a  aplicar  diferentes  transformaciones  geométricas  a  imágenes  como  rotación,  traslación,  
etc.

•  Umbral  de  imagen

Aprenda  a  convertir  imágenes  en  imágenes  binarias  mediante  umbralización  global,  umbralización  
adaptativa,  binarización  de  Otsu,  etc.

•  Suavizado  de  imágenes

Aprenda  a  desenfocar  las  imágenes,  filtrar  las  imágenes  con  núcleos  personalizados,  etc.

•  Transformaciones  morfológicas

46 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Aprenda  sobre  transformaciones  morfológicas  como  erosión,  dilatación,  apertura,  cierre,  etc.

•  Gradientes  de  imagen

Aprenda  a  encontrar  gradientes  de  imagen,  bordes,  etc.

•  Detección  de  borde  astuto

Aprenda  a  encontrar  bordes  con  Canny  Edge  Detection

•  Pirámides  de  imágenes

Aprenda  sobre  las  pirámides  de  imágenes  y  cómo  usarlas  para  la  combinación  de  imágenes

•  Contornos  en  OpenCV

Todo  sobre  Contornos  en  OpenCV

•  Histogramas  en  OpenCV

1.4.  Procesamiento  de  imágenes  en  OpenCV 47
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Todo  sobre  histogramas  en  OpenCV

•  Transformaciones  de  imagen  en  OpenCV

Conozca  diferentes  transformaciones  de  imagen  en  OpenCV  como  la  transformada  de  Fourier,  la  
transformada  de  coseno,  etc.

•  Coincidencia  de  plantillas

Aprenda  a  buscar  un  objeto  en  una  imagen  mediante  la  coincidencia  de  plantillas

•  Transformación  de  la  línea  de  Hough

Aprende  a  detectar  líneas  en  una  imagen

•  Transformación  del  círculo  de  Hough

Aprende  a  detectar  círculos  en  una  imagen

•  Segmentación  de  imágenes  con  algoritmo  Watershed

48 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Aprende  a  segmentar  imágenes  con  segmentación  de  cuencas  hidrográficas

•  Extracción  interactiva  en  primer  plano  mediante  el  algoritmo  GrabCut

Aprenda  a  extraer  el  primer  plano  con  el  algoritmo  GrabCut

1.4.  Procesamiento  de  imágenes  en  OpenCV 49
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Cambio  de  espacios  de  color

Meta

•  En  este  tutorial,  aprenderá  a  convertir  imágenes  de  un  espacio  de  color  a  otro,  como  BGR  ↔  Gray,  BGR
↔  VHS,  etc.

•  Además  de  eso,  crearemos  una  aplicación  que  extraiga  un  objeto  coloreado  en  un  video

•  Aprenderá  las  siguientes  funciones:  cv2.cvtColor(),  cv2.inRange()  etc.

Cambiar  el  espacio  de  color

Hay  más  de  150  métodos  de  conversión  de  espacio  de  color  disponibles  en  OpenCV.  Pero  solo  veremos  dos  que  son  los  más  utilizados,  BGR  ↔  
Gray  y  BGR  ↔  HSV.

Para  la  conversión  de  color,  usamos  la  función  cv2.cvtColor(input_image,  flag)  donde  flag  determina  el  tipo  de  conversión.

Para  la  conversión  de  BGR  →  Gray  usamos  las  banderas  cv2.COLOR_BGR2GRAY.  De  manera  similar,  para  BGR  →  HSV,  usamos  la  bandera  
cv2.COLOR_BGR2HSV.  Para  obtener  otras  banderas,  simplemente  ejecute  los  siguientes  comandos  en  su  terminal  de  Python:

>>>  import  cv2  >>>  
flags  =  [i  for  i  in  dir(cv2)  if  i.startswith('COLOR_')]  >>>  print  flags

Nota:  Para  HSV,  el  rango  de  tono  es  [0,179],  el  rango  de  saturación  es  [0,255]  y  el  rango  de  valor  es  [0,255].  Diferentes  softwares  usan  diferentes  
escalas.  Entonces,  si  está  comparando  los  valores  de  OpenCV  con  ellos,  debe  normalizar  estos  rangos.

Seguimiento  de  objetos

Ahora  que  sabemos  cómo  convertir  una  imagen  BGR  a  HSV,  podemos  usar  esto  para  extraer  un  objeto  coloreado.  En  HSV,  es  más  fácil  
representar  un  color  que  el  espacio  de  color  RGB.  En  nuestra  aplicación,  intentaremos  extraer  un  objeto  de  color  azul.  Así  que  aquí  está  el  método:

•  Toma  cada  cuadro  del  video

•  Convertir  de  espacio  de  color  BGR  a  HSV

•  Umbramos  la  imagen  HSV  para  un  rango  de  color  azul

•  Ahora  extraiga  el  objeto  azul  solo,  podemos  hacer  lo  que  queramos  en  esa  imagen.

A  continuación  se  muestra  el  código  que  se  comenta  en  detalle:

importar  cv2  
importar  numpy  como  np

tapa  =  cv2.VideoCapture(0)

mientras(1):

#  Toma  cada  cuadro
_, marco  =  cap.read()

#  Convertir  BGR  a  HSV

50 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

hsv  =  cv2.cvtColor(marco,  cv2.COLOR_BGR2HSV)

#  definir  rango  de  color  azul  en  HSV  lower_blue  =  
np.array([110,50,50])  upper_blue  =  np.array([130,255,255])

#  Umbral  de  la  imagen  HSV  para  obtener  solo  máscara  de  colores  azules  =  
cv2.inRange(hsv,  lower_blue,  upper_blue)

#  Bitwise­AND  mask  e  imagen  original  res  =  
cv2.bitwise_and(frame,frame,  mask=  mask)

cv2.imshow('marco',marco)  
cv2.imshow('máscara',máscara)  
cv2.imshow('res',res)  k  =  
cv2.waitKey(5)  &  0xFF  si  k  ==  27:

romper

cv2.destroyAllWindows()

La  imagen  de  abajo  muestra  el  seguimiento  del  objeto  azul:

Nota:  Hay  algunos  ruidos  en  la  imagen.  Veremos  cómo  eliminarlos  en  capítulos  posteriores.

Nota:  Este  es  el  método  más  simple  en  el  seguimiento  de  objetos.  Una  vez  que  aprenda  las  funciones  de  los  contornos,  puede  hacer  muchas  
cosas  como  encontrar  el  centroide  de  este  objeto  y  usarlo  para  rastrear  el  objeto,  dibujar  diagramas  simplemente  moviendo  la  mano  frente  a  la  
cámara  y  muchas  otras  cosas  divertidas.

¿Cómo  encontrar  valores  HSV  para  rastrear?

Esta  es  una  pregunta  común  que  se  encuentra  en  stackoverflow.com.  Es  muy  simple  y  puedes  usar  la  misma  función,  cv2.cvtColor().  En  lugar  de  
pasar  una  imagen,  solo  pasa  los  valores  BGR  que  desea.  Por  ejemplo,  para  encontrar  el

1.4.  Procesamiento  de  imágenes  en  OpenCV 51
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Valor  HSV  de  Green,  intente  seguir  los  comandos  en  la  terminal  de  Python:

>>>  verde  =  np.uint8([[[0,255,0 ]]])  >>>  hsv_green  =  
cv2.cvtColor(green,cv2.COLOR_BGR2HSV)  >>>  print  hsv_green  [[[ 60  255  255]]]

Ahora  toma  [H­10,  100,100]  y  [H+10,  255,  255]  como  límite  inferior  y  límite  superior  respectivamente.  Además  de  este  método,  puede  
usar  cualquier  herramienta  de  edición  de  imágenes  como  GIMP  o  cualquier  convertidor  en  línea  para  encontrar  estos  valores,  pero  no  
olvide  ajustar  los  rangos  de  HSV.

Recursos  adicionales

Ejercicios

1.  Intente  encontrar  una  manera  de  extraer  más  de  un  objeto  de  color,  por  ejemplo,  extraer  objetos  rojos,  azules  y  verdes  simultáneamente.

Umbral  de  imagen

Meta

•  En  este  tutorial,  aprenderá  umbralización  simple,  umbralización  adaptativa,  umbralización  de  Otsu,  etc.

•  Aprenderá  estas  funciones:  cv2.threshold,  cv2.adaptiveThreshold ,  etc.

Umbral  simple

Aquí,  el  asunto  es  sencillo.  Si  el  valor  del  píxel  es  mayor  que  un  valor  de  umbral,  se  le  asigna  un  valor  (puede  ser  blanco),  de  lo  contrario,  
se  le  asigna  otro  valor  (puede  ser  negro).  La  función  utilizada  es  cv2.threshold.  El  primer  argumento  es  la  imagen  de  origen,  que  debería  
ser  una  imagen  en  escala  de  grises.  El  segundo  argumento  es  el  valor  de  umbral  que  se  utiliza  para  clasificar  los  valores  de  píxel.  El  
tercer  argumento  es  maxVal,  que  representa  el  valor  que  se  dará  si  el  valor  del  píxel  es  mayor  (a  veces  menor  que)  el  valor  del  umbral.  
OpenCV  proporciona  diferentes  estilos  de  umbralización  y  se  decide  por  el  cuarto  parámetro  de  la  función.  Los  diferentes  tipos  son:

•  cv2.THRESH_BINARIO

•  cv2.THRESH_BINARY_INV

•  cv2.THRESH_TRUNC

•  cv2.THRESH_TOZERO

•  cv2.THRESH_TOZERO_INV

La  documentación  explica  claramente  para  qué  sirve  cada  tipo.  Por  favor,  consulte  la  documentación.

Se  obtienen  dos  salidas.  El  primero  es  un  retval  que  se  explicará  más  adelante.  La  segunda  salida  es  nuestra  imagen  con  umbral.

Código:

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('gradient.png',0)  ret,thresh1  =  
cv2.threshold(img,127,255,cv2.THRESH_BINARY)  ret,thresh2  =  
cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)

52 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

ret,thresh3  =  cv2.threshold(img,127,255,cv2.THRESH_TRUNC)  ret,thresh4  =  
cv2.threshold(img,127,255,cv2.THRESH_TOZERO)  ret,thresh5  =  
cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)

títulos  =  ['Imagen  original  ','BINARIO','BINARIO_INV','TRUNC','TOZERO','TOZERO_INV']  imágenes  =  [img,  umbral1,  umbral2,  
umbral3,  umbral4,  umbral5]

para  i  en  xrange(6):
plt.subplot(2,3,i+1),plt.imshow(imágenes[i],'gris')  plt.title(títulos[i])  
plt.xticks([]),plt.yticks([])

plt.mostrar()

Nota:  para  trazar  varias  imágenes,  hemos  utilizado  la  función  plt.subplot().  Consulte  los  documentos  de  Matplotlib  para  obtener  más  detalles.

El  resultado  se  da  a  continuación:

Umbral  adaptativo

En  la  sección  anterior,  usamos  un  valor  global  como  valor  de  umbral.  Pero  puede  que  no  sea  bueno  en  todas  las  condiciones  en  las  que  la  
imagen  tiene  diferentes  condiciones  de  iluminación  en  diferentes  áreas.  En  ese  caso,  optamos  por  el  umbral  adaptativo.  En  esto,  el  algoritmo  
calcula  el  umbral  para  una  pequeña  región  de  la  imagen.  Entonces  obtenemos  diferentes  umbrales  para  diferentes  regiones  de  la  misma  
imagen  y  nos  da  mejores  resultados  para  imágenes  con  iluminación  variable.

Tiene  tres  parámetros  de  entrada  'especiales'  y  solo  un  argumento  de  salida.

Método  adaptativo:  decide  cómo  se  calcula  el  valor  de  umbral.

1.4.  Procesamiento  de  imágenes  en  OpenCV 53
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

•  cv2.ADAPTIVE_THRESH_MEAN_C:  el  valor  del  umbral  es  la  media  del  área  vecina.

•  cv2.ADAPTIVE_THRESH_GAUSSIAN_C:  el  valor  del  umbral  es  la  suma  ponderada  del  valor  del  vecindario
ues  donde  los  pesos  son  una  ventana  gaussiana.

Tamaño  de  bloque :  decide  el  tamaño  del  área  del  vecindario.

C  ­  Es  solo  una  constante  que  se  resta  de  la  media  o  media  ponderada  calculada.

El  siguiente  fragmento  de  código  compara  el  umbral  global  y  el  umbral  adaptativo  para  una  imagen  con  iluminación  variable:

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('dave.jpg',0)  img  =  
cv2.medianBlur(img,5)

ret,th1  =  cv2.threshold(img,127,255,cv2.THRESH_BINARY)  th2  =  
cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
cv2.UMBRAL_BINARIO,11,2)  th3  =  
cv2.umbral  adaptativo(img,255,cv2.UMBRAL_ADAPTADOR_GAUSSIAN_C,\  cv2.UMBRAL_BINARIO,11,2)

titles  =  ['Imagen  original',  'Umbral  global  (v  =  127)',
'Umbral  medio  adaptativo',  'Umbral  gaussiano  adaptativo']
imágenes  =  [img,  th1,  th2,  th3]

para  i  en  xrange(4):
plt.subplot(2,2,i+1),plt.imshow(imágenes[i],'gris')  plt.title(títulos[i])  
plt.xticks([]),plt.yticks([])

plt.mostrar()

Resultado :

54 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Binarización  de  Otsu

En  la  primera  sección,  les  dije  que  hay  un  segundo  parámetro  retVal.  Su  uso  viene  cuando  vamos  por  la  Binarización  de  Otsu.
¿Así  que  qué  es  lo?

En  el  umbral  global,  usamos  un  valor  arbitrario  para  el  valor  del  umbral,  ¿verdad?  Entonces,  ¿cómo  podemos  saber  que  un  valor  que  
seleccionamos  es  bueno  o  no?  La  respuesta  es,  método  de  prueba  y  error.  Pero  considere  una  imagen  bimodal  (en  palabras  simples,  la  
imagen  bimodal  es  una  imagen  cuyo  histograma  tiene  dos  picos).  Para  esa  imagen,  podemos  tomar  aproximadamente  un  valor  en  el  
medio  de  esos  picos  como  valor  de  umbral,  ¿verdad?  Eso  es  lo  que  hace  la  binarización  de  Otsu.  Entonces,  en  palabras  simples,  calcula  
automáticamente  un  valor  de  umbral  del  histograma  de  la  imagen  para  una  imagen  bimodal.  (Para  imágenes  que  no  son  bimodales,  la  
binarización  no  será  precisa).

Para  esto,  se  utiliza  nuestra  función  cv2.threshold(),  pero  se  pasa  un  indicador  adicional,  cv2.THRESH_OTSU.  Para  el  valor  de  umbral,  
simplemente  pase  cero.  Luego,  el  algoritmo  encuentra  el  valor  de  umbral  óptimo  y  lo  devuelve  como  la  segunda  salida,  retVal.  Si  no  se  
usa  el  umbral  de  Otsu,  retVal  es  el  mismo  que  el  valor  de  umbral  que  usó.

1.4.  Procesamiento  de  imágenes  en  OpenCV 55
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Mira  el  siguiente  ejemplo.  La  imagen  de  entrada  es  una  imagen  ruidosa.  En  el  primer  caso,  apliqué  un  umbral  global  para  un  valor  
de  127.  En  el  segundo  caso,  apliqué  el  umbral  de  Otsu  directamente.  En  el  tercer  caso,  filtré  la  imagen  con  un  núcleo  gaussiano  de  
5x5  para  eliminar  el  ruido  y  luego  apliqué  el  umbral  de  Otsu.  Vea  cómo  el  filtrado  de  ruido  mejora  el  resultado.

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('ruidoso2.png',0)

#  umbral  global  ret1,th1  =  
cv2.threshold(img,127,255,cv2.THRESH_BINARY)

#  Umbral  de  Otsu  ret2,th2  =  
cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

#  Umbral  de  Otsu  después  del  desenfoque  de  filtrado  gaussiano  =  
cv2.GaussianBlur(img,(5,5),0)  ret3,th3  =  
cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

#  graficar  todas  las  imágenes  y  sus  histogramas  imágenes  =  [img,  
0,  th1,  img,  0,  th2,  blur,  0,  th3]

titles  =  ['Imagen  ruidosa  original  ','Histograma','  Umbral  global  (v=127)',
'Imagen  ruidosa  original  ',  'Histograma',  "  Umbral  de  Otsu",
'Imagen  filtrada  gaussiana  ',  'Histograma',  "  Umbral  de  Otsu"]

para  i  en  xrange(3):
plt.subplot(3,3,i*3+1),plt.imshow(imágenes[i*3],'gris')  plt.title(títulos[i*3]),  plt.xticks([]),  
plt.yticks([])  plt.subplot(3,3,i*3+2),plt.hist(imágenes[i*3].ravel(),256)  plt.title(títulos[i*3+1 ]),  
plt.xticks([]),  plt.yticks([])  plt.subplot(3,3,i*3+3),plt.imshow(imágenes[i*3+2],'gris')  
plt.title(títulos[i*3+2]),  plt.xticks([]),  plt.yticks([])

plt.mostrar()

Resultado :

56 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

¿Cómo  funciona  la  binarización  de  Otsu?

Esta  sección  demuestra  una  implementación  de  Python  de  la  binarización  de  Otsu  para  mostrar  cómo  funciona  realmente.  Si  no  
estás  interesado,  puedes  saltarte  esto.

Dado  que  estamos  trabajando  con  imágenes  bimodales,  el  algoritmo  de  Otsu  intenta  encontrar  un  valor  de  umbral  (t)  que  minimice  
la  varianza  dentro  de  la  clase  ponderada  dada  por  la  relación:

2 2 2
( )  =  1( ) 1  ( )  +  2  ( )  2  ( )

dónde

1( )  =  ∑   ( )  &  1( )  =  ∑ ( )


=1 =  +1

( )   ( )  
1( )  =  ∑ &  2( )  =  ∑
=1 1( ) =  +1
2( )

2 ( )   2 ( )  
1  ( )  =  ∑   [ −  1( )]2 & 2  ( )  =  ∑ [ −  1( )]2  
=1 1( ) =  +1
2( )

En  realidad,  encuentra  un  valor  de  t  que  se  encuentra  entre  dos  picos,  de  modo  que  las  variaciones  de  ambas  clases  son  mínimas.  Se  puede  
implementar  simplemente  en  Python  de  la  siguiente  manera:

img  =  cv2.imread('ruidoso2.png',0)  desenfoque  =  
cv2.GaussianBlur(img,(5,5),0)

#  encuentra  el  histograma_normalizado  y  su  función  de  distribución  acumulativa

1.4.  Procesamiento  de  imágenes  en  OpenCV 57
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

hist  =  cv2.calcHist([desenfoque],[0],Ninguno,[256],[0,256])  hist_norm  =  hist.ravel()/
hist.max()
Q  =  hist_norm.cumsum()

contenedores  =  np.arange(256)

fn_min  =  np.inf  umbral  =  
­1

para  i  en  xrange(1,256):
p1,p2  =  np.hsplit(hist_norm,[i])  #  probabilidades  q1,q2  =  Q[i],Q[255]­Q[i]  #  suma  
acumulada  de  clases  b1,b2  =  np.hsplit(bins,[ i])  #  pesos

#  encontrar  medias  y  varianzas  m1,m2  =  
np.sum(p1*b1)/q1,  np.sum(p2*b2)/q2  v1,v2  =  np.sum(((b1­m1)**2)*p1 )/
q1,np.suma(((b2­m2)**2)*p2)/q2

#  calcula  la  función  de  minimización
fn  =  v1*q1  +  v2*q2  si  fn  <  
fn_min:  fn_min  =  fn  
umbral  =  i

#  encuentre  el  valor  de  umbral  de  otsu  con  la  función  OpenCV  ret,  otsu  =  
cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)  print  thresh,ret

(Algunas  de  las  funciones  pueden  ser  nuevas  aquí,  pero  las  cubriremos  en  los  próximos  capítulos)

Recursos  adicionales

1.  Procesamiento  Digital  de  Imágenes,  Rafael  C.  González

Ejercicios

1.  Hay  algunas  optimizaciones  disponibles  para  la  binarización  de  Otsu.  Puedes  buscarlo  e  implementarlo.

Transformaciones  Geométricas  de  Imágenes

Objetivos

•  Aprenda  a  aplicar  diferentes  transformaciones  geométricas  a  imágenes  como  traslación,  rotación,  transformación  afín,  etc.

•  Verá  estas  funciones:  cv2.getPerspectiveTransform

Transformaciones

OpenCV  proporciona  dos  funciones  de  transformación,  cv2.warpAffine  y  cv2.warpPerspective,  con  las  que  puedes  tener  todo  tipo  de  
transformaciones.  cv2.warpAffine  toma  una  matriz  de  transformación  de  2x3  mientras  que  cv2.warpPerspective  toma  una  matriz  de  
transformación  de  3x3  como  entrada.

58 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Escalada

Escalar  es  simplemente  cambiar  el  tamaño  de  la  imagen.  OpenCV  viene  con  una  función  cv2.resize()  para  este  propósito.  El  tamaño  de  la  
imagen  se  puede  especificar  manualmente  o  puede  especificar  el  factor  de  escala.  Se  utilizan  diferentes  métodos  de  interpolación.  Los  
métodos  de  interpolación  preferibles  son  cv2.INTER_AREA  para  reducir  y  cv2.INTER_CUBIC  (lento)  y  cv2.INTER_LINEAR  para  hacer  
zoom.  De  forma  predeterminada,  el  método  de  interpolación  utilizado  es  cv2.INTER_LINEAR  para  todos  los  fines  de  cambio  de  tamaño.  
Puede  cambiar  el  tamaño  de  una  imagen  de  entrada  cualquiera  de  los  siguientes  métodos:

importar  cv2  
importar  numpy  como  np

img  =  cv2.imread('messi5.jpg')

res  =  cv2.resize(img,Ninguno,fx=2,  fy=2,  interpolación  =  cv2.INTER_CUBIC)

#O

alto,  ancho  =  img.shape[:2]  res  =  
cv2.resize(img,(2*ancho,  2*alto),  interpolación  =  cv2.INTER_CUBIC)

Traducción

La  traducción  es  el  cambio  de  ubicación  del  objeto.  Si  conoce  el  cambio  en  la  dirección  (x,  y),  sea  ( la  matriz  de   , ),  puede  crear
transformación  M  de  la  siguiente  manera:

=  [ 0  
10 ]
 1  

Puede  convertirlo  en  una  matriz  Numpy  de  tipo  np.float32  y  pasarlo  a  la  función  cv2.warpAffine() .  Vea  el  siguiente  ejemplo  para  un  cambio  
de  (100,50):

importar  cv2  
importar  numpy  como  np

img  =  cv2.imread('messi5.jpg',0)  filas,columnas  =  
img.forma

M  =  np.float32([[1,0,100],[0,1,50]])  dst  =  
cv2.warpAffine(img,M,(columnas,filas))

cv2.imshow('img',dst)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

Advertencia:  el  tercer  argumento  de  la  función  cv2.warpAffine()  es  el  tamaño  de  la  imagen  de  salida,  que  debe  tener  la  forma  de  
(ancho,  alto).  Recuerda  ancho  =  número  de  columnas  y  alto  =  número  de  filas.

Vea  el  resultado  a  continuación:

1.4.  Procesamiento  de  imágenes  en  OpenCV 59
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Rotación

La  rotación  de  una  imagen  para  un  ángulo  se  logra  mediante  la  matriz  de  transformación  de  la  forma

=  [ − ]

Pero  OpenCV  proporciona  una  rotación  escalada  con  un  centro  de  rotación  ajustable  para  que  pueda  rotar  en  cualquier  lugar  que  
prefiera.  La  matriz  de  transformación  modificada  viene  dada  por

(1  ­ )  ∙ .   . −  ∙
.
− ∙ +  (1  − )  ∙ . ]
[
dónde:

=  ∙  porque ,
=  ∙  pecado

Para  encontrar  esta  matriz  de  transformación,  OpenCV  proporciona  una  función,  cv2.getRotationMatrix2D.  Consulte  el  
siguiente  ejemplo  que  gira  la  imagen  90  grados  con  respecto  al  centro  sin  ninguna  escala.

img  =  cv2.imread('messi5.jpg',0)  filas,columnas  =  
img.forma

M  =  cv2.getRotationMatrix2D((cols/2,rows/2),90,1)  dst  =  cv2.warpAffine(img,M,
(cols,rows))

Vea  el  resultado:

60 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Transformacion  afin

En  la  transformación  afín,  todas  las  líneas  paralelas  en  la  imagen  original  seguirán  siendo  paralelas  en  la  imagen  de  salida.  Para  encontrar  la  
matriz  de  transformación,  necesitamos  tres  puntos  de  la  imagen  de  entrada  y  sus  ubicaciones  correspondientes  en  la  imagen  de  salida.  
Luego,  cv2.getAffineTransform  creará  una  matriz  de  2x3  que  se  pasará  a  cv2.warpAffine.

Verifique  el  ejemplo  a  continuación  y  también  mire  los  puntos  que  seleccioné  (que  están  marcados  en  color  verde):

img  =  cv2.imread('dibujo.png')  filas,columnas,ch  
=  img.forma

pts1  =  np.float32([[50.50],[200.50],[50.200]])  pts2  =  np.float32([[10,100],
[200.50],[100,250]])

M  =  cv2.getAffineTransform(pts1,pts2)

dst  =  cv2.warpAffine(img,M,(columnas,filas))

plt.subplot(121),plt.imshow(img),plt.title('Entrada')  plt.subplot  
(122),plt.imshow(dst),plt.title('Salida')  plt.show()

Vea  el  resultado:

Transformación  de  perspectiva

Para  la  transformación  de  perspectiva,  necesita  una  matriz  de  transformación  de  3x3.  Las  líneas  rectas  permanecerán  rectas  incluso  después  
de  la  transformación.  Para  encontrar  esta  matriz  de  transformación,  necesita  4  puntos  en  la  imagen  de  entrada  y  los  puntos  correspondientes  
en  la  imagen  de  salida.  Entre  estos  4  puntos,  3  de  ellos  no  deben  ser  colineales.  Entonces  la  matriz  de  transformación  se  puede  encontrar  
mediante  la  función  cv2.getPerspectiveTransform.  Luego  aplique  cv2.warpPerspective  con  esta  matriz  de  transformación  de  3x3.

Vea  el  código  a  continuación:

1.4.  Procesamiento  de  imágenes  en  OpenCV 61
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

img  =  cv2.imread('sudokusmall.png')  filas,columnas,ch  
=  img.forma

pts1  =  np.float32([[56.65],[368.52],[28.387],[389.390]])  pts2  =  np.float32([[0.0],[300.0],
[0.300] ,[300,300]])

M  =  cv2.getPerspectiveTransform(pts1,pts2)

dst  =  cv2.warpPerspective(img,M,(300,300))

plt.subplot(121),plt.imshow(img),plt.title('Entrada')  plt.subplot  
(122),plt.imshow(dst),plt.title('Salida')  plt.show()

Resultado:

Recursos  adicionales

1.  “Visión  por  Computador:  Algoritmos  y  Aplicaciones”,  Richard  Szeliski

Ejercicios

Suavizado  de  imágenes

Objetivos

Aprender  a:

•  Imágenes  borrosas  con  varios  filtros  de  paso  bajo

•  Aplicar  filtros  personalizados  a  las  imágenes  (convolución  2D)

62 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Convolución  2D  (filtrado  de  imágenes)

En  cuanto  a  las  señales  unidimensionales,  las  imágenes  también  se  pueden  filtrar  con  varios  filtros  de  paso  bajo  (LPF),  filtros  de  paso  
alto  (HPF),  etc.  Un  LPF  ayuda  a  eliminar  el  ruido  o  desenfocar  la  imagen.  Un  filtro  HPF  ayuda  a  encontrar  bordes  en  una  imagen.

OpenCV  proporciona  una  función,  cv2.filter2D(),  para  convolucionar  un  kernel  con  una  imagen.  Como  ejemplo,  probaremos  un  filtro  
promedio  en  una  imagen.  Un  kernel  de  filtro  promedio  de  5x5  se  puede  definir  de  la  siguiente  manera:

1  1  1  1  1
1  1  1  1  1
1
=      1  1  1  1  1     
25
1  1  1  1  1         

1  1  1  1  1

El  filtrado  con  el  kernel  anterior  da  como  resultado  lo  siguiente:  para  cada  píxel,  se  centra  una  ventana  de  5x5  en  este  píxel,  
se  suman  todos  los  píxeles  que  caen  dentro  de  esta  ventana  y  el  resultado  se  divide  por  25.  Esto  equivale  a  calcular  el  
promedio  de  los  valores  de  píxeles  dentro  de  esa  ventana.  Esta  operación  se  realiza  para  todos  los  píxeles  de  la  imagen  
para  producir  la  imagen  filtrada  de  salida.  Prueba  este  código  y  comprueba  el  resultado:

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('opencv_logo.png')

kernel  =  np.ones((5,5),np.float32)/25  dst  =  
cv2.filter2D(img,­1,kernel)

plt.subplot(121),plt.imshow(img),plt.title('Original')  plt.xticks([]),  plt.yticks([])  
plt.subplot(122),plt.imshow(dst) ,plt.title('Promedio')  
plt.xticks([]),  plt.yticks([])  plt.show()

Resultado:

1.4.  Procesamiento  de  imágenes  en  OpenCV 63
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Imagen  borrosa  (suavizado  de  imagen)

El  desenfoque  de  la  imagen  se  logra  convolucionando  la  imagen  con  un  núcleo  de  filtro  de  paso  bajo.  Es  útil  para  eliminar  el  ruido.  En  
realidad,  elimina  el  contenido  de  alta  frecuencia  (p.  ej.,  ruido,  bordes)  de  la  imagen,  lo  que  hace  que  los  bordes  se  vean  borrosos  cuando  
se  aplica  este  filtro.  (Bueno,  existen  técnicas  de  desenfoque  que  no  desdibujan  los  bordes).  OpenCV  proporciona  principalmente  cuatro  
tipos  de  técnicas  de  desenfoque.

1.  Promedio

Esto  se  hace  convolucionando  la  imagen  con  un  filtro  de  caja  normalizado.  Simplemente  toma  el  promedio  de  todos  los  
píxeles  bajo  el  área  del  núcleo  y  reemplaza  el  elemento  central  con  este  promedio.  Esto  lo  hace  la  función  cv2.blur()  o  
cv2.boxFilter().  Consulte  los  documentos  para  obtener  más  detalles  sobre  el  kernel.  Debemos  especificar  el  ancho  y  la  altura  del  núcleo.
Un  filtro  de  caja  normalizado  de  3x3  se  vería  así:

1  1  1
1
= 1  1  1
9
1  
  
1  1   

Nota:  si  no  desea  utilizar  un  filtro  de  cuadro  normalizado,  utilice  cv2.boxFilter()  y  pase  el  argumento  normalize=False  a  la  
función.

Verifique  la  demostración  de  muestra  a  continuación  con  un  kernel  de  tamaño  5x5:

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('opencv_logo.png')

64 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

desenfoque  =  cv2.desenfoque(img,(5,5))

plt.subplot(121),plt.imshow(img),plt.title('Original')  plt.xticks([]),  plt.yticks([])  
plt.subplot(122),plt.imshow(desenfoque) ,plt.title('Blurred')  
plt.xticks([]),  plt.yticks([])  plt.show()

Resultado:

2.  Filtrado  gaussiano

En  este  enfoque,  en  lugar  de  un  filtro  de  caja  que  consta  de  coeficientes  de  filtro  iguales,  se  utiliza  un  núcleo  gaussiano.  Se  hace  con  la  función  
cv2.GaussianBlur().  Deberíamos  especificar  el  ancho  y  la  altura  del  núcleo,  que  debería  ser  positivo  e  impar.  También  debemos  especificar  la  
desviación  estándar  en  las  direcciones  X  e  Y,  sigmaX  y  sigmaY  respectivamente.  Si  solo  se  especifica  sigmaX,  sigmaY  se  considera  igual  a  
sigmaX.  Si  ambos  se  dan  como  ceros,  se  calculan  a  partir  del  tamaño  del  kernel.  El  filtrado  gaussiano  es  muy  eficaz  para  eliminar  el  ruido  
gaussiano  de  la  imagen.

Si  lo  desea,  puede  crear  un  kernel  gaussiano  con  la  función  cv2.getGaussianKernel().

El  código  anterior  se  puede  modificar  para  el  desenfoque  gaussiano:

desenfoque  =  cv2.GaussianBlur(img,(5,5),0)

Resultado:

1.4.  Procesamiento  de  imágenes  en  OpenCV sesenta  y  cinco
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

3.  Filtrado  mediano

Aquí,  la  función  cv2.medianBlur()  calcula  la  mediana  de  todos  los  píxeles  debajo  de  la  ventana  del  kernel  y  el  píxel  central  se  
reemplaza  con  este  valor  de  la  mediana.  Esto  es  muy  eficaz  para  eliminar  el  ruido  de  sal  y  pimienta.  Una  cosa  interesante  a  tener  
en  cuenta  es  que,  en  los  filtros  Gaussiano  y  de  caja,  el  valor  filtrado  para  el  elemento  central  puede  ser  un  valor  que  puede  no  
existir  en  la  imagen  original.  Sin  embargo,  este  no  es  el  caso  en  el  filtrado  de  mediana,  ya  que  el  elemento  central  siempre  se  
reemplaza  por  algún  valor  de  píxel  en  la  imagen.  Esto  reduce  el  ruido  de  manera  efectiva.  El  tamaño  del  núcleo  debe  ser  un  
número  entero  impar  positivo.

En  esta  demostración,  agregamos  un  50%  de  ruido  a  nuestra  imagen  original  y  usamos  un  filtro  mediano.  Compruebe  el  resultado:

mediana  =  cv2.medianBlur(img,5)

Resultado:

66 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

4.  Filtrado  bilateral

Como  notamos,  los  filtros  que  presentamos  anteriormente  tienden  a  desenfocar  los  bordes.  Este  no  es  el  caso  del  filtro  bilateral,  cv2.bilateralFilter(),  
que  se  definió  para  eliminar  el  ruido  y  es  muy  eficaz  al  mismo  tiempo  que  preserva  los  bordes.  Pero  el  funcionamiento  es  más  lento  en  comparación  
con  otros  filtros.  Ya  vimos  que  un  filtro  gaussiano  toma  la  vecindad  alrededor  del  píxel  y  encuentra  su  promedio  ponderado  gaussiano.  Este  filtro  
gaussiano  es  una  función  del  espacio  únicamente,  es  decir,  los  píxeles  cercanos  se  consideran  durante  el  filtrado.  No  considera  si  los  píxeles  tienen  
casi  el  mismo  valor  de  intensidad  y  no  considera  si  el  píxel  se  encuentra  en  un  borde  o  no.  El  efecto  resultante  es  que  los  filtros  gaussianos  tienden  a  
desenfocar  los  bordes,  lo  que  no  es  deseable.

El  filtro  bilateral  también  usa  un  filtro  gaussiano  en  el  dominio  del  espacio,  pero  también  usa  un  componente  de  filtro  gaussiano  más  (multiplicativo)  
que  es  una  función  de  las  diferencias  de  intensidad  de  píxeles.  La  función  gaussiana  del  espacio  asegura  que  solo  los  píxeles  que  son  'vecinos  
espaciales'  se  consideren  para  el  filtrado,  mientras  que  el  componente  gaussiano  aplicado  en  el  dominio  de  intensidad  (una  función  gaussiana  de  
diferencias  de  intensidad)  asegura  que  solo  aquellos  píxeles  con  intensidades  similares  a  la  del  centro.  se  incluyen  píxeles  ("vecinos  de  intensidad")  
para  calcular  el  valor  de  intensidad  borrosa.  Como  resultado,  este  método  conserva  los  bordes,  ya  que  para  los  píxeles  que  se  encuentran  cerca  de  
los  bordes,  los  píxeles  vecinos  ubicados  en  el  otro  lado  del  borde  y,  por  lo  tanto,  presentan  grandes  variaciones  de  intensidad  en  comparación  con  el  
píxel  central,  no  se  incluirán  en  el  desenfoque.

El  siguiente  ejemplo  demuestra  el  uso  de  filtrado  bilateral  (para  obtener  detalles  sobre  los  argumentos,  consulte  los  documentos  de  OpenCV).

desenfoque  =  cv2.bilateralFilter(img,9,75,75)

Resultado:

1.4.  Procesamiento  de  imágenes  en  OpenCV 67
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Tenga  en  cuenta  que  la  textura  de  la  superficie  ha  desaparecido,  pero  los  bordes  aún  se  conservan.

Recursos  adicionales

1.  Los  detalles  sobre  el  filtrado  bilateral  se  pueden  encontrar  en

Ejercicios

Tome  una  imagen,  agregue  ruido  gaussiano  y  ruido  de  sal  y  pimienta,  compare  el  efecto  de  desenfoque  a  través  de  filtros  de  caja,  gaussianos,  
medianos  y  bilaterales  para  ambas  imágenes  ruidosas,  a  medida  que  cambia  el  nivel  de  ruido.

Transformaciones  morfológicas

Meta

En  este  capítulo,

•  Aprenderemos  diferentes  operaciones  morfológicas  como  Erosión,  Dilatación,  Apertura,  Cierre,  etc.

•  Veremos  diferentes  funciones  como:  cv2.erode(),  cv2.dilate(),  cv2.morphologyEx()  etc.

Teoría

Las  transformaciones  morfológicas  son  algunas  operaciones  simples  basadas  en  la  forma  de  la  imagen.  Normalmente  se  realiza  en  
imágenes  binarias.  Necesita  dos  entradas,  una  es  nuestra  imagen  original,  la  segunda  se  llama  elemento  estructurante  o  kernel  que  decide  
la  naturaleza  de  la  operación.  Dos  operadores  morfológicos  básicos  son  la  Erosión  y  la  Dilatación.  Luego,  sus  formas  variantes  como  
Apertura,  Cierre,  Gradiente,  etc.  también  entran  en  juego.  Los  veremos  uno  por  uno  con  la  ayuda  de  la  siguiente  imagen:

68 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

1.  Erosión

La  idea  básica  de  la  erosión  es  como  la  erosión  del  suelo,  erosiona  los  límites  del  objeto  en  primer  plano  (siempre  trate  de  mantener  el  
primer  plano  en  blanco).  Entonces  ¿Qué  es  lo  que  hace?  El  núcleo  se  desliza  a  través  de  la  imagen  (como  en  la  convolución  2D).  Un  
píxel  en  la  imagen  original  (ya  sea  1  o  0)  se  considerará  1  solo  si  todos  los  píxeles  debajo  del  núcleo  son  1;  de  lo  contrario,  se  erosiona  
(se  hace  cero).

Entonces,  lo  que  sucede  es  que  todos  los  píxeles  cercanos  al  límite  se  descartarán  según  el  tamaño  del  kernel.  Entonces,  el  grosor  o  el  
tamaño  del  objeto  en  primer  plano  disminuye  o  simplemente  disminuye  la  región  blanca  en  la  imagen.  Es  útil  para  eliminar  pequeños  
ruidos  blancos  (como  hemos  visto  en  el  capítulo  de  espacio  de  color),  separar  dos  objetos  conectados,  etc.

Aquí,  como  ejemplo,  usaría  un  kernel  5x5  lleno  de  unos.  Veamos  cómo  funciona:

importar  cv2  
importar  numpy  como  np

img  =  cv2.imread('j.png',0)  kernel  =  
np.ones((5,5),np.uint8)  erosión  =  
cv2.erode(img,kernel,iteraciones  =  1)

Resultado:

2.  Dilatación

Es  justo  lo  contrario  de  la  erosión.  Aquí,  un  elemento  de  píxel  es  '1'  si  al  menos  un  píxel  debajo  del  kernel  es  '1'.  Por  lo  tanto,  aumenta  
la  región  blanca  en  la  imagen  o  aumenta  el  tamaño  del  objeto  en  primer  plano.  Normalmente,  en  casos  como  eliminación  de  ruido,  erosión

1.4.  Procesamiento  de  imágenes  en  OpenCV 69
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

le  sigue  la  dilatación.  Porque  la  erosión  elimina  los  ruidos  blancos,  pero  también  encoge  nuestro  objeto.  Entonces  lo  dilatamos.  Dado  que  
el  ruido  se  ha  ido,  no  volverán,  pero  el  área  de  nuestro  objeto  aumenta.  También  es  útil  para  unir  partes  rotas  de  un  objeto.

dilatación  =  cv2.dilate(img,kernel,iteraciones  =  1)

Resultado:

3.  Apertura

La  apertura  es  solo  otro  nombre  de  la  erosión  seguida  de  la  dilatación.  Es  útil  para  eliminar  el  ruido,  como  explicamos  anteriormente.
Aquí  usamos  la  función,  cv2.morphologyEx()

apertura  =  cv2.morphologyEx(img,  cv2.MORPH_OPEN,  kernel)

Resultado:

4.  Cierre

El  cierre  es  el  reverso  de  la  apertura,  la  dilatación  seguida  de  la  erosión.  Es  útil  para  cerrar  pequeños  agujeros  dentro  de  los  objetos  de  
primer  plano  o  pequeños  puntos  negros  en  el  objeto.

cierre  =  cv2.morphologyEx(img,  cv2.MORPH_CLOSE,  kernel)

Resultado:

70 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

5.  Gradiente  morfológico

Es  la  diferencia  entre  dilatación  y  erosión  de  una  imagen.

El  resultado  se  verá  como  el  contorno  del  objeto.

degradado  =  cv2.morphologyEx(img,  cv2.MORPH_GRADIENT,  kernel)

Resultado:

6.  Sombrero  de  copa

Es  la  diferencia  entre  imagen  de  entrada  y  Apertura  de  la  imagen.  El  siguiente  ejemplo  está  hecho  para  un  kernel  9x9.

sombrero  de  copa  =  cv2.morphologyEx(img,  cv2.MORPH_TOPHAT,  kernel)

Resultado:

1.4.  Procesamiento  de  imágenes  en  OpenCV 71
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

7.  Sombrero  negro

Es  la  diferencia  entre  el  cierre  de  la  imagen  de  entrada  y  la  imagen  de  entrada.

blackhat  =  cv2.morphologyEx(img,  cv2.MORPH_BLACKHAT,  kernel)

Resultado:

Elemento  Estructurante

Creamos  manualmente  elementos  de  estructuración  en  los  ejemplos  anteriores  con  la  ayuda  de  Numpy.  Es  de  forma  rectangular.
Pero  en  algunos  casos,  es  posible  que  necesite  granos  de  forma  elíptica  o  circular.  Entonces,  para  este  propósito,  OpenCV  tiene  una  función,  
cv2.getStructuringElement().  Simplemente  pasa  la  forma  y  el  tamaño  del  kernel,  obtiene  el  kernel  deseado.

#  Kernel  rectangular  >>>  
cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))  array([[1,  1,  1,  1,  1],  [1,  1,  1,  
1,  1],

[1,  1,  1,  1,  1],
[1,  1,  1,  1,  1],  [1,  1,  1,  1,  
1]],  dtipo=uint8)

#  Núcleo  elíptico  >>>  
cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))  array([[0,  0,  1,  0,  0],  [1,  1,  1 ,  1 ,  
1],  [1,  1,  1,  1,  1],

72 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

[1,  1,  1,  1,  1],  [0,  0,  1,  0,  
0]],  dtipo=uint8)

#  Kernel  en  forma  de  cruz  >>>  
cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))  array([[0,  0,  1,  0,  0],  [0,  0,  
1,  0,  0],  [ 1,  1,  1,  1,  1],  [0,  0,  1,  0,  0],  
[0,  0,  1,  0,  0]],  
dtype=uint8)

Recursos  adicionales

1.  Operaciones  morfológicas  en  HIPR2

Ejercicios

Gradientes  de  imagen

Meta

En  este  capítulo,  aprenderemos  a:

•  Encuentra  gradientes  de  imagen,  bordes,  etc.

•  Veremos  las  siguientes  funciones:  cv2.Sobel(),  cv2.Scharr(),  cv2.Laplacian()  etc.

Teoría

OpenCV  proporciona  tres  tipos  de  filtros  de  gradiente  o  filtros  de  paso  alto,  Sobel,  Scharr  y  Laplacian.  Veremos  cada  
uno  de  ellos.

1.  Derivados  de  Sobel  y  Scharr

Los  operadores  de  Sobel  son  una  operación  conjunta  de  suavizado  gaussiano  más  diferenciación,  por  lo  que  es  más  resistente  al  ruido.  
Puede  especificar  la  dirección  de  las  derivadas  a  tomar,  vertical  u  horizontal  (mediante  los  argumentos,  yorder  y  xorder  respectivamente).  
También  puede  especificar  el  tamaño  del  núcleo  mediante  el  argumento  ksize.  Si  ksize  =  ­1,  se  utiliza  un  filtro  Scharr  de  3x3  que  da  
mejores  resultados  que  un  filtro  Sobel  de  3x3.  Consulte  los  documentos  para  los  núcleos  utilizados.

2.  Derivados  laplacianos

2 2

Calcula  el  Laplaciano  de  la  imagen  dado  por  la  relación,  ∆  =  usando   ∂  ∂  2 + ∂  ∂  2 donde  se  encuentra  cada  derivada


derivadas  de  Sobel.  Si  ksize  =  1,  se  utiliza  el  siguiente  kernel  para  filtrar:

0  1  0
= 1  −4  1
0  
  
1  0   

1.4.  Procesamiento  de  imágenes  en  OpenCV 73
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Código

El  siguiente  código  muestra  todos  los  operadores  en  un  solo  diagrama.  Todos  los  núcleos  son  de  tamaño  5x5.  Se  pasa  la  profundidad  de  la  imagen  de  salida  ­1  
para  obtener  el  resultado  en  el  tipo  np.uint8.

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('dave.jpg',0)

laplacian  =  cv2.Laplacian(img,cv2.CV_64F)  sobelx  =  
cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)  sobely  =  
cv2.Sobel(img,cv2.CV_64F,0,1,ksize=  5)

plt.subplot(2,2,1),plt.imshow(img,cmap  =  'gris')  plt.title('Original'),  plt.xticks([]),  
plt.yticks([])  plt.subplot  (2,2,2),plt.imshow(laplaciano,cmap  =  'gris')  plt.title('Laplaciano'),  
plt.xticks([]),  plt.yticks([])  plt.subplot(2,  2,3),plt.imshow(sobelx,cmap  =  'gris')  plt.title('Sobel  
X'),  plt.xticks([]),  plt.yticks([])  plt.subplot(2,2,  4),plt.imshow(sobely,cmap  =  'gris')  
plt.title('Sobel  Y'),  plt.xticks([]),  plt.yticks([])

plt.mostrar()

Resultado:

74 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

¡Un  asunto  importante!

En  nuestro  último  ejemplo,  el  tipo  de  datos  de  salida  es  cv2.CV_8U  o  np.uint8.  Pero  hay  un  pequeño  problema  con  eso.  La  transición  de  negro  a  
blanco  se  toma  como  una  pendiente  positiva  (tiene  un  valor  positivo)  mientras  que  la  transición  de  blanco  a  negro  se  toma  como  una  pendiente  
negativa  (tiene  un  valor  negativo).  Entonces,  cuando  convierte  datos  a  np.uint8,  todas  las  pendientes  negativas  se  vuelven  cero.  En  palabras  
simples,  extrañas  esa  ventaja.

Si  desea  detectar  ambos  bordes,  la  mejor  opción  es  mantener  el  tipo  de  datos  de  salida  en  algunas  formas  superiores,  como  cv2.CV_16S,  
cv2.CV_64F,  etc.,  tome  su  valor  absoluto  y  luego  vuelva  a  convertirlo  a  cv2.CV_8U.  El  siguiente  código  demuestra  este  procedimiento  para  un  filtro  
Sobel  horizontal  y  la  diferencia  en  los  resultados.

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

1.4.  Procesamiento  de  imágenes  en  OpenCV 75
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

img  =  cv2.imread('caja.png',0)

#  Tipo  de  salida  =  cv2.CV_8U  sobelx8u  =  
cv2.Sobel(img,cv2.CV_8U,1,0,ksize=5)

#  Tipo  de  salida  =  cv2.CV_64F.  Luego  tome  su  absoluto  y  conviértalo  a  cv2.CV_8U  sobelx64f  =  
cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)  abs_sobel64f  =  np.absolute(sobelx64f)  
sobel_8u  =  np.uint8(abs_sobel64f)

plt.subplot(1,3,1),plt.imshow(img,cmap  =  'gris')  plt.title('Original'),  plt.xticks([]),  
plt.yticks([])  plt.subplot  (1,3,2),plt.imshow(sobelx8u,cmap  =  'gris')  plt.title('Sobel  
CV_8U'),  plt.xticks([]),  plt.yticks([])  plt.subplot(1  ,3,3),plt.imshow(sobel_8u,cmap  =  
'gris')  plt.title('Sobel  abs(CV_64F)'),  plt.xticks([]),  plt.yticks([])

plt.mostrar()

Compruebe  el  resultado  a  continuación:

Recursos  adicionales

Ejercicios

Detección  de  borde  astuto

Meta

En  este  capítulo  aprenderemos  sobre

•  Concepto  de  detección  de  bordes  Canny

•  Funciones  OpenCV  para  eso:  cv2.Canny()

Teoría

Canny  Edge  Detection  es  un  popular  algoritmo  de  detección  de  bordes.  Fue  desarrollado  por  John  F.  Canny  en  1986.  Es  un  algoritmo  de  
varias  etapas  y  pasaremos  por  cada  etapa.

1.  Reducción  de  ruido

76 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Dado  que  la  detección  de  bordes  es  susceptible  al  ruido  en  la  imagen,  el  primer  paso  es  eliminar  el  ruido  en  la  imagen  con  un  filtro  
gaussiano  de  5x5.  Ya  lo  hemos  visto  en  capítulos  anteriores.

2.  Encontrar  el  gradiente  de  intensidad  de  la  imagen

Luego,  la  imagen  suavizada  se  filtra  con  un  núcleo  Sobel  en  dirección  horizontal  y  vertical  para  obtener  la  primera  derivada  en  dirección  
horizontal  ( )  y  dirección  vertical  ( ).  A  partir  de  estas  dos  imágenes,  podemos  encontrar  el  degradado  del  borde  y  la  dirección  de  cada  píxel  
de  la  siguiente  manera:

_ + 2
( )  =  √   2  ( )  

=  tan−1  ( )

La  dirección  del  degradado  siempre  es  perpendicular  a  los  bordes.  Se  redondea  a  uno  de  los  cuatro  ángulos  que  representan  las  direcciones  
vertical,  horizontal  y  dos  diagonales.

3.  Supresión  no  máxima

Después  de  obtener  la  magnitud  y  la  dirección  del  gradiente,  se  realiza  un  escaneo  completo  de  la  imagen  para  eliminar  los  píxeles  no  
deseados  que  pueden  no  constituir  el  borde.  Para  esto,  en  cada  píxel,  se  verifica  si  el  píxel  es  un  máximo  local  en  su  vecindad  en  la  
dirección  del  gradiente.  Revisa  la  imagen  a  continuación:

El  punto  A  está  en  el  borde  (en  dirección  vertical).  La  dirección  del  degradado  es  normal  al  borde.  Los  puntos  B  y  C  están  en  direcciones  
de  gradiente.  Entonces,  el  punto  A  se  verifica  con  el  punto  B  y  C  para  ver  si  forma  un  máximo  local.  Si  es  así,  se  considera  para  la  
siguiente  etapa,  de  lo  contrario,  se  suprime  (se  pone  a  cero).

En  resumen,  el  resultado  que  obtiene  es  una  imagen  binaria  con  "bordes  delgados".

4.  Umbral  de  histéresis

Esta  etapa  decide  cuáles  son  todos  los  bordes  que  son  realmente  bordes  y  cuáles  no.  Para  esto,  necesitamos  dos  valores  de  umbral,  
minVal  y  maxVal.  Cualquier  borde  con  un  gradiente  de  intensidad  superior  a  maxVal  seguramente  será  borde  y  aquellos  por  debajo  de  
minVal  seguramente  no  serán  bordes,  por  lo  tanto,  deséchelos.  Aquellos  que  se  encuentran  entre  estos  dos  umbrales  se  clasifican  como  
bordes  o  no  bordes  en  función  de  su  conectividad.  Si  están  conectados  a  píxeles  de  "borde  seguro",  se  consideran  parte  de  los  bordes.
De  lo  contrario,  también  se  desechan.  Vea  la  imagen  a  continuación:

1.4.  Procesamiento  de  imágenes  en  OpenCV 77
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

El  borde  A  está  por  encima  de  maxVal,  por  lo  que  se  considera  "borde  seguro".  Aunque  el  borde  C  está  por  debajo  de  maxVal,  está  conectado  
al  borde  A,  por  lo  que  también  se  considera  un  borde  válido  y  obtenemos  esa  curva  completa.  Pero  el  borde  B,  aunque  está  por  encima  de  
minVal  y  está  en  la  misma  región  que  el  borde  C,  no  está  conectado  a  ningún  "borde  seguro",  por  lo  que  se  descarta.  Por  lo  tanto,  es  muy  
importante  que  seleccionemos  minVal  y  maxVal  en  consecuencia  para  obtener  el  resultado  correcto.

Esta  etapa  también  elimina  los  ruidos  de  los  píxeles  pequeños  asumiendo  que  los  bordes  son  líneas  largas.

Entonces,  lo  que  finalmente  obtenemos  son  bordes  fuertes  en  la  imagen.

Detección  de  Canny  Edge  en  OpenCV

OpenCV  pone  todo  lo  anterior  en  una  sola  función,  cv2.Canny().  Veremos  cómo  usarlo.  El  primer  argumento  es  nuestra  imagen  de  entrada.  El  
segundo  y  tercer  argumento  son  nuestro  minVal  y  maxVal  respectivamente.  El  tercer  argumento  es  tamaño_apertura.  Es  el  tamaño  del  núcleo  
Sobel  utilizado  para  encontrar  gradientes  de  imagen.  Por  defecto  es  3.  El  último  argumento  es  L2gradient  que  especifica  la  ecuación  para  
encontrar  la  magnitud  del  gradiente.  Si  es  True,  utiliza  la  ecuación  mencionada  anteriormente,  que  es  más  precisa,  |.  Por  defecto,  es  Falso.  de  
_ ( )  =  | |  +  | lo  contrario,  utiliza  esta  función:

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('messi5.jpg',0)  bordes  =  
cv2.Canny(img,100,200)

plt.subplot(121),plt.imshow(img,cmap  =  'gray')  plt.title('  Imagen  original'),  
plt.xticks([]),  plt.yticks([])  plt.subplot(122) ,plt.imshow(bordes,cmap  =  'gris')  plt.title('  Imagen  de  
borde'),  plt.xticks([]),  plt.yticks([])

plt.mostrar()

Vea  el  resultado  a  continuación:

78 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

1.  Canny  detector  de  bordes  en  Wikipedia

2.  Tutorial  de  detección  de  Canny  Edge  por  Bill  Green,  2002.

Ejercicios

1.  Escriba  una  pequeña  aplicación  para  encontrar  la  detección  de  bordes  Canny  cuyos  valores  de  umbral  se  pueden  variar  usando  dos
barras  de  seguimiento  De  esta  manera,  puede  comprender  el  efecto  de  los  valores  de  umbral.

Pirámides  de  imágenes

Meta

En  este  capítulo,

•  Aprenderemos  sobre  Pirámides  de  Imágenes

•  Usaremos  pirámides  de  imágenes  para  crear  una  nueva  fruta,  “Oapple”

•  Veremos  estas  funciones:  cv2.pyrUp(),  cv2.pyrDown()

Teoría

Normalmente,  solíamos  trabajar  con  una  imagen  de  tamaño  constante.  Pero  en  algunas  ocasiones,  necesitamos  trabajar  con  imágenes  de  
diferente  resolución  de  una  misma  imagen.  Por  ejemplo,  al  buscar  algo  en  una  imagen,  como  una  cara,  no  estamos  seguros  de  qué  tamaño  
tendrá  el  objeto  en  la  imagen.  En  ese  caso,  necesitaremos  crear  un  conjunto  de  imágenes  con  diferente  resolución  y  buscar  objetos  en  todas  
las  imágenes.  Este  conjunto  de  imágenes  con  diferente  resolución  se  denomina  Pirámides  de  imágenes  (porque  cuando  se  mantienen  en  una  
pila  con  la  imagen  más  grande  en  la  parte  inferior  y  la  imagen  más  pequeña  en  la  parte  superior,  se  ven  como  una  pirámide).

Hay  dos  tipos  de  pirámides  de  imágenes.  1)  Pirámide  Gaussiana  y  2)  Pirámides  Laplacianas

El  nivel  superior  (baja  resolución)  en  una  pirámide  gaussiana  se  forma  eliminando  filas  y  columnas  consecutivas  en  la  imagen  de  nivel  inferior  
(resolución  superior).  Luego,  cada  píxel  en  el  nivel  superior  está  formado  por  la  contribución  de  5  píxeles  en  el  nivel  subyacente  con  pesos  
gaussianos.  Al  hacerlo,  una  imagen  ×  se  convierte  en  una  imagen /2  × /2.  Entonces  el  área  se  reduce  a  un  cuarto  del  área  original.  Se  llama  
Octava.  El  mismo  patrón  continúa  a  medida  que  ascendemos  en  la  pirámide  (es  decir,  la  resolución  disminuye).  De  manera  similar,  mientras  
se  expande,  el  área  se  vuelve  4  veces  en  cada  nivel.  Podemos  encontrar  pirámides  de  Gauss  usando  las  funciones  cv2.pyrDown()  y  
cv2.pyrUp() .

1.4.  Procesamiento  de  imágenes  en  OpenCV 79
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

img  =  cv2.imread('messi5.jpg')  menor_reso  =  
cv2.pyrDown(mayor_reso)

A  continuación  se  muestran  los  4  niveles  en  una  pirámide  de  imágenes.

Ahora  puedes  bajar  por  la  pirámide  de  imágenes  con  la  función  cv2.pyrUp() .

mayor_reso2  =  cv2.pyrUp(menor_reso)

Recuerda,  high_reso2  no  es  igual  a  high_reso,  porque  una  vez  que  disminuyes  la  resolución,  pierdes  la  información.  Debajo  de  
la  imagen  hay  3  niveles  por  debajo  de  la  pirámide  creada  a  partir  de  la  imagen  más  pequeña  en  el  caso  anterior.  Compáralo  con  
la  imagen  original:

80 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Las  pirámides  laplacianas  se  forman  a  partir  de  las  pirámides  gaussianas.  No  hay  una  función  exclusiva  para  eso.  Las  imágenes  de  
la  pirámide  laplaciana  son  solo  imágenes  de  borde.  La  mayoría  de  sus  elementos  son  ceros.  Se  utilizan  en  la  compresión  de  
imágenes.  Un  nivel  en  la  Pirámide  Laplaciana  está  formado  por  la  diferencia  entre  ese  nivel  en  la  Pirámide  Gaussiana  y  la  versión  
expandida  de  su  nivel  superior  en  la  Pirámide  Gaussiana.  Los  tres  niveles  de  un  nivel  laplaciano  se  verán  a  continuación  (el  contraste  
se  ajusta  para  mejorar  los  contenidos):

1.4.  Procesamiento  de  imágenes  en  OpenCV 81
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

82 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Fusión  de  imágenes  usando  pirámides

Una  aplicación  de  Pyramids  es  Image  Blending.  Por  ejemplo,  en  la  unión  de  imágenes,  deberá  apilar  dos  imágenes  juntas,  pero  es  posible  que  no  se  vea  bien  
debido  a  las  discontinuidades  entre  las  imágenes.  En  ese  caso,  la  combinación  de  imágenes  con  Pyramids  le  brinda  una  combinación  perfecta  sin  dejar  muchos  
datos  en  las  imágenes.  Un  ejemplo  clásico  de  esto  es  la  mezcla  de  dos  frutas,  Naranja  y  Manzana.  Vea  el  resultado  ahora  mismo  para  entender  lo  que  estoy  
diciendo:

Consulte  la  primera  referencia  en  recursos  adicionales,  tiene  detalles  esquemáticos  completos  sobre  la  combinación  de  imágenes,  los  medios  de  Laplacian  
Pyra,  etc.  Simplemente  se  hace  de  la  siguiente  manera:

1.  Cargue  las  dos  imágenes  de  manzana  y  naranja.

2.  Encuentre  las  pirámides  de  Gauss  para  manzana  y  naranja  (en  este  ejemplo  en  particular,  el  número  de  niveles  es  6)

3.  A  partir  de  las  pirámides  gaussianas,  encuentra  sus  pirámides  laplacianas

4.  Ahora  une  la  mitad  izquierda  de  la  manzana  y  la  mitad  derecha  de  la  naranja  en  cada  nivel  de  las  Pirámides  Laplacianas.

5.  Finalmente  a  partir  de  esta  imagen  conjunta  de  las  pirámides,  reconstruiremos  la  imagen  original.

1.4.  Procesamiento  de  imágenes  en  OpenCV 83
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

A  continuación  se  muestra  el  código  completo.  (En  aras  de  la  simplicidad,  cada  paso  se  realiza  por  separado,  lo  que  puede  requerir  más  
memoria.  Puede  optimizarlo  si  lo  desea).

importar  cv2  
importar  numpy  como  np,  sys

A  =  cv2.imread('manzana.jpg')
B  =  cv2.imread('naranja.jpg')

#  generar  pirámide  gaussiana  para  A  G  =  A.copy()  
gpA  =  [G]  para  i  
en  xrange(6):  
G  =  cv2.pyrDown(G)  
gpA.append(G)

#  generar  pirámide  gaussiana  para  B  G  =  B.copy()  
gpB  =  [G]  para  i  
en  xrange(6):  
G  =  cv2.pyrDown(G)  
gpB.append(G)

#  generar  la  Pirámide  Laplaciana  para  A  lpA  =  [gpA[5]]  
para  i  en  xrange(5,0,­1):

GE  =  cv2.pyrUp(gpA[i])
L  =  cv2.restar(gpA[i­1],GE)  lpA.agregar(L)

#  generar  la  Pirámide  Laplaciana  para  B  lpB  =  [gpB[5]]  
para  i  en  xrange(5,0,­1):

GE  =  cv2.pyrUp(gpB[i])
L  =  cv2.restar(gpB[i­1],GE)  lpB.agregar(L)

#  Ahora  agregue  las  mitades  izquierda  y  derecha  de  las  imágenes  en  cada  nivel
LS  =  []  
para  la,lb  en  zip(lpA,lpB):
filas,columnas,dpt  =  la.forma  ls  =  
np.hstack((la[:,0:columnas/2],  lb[:,columnas/2:]))
LS.append(ls)

#  ahora  reconstruir
ls_  =  LS[0]  para  
i  en  xrange(1,6):
ls_  =  cv2.pyrUp(ls_)  ls_  =  
cv2.add(ls_,  LS[i])

#  imagen  con  conexión  directa  cada  medio  real  =  
np.hstack((A[:,:cols/2],B[:,cols/2:]))

cv2.imwrite('Pyramid_blending2.jpg',ls_)  
cv2.imwrite('Direct_blending.jpg',real)

84 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

1.  Fusión  de  imágenes

Ejercicios

Contornos  en  OpenCV

•  Contornos:  Primeros  pasos

Aprende  a  encontrar  y  dibujar  contornos

•  Funciones  de  contorno

Aprenda  a  encontrar  diferentes  características  de  contornos  como  área,  perímetro,  rectángulo  
delimitador,  etc.

•  Propiedades  de  contorno

Aprenda  a  encontrar  diferentes  propiedades  de  contornos  como  Solidez,  Intensidad  media
etc.

•  Contornos:  más  funciones

Aprenda  a  encontrar  defectos  de  convexidad,  pointPolygonTest,  haga  coincidir  diferentes  formas,  
etc.

•  Jerarquía  de  contornos

1.4.  Procesamiento  de  imágenes  en  OpenCV 85
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Más  información  sobre  la  jerarquía  de  contornos

86 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Contornos:  Primeros  pasos

Meta

•  Comprender  qué  son  los  contornos.

•  Aprenda  a  encontrar  contornos,  dibujar  contornos,  etc.

•  Verá  estas  funciones:  cv2.findContours(),  cv2.drawContours()

¿Qué  son  los  contornos?

Los  contornos  se  pueden  explicar  simplemente  como  una  curva  que  une  todos  los  puntos  continuos  (a  lo  largo  del  límite),  que  tienen  el  mismo  color  o  
intensidad.  Los  contornos  son  una  herramienta  útil  para  el  análisis  de  formas  y  la  detección  y  reconocimiento  de  objetos.

•  Para  mayor  precisión,  utilice  imágenes  binarias.  Entonces,  antes  de  encontrar  contornos,  aplique  umbral  o  detección  de  bordes  astutos.

•  La  función  findContours  modifica  la  imagen  de  origen.  Entonces,  si  desea  una  imagen  de  origen  incluso  después  de  encontrar  contornos,
ya  almacenarlo  en  algunas  otras  variables.

•  En  OpenCV,  encontrar  contornos  es  como  encontrar  un  objeto  blanco  en  un  fondo  negro.  Así  que  recuerda,  el  objeto  a  encontrar  debe  ser  blanco  
y  el  fondo  debe  ser  negro.

Veamos  cómo  encontrar  los  contornos  de  una  imagen  binaria:

importar  numpy  como  np  
importar  cv2

im  =  cv2.imread('test.jpg')  imgray  =  
cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)  ret,thresh  =  
cv2.threshold(imgray,127,255,0)  imagen,  contornos,  jerarquía  =  
cv2.findContours(thresh,  cv2.RETR_TREE,cv2.CHAIN_APPROX_   →SIMPLE)

Mira,  hay  tres  argumentos  en  la  función  cv2.findContours() ,  el  primero  es  la  imagen  de  origen,  el  segundo  es  el  modo  de  recuperación  de  contorno,  el  
tercero  es  el  método  de  aproximación  de  contorno.  Y  genera  la  imagen,  los  contornos  y  la  jerarquía.  contornos  es  una  lista  de  Python  de  todos  los  
contornos  de  la  imagen.  Cada  contorno  individual  es  una  matriz  Numpy  de  coordenadas  (x,  y)  de  puntos  límite  del  objeto.

Nota:  Discutiremos  los  argumentos  segundo  y  tercero  y  sobre  la  jerarquía  en  detalles  más  adelante.  Hasta  entonces,  los  valores  que  se  les  dieron  en  el  
ejemplo  de  código  funcionarán  bien  para  todas  las  imágenes.

¿Cómo  dibujar  los  contornos?

Para  dibujar  los  contornos,  se  utiliza  la  función  cv2.drawContours.  También  se  puede  utilizar  para  dibujar  cualquier  forma  siempre  que  tenga  sus  puntos  
de  contorno.  Su  primer  argumento  es  la  imagen  de  origen,  el  segundo  argumento  son  los  contornos  que  deben  pasarse  como  una  lista  de  Python,  el  
tercer  argumento  es  el  índice  de  contornos  (útil  al  dibujar  contornos  individuales.  Para  dibujar  todos  los  contornos,  pase  ­1)  y  los  argumentos  restantes  
son  color,  grosor  etc.

Para  dibujar  todos  los  contornos  de  una  imagen:

img  =  cv2.drawContours(img,  contornos,  ­1,  (0,255,0),  3)

Para  dibujar  un  contorno  individual,  diga  el  cuarto  contorno:

1.4.  Procesamiento  de  imágenes  en  OpenCV 87
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

img  =  cv2.drawContours(img,  contornos,  3,  (0,255,0),  3)

Pero  la  mayoría  de  las  veces,  el  siguiente  método  será  útil:

cnt  =  contornos[4]  img  =  
cv2.drawContours(img,  [cnt],  0,  (0,255,0),  3)

Nota:  Los  últimos  dos  métodos  son  iguales,  pero  cuando  avance,  verá  que  el  último  es  más  útil.

Método  de  aproximación  de  contorno

Este  es  el  tercer  argumento  en  la  función  cv2.findContours.  ¿Qué  denota  en  realidad?

Arriba,  dijimos  que  los  contornos  son  los  límites  de  una  forma  con  la  misma  intensidad.  Almacena  las  coordenadas  (x,y)  del  límite  de  una  
forma.  Pero,  ¿almacena  todas  las  coordenadas?  Eso  se  especifica  mediante  este  método  de  aproximación  de  contorno.

Si  pasa  cv2.CHAIN_APPROX_NONE,  se  almacenan  todos  los  puntos  límite.  Pero,  ¿realmente  necesitamos  todos  los  puntos?
Por  ejemplo,  encontraste  el  contorno  de  una  línea  recta.  ¿Necesitas  todos  los  puntos  en  la  línea  para  representar  esa  línea?  No,  solo  
necesitamos  dos  puntos  finales  de  esa  línea.  Esto  es  lo  que  hace  cv2.CHAIN_APPROX_SIMPLE.  Elimina  todos  los  puntos  redundantes  
y  comprime  el  contorno,  ahorrando  así  memoria.

La  imagen  de  abajo  de  un  rectángulo  demuestra  esta  técnica.  Simplemente  dibuje  un  círculo  en  todas  las  coordenadas  en  la  matriz  de  
contorno  (dibujado  en  color  azul).  La  primera  imagen  muestra  los  puntos  que  obtuve  con  cv2.CHAIN_APPROX_NONE  (734  puntos)  y  la  
segunda  imagen  muestra  el  que  tiene  cv2.CHAIN_APPROX_SIMPLE  (solo  4  puntos).  ¡Mira,  cuánta  memoria  ahorra!

Recursos  adicionales

Ejercicios

Características  de  contorno

Meta

En  este  artículo  aprenderemos

•  Para  encontrar  las  diferentes  características  de  los  contornos,  como  el  área,  el  perímetro,  el  centroide,  el  cuadro  delimitador,  etc.

•  Verá  un  montón  de  funciones  relacionadas  con  los  contornos.

88 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

1.  Momentos

Los  momentos  de  imagen  lo  ayudan  a  calcular  algunas  características  como  el  centro  de  masa  del  objeto,  el  área  del  objeto,  etc.  Consulte  
la  página  de  wikipedia  en  Momentos  de  imagen

La  función  cv2.moments()  proporciona  un  diccionario  de  todos  los  valores  de  momento  calculados.  Vea  abajo:

importar  cv2  
importar  numpy  como  np

img  =  cv2.imread('star.jpg',0)  ret,umbral  =  
cv2.umbral(img,127,255,0)  contornos,jerarquía  =  
cv2.findContours(umbral,  1,  2)

cnt  =  contornos[0]
M  =  cv2.momentos(cnt)
imprimir  M

10
A  partir  de  este  momento,  puede  extraer  datos  útiles  como  área,  centroide,  etc.  El  centroide  está  dado  por  las  relaciones,  =  y  =
00
01
00
. Esto  puede  hacerse  de  la  siguiente  manera:
cx  =  int(M['m10']/M['m00'])  cy  =  int(M['m01']/
M['m00'])

2.  Área  de  contorno

El  área  de  contorno  viene  dada  por  la  función  cv2.contourArea()  oa  partir  de  momentos,  M['m00'].

area  =  cv2.contourArea(cnt)

3.  Perímetro  de  contorno

También  se  le  llama  longitud  de  arco.  Se  puede  averiguar  usando  la  función  cv2.arcLength() .  El  segundo  argumento  especifica  si  la  forma  
es  un  contorno  cerrado  (si  se  pasa  True),  o  simplemente  una  curva.

perímetro  =  cv2.arcLength(cnt,True)

4.  Aproximación  al  contorno

Aproxima  una  forma  de  contorno  a  otra  forma  con  menos  número  de  vértices  dependiendo  de  la  precisión  que  especifiquemos.
Es  una  implementación  del  algoritmo  de  Douglas­Peucker.  Consulte  la  página  de  wikipedia  para  ver  el  algoritmo  y  la  demostración.

Para  entender  esto,  suponga  que  está  tratando  de  encontrar  un  cuadrado  en  una  imagen,  pero  debido  a  algunos  problemas  en  la  imagen,  
no  obtuvo  un  cuadrado  perfecto,  sino  una  "forma  incorrecta" (como  se  muestra  en  la  primera  imagen  a  continuación).  Ahora  puede  usar  esta  
función  para  aproximar  la  forma.  En  esto,  el  segundo  argumento  se  llama  épsilon,  que  es  la  distancia  máxima  del  contorno  al  contorno  
aproximado.  Es  un  parámetro  de  precisión.  Se  necesita  una  sabia  selección  de  épsilon  para  obtener  la  salida  correcta.

épsilon  =  0.1*cv2.arcLength(cnt,True)  aprox.  =  
cv2.approxPolyDP(cnt,epsilon,True)

A  continuación,  en  la  segunda  imagen,  la  línea  verde  muestra  la  curva  aproximada  para  épsilon  =  10  %  de  la  longitud  del  arco.  La  tercera  
imagen  muestra  lo  mismo  para  epsilon  =  1%  de  la  longitud  del  arco.  El  tercer  argumento  especifica  si  la  curva  está  cerrada  o  no.

1.4.  Procesamiento  de  imágenes  en  OpenCV 89
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

5.  Casco  convexo

Casco  convexo  se  verá  similar  a  la  aproximación  de  contorno,  pero  no  lo  es  (Ambos  pueden  proporcionar  los  mismos  resultados  en  algunos  casos).
Aquí,  la  función  cv2.convexHull()  verifica  una  curva  en  busca  de  defectos  de  convexidad  y  la  corrige.  En  términos  generales,  las  curvas  convexas  son  las  
curvas  que  siempre  están  abultadas,  o  al  menos  planas.  Y  si  está  abombado  por  dentro,  se  llama  defectos  de  convexidad.  Por  ejemplo,  compruebe  la  
siguiente  imagen  de  la  mano.  La  línea  roja  muestra  el  casco  convexo  de  la  mano.  Las  marcas  de  flechas  de  dos  lados  muestran  los  defectos  de  convexidad,  
que  son  las  desviaciones  máximas  locales  del  casco  con  respecto  a  los  contornos.

Hay  algunas  cosas  que  discutir  sobre  su  sintaxis:

casco  =  cv2.convexHull(puntos[,  casco[,  en  el  sentido  de  las  agujas  del  reloj[,  returnPoints]]

Detalles  de  los  argumentos:

•  los  puntos  son  los  contornos  por  los  que  pasamos.

•  casco  es  la  salida,  normalmente  la  evitamos.

90 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

•  en  el  sentido  de  las  agujas  del  reloj :  bandera  de  orientación.  Si  es  True,  el  casco  convexo  de  salida  está  orientado  en  el  sentido  de  las  agujas  del  reloj.  De  lo  contrario,  está  orientado
en  sentido  anti­horario.

•  puntos  de  retorno :  por  defecto,  verdadero.  Luego  devuelve  las  coordenadas  de  los  puntos  del  casco.  Si  es  False,  devuelve  el
índices  de  puntos  de  contorno  correspondientes  a  los  puntos  del  casco.

Entonces,  para  obtener  un  casco  convexo  como  en  la  imagen  de  arriba,  lo  siguiente  es  suficiente:

casco  =  cv2.convexHull(cnt)

Pero  si  desea  encontrar  defectos  de  convexidad,  debe  pasar  returnPoints  =  False.  Para  entenderlo,  tomaremos  la  imagen  del  rectángulo  de  arriba.  Primero  
encontré  su  contorno  como  cnt.  Ahora  encontré  su  casco  convexo  con  returnPoints  =  True,  obtuve  los  siguientes  valores:  [[[234  202]],  [[ 51  202]],  [[ 51  79]],  
[[234  79]]]  que  son  las  cuatro  esquinas  puntos  del  rectángulo.  Ahora,  si  hago  lo  mismo  con  returnPoints  =  False,  obtengo  el  siguiente  resultado:  [[129],[67],[0],
[142]].  Estos  son  los  índices  de  los  puntos  correspondientes  en  los  contornos.  Por  ejemplo,  compruebe  el  primer  valor:  cnt[129]  =  [[234,  202]]  que  es  el  mismo  
que  el  primer  resultado  (y  así  sucesivamente  para  los  demás).

Lo  verá  nuevamente  cuando  hablemos  sobre  los  defectos  de  convexidad.

6.  Comprobación  de  la  convexidad

Hay  una  función  para  comprobar  si  una  curva  es  convexa  o  no,  cv2.isContourConvex().  Simplemente  devuelve  si  es  Verdadero  o  Falso.
No  es  un  gran  trato.

k  =  cv2.isContourConvex(cnt)

7.  Rectángulo  delimitador

Hay  dos  tipos  de  rectángulos  delimitadores.

7.a.  Rectángulo  delimitador  recto

Es  un  rectángulo  recto,  no  considera  la  rotación  del  objeto.  Entonces,  el  área  del  rectángulo  delimitador  no  será  mínima.  Se  encuentra  mediante  la  función  
cv2.boundingRect().

Sea  (x,y)  la  coordenada  superior  izquierda  del  rectángulo  y  (w,h)  su  ancho  y  alto.

x,y,w,h  =  cv2.boundingRect(cnt)  img  =  
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

7.b.  Rectángulo  girado

Aquí,  el  rectángulo  delimitador  se  dibuja  con  un  área  mínima,  por  lo  que  también  considera  la  rotación.  La  función  utilizada  es  cv2.minAreaRect().  Devuelve  
una  estructura  Box2D  que  contiene  los  siguientes  detalles:  (esquina  superior  izquierda  (x,  y),  (ancho,  alto),  ángulo  de  rotación).  Pero  para  dibujar  este  
rectángulo,  necesitamos  4  esquinas  del  rectángulo.  Se  obtiene  mediante  la  función  cv2.boxPoints()

rect  =  cv2.minAreaRect(cnt)  cuadro  =  
cv2.boxPoints(rect)  cuadro  =  np.int0(cuadro)  
im  =  cv2.drawContours(im,
[box],0,(0,0,255),2)

1.4.  Procesamiento  de  imágenes  en  OpenCV 91
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Ambos  rectángulos  se  muestran  en  una  sola  imagen.  El  rectángulo  verde  muestra  el  rectángulo  delimitador  normal.  El  rectángulo  rojo  
es  el  recto  rotado.

8.  Círculo  envolvente  mínimo

A  continuación,  encontramos  el  círculo  circunscrito  de  un  objeto  mediante  la  función  cv2.minEnclosingCircle().  Es  un  círculo  que  
cubre  completamente  el  objeto  con  un  área  mínima.

(x,y),radio  =  cv2.minEnclosingCircle(cnt)  centro  =  (int(x),int(y))  
radio  =  int(radio)

img  =  cv2.circle(img,centro,radio,(0,255,0),2)

92 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

9.  Ajuste  de  una  elipse

El  siguiente  es  ajustar  una  elipse  a  un  objeto.  Devuelve  el  rectángulo  rotado  en  el  que  se  inscribe  la  elipse.

elipse  =  cv2.fitEllipse(cnt)  im  =  
cv2.ellipse(im,elipse,(0,255,0),2)

1.4.  Procesamiento  de  imágenes  en  OpenCV 93
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

10.  Ajuste  de  una  línea

De  manera  similar,  podemos  ajustar  una  línea  a  un  conjunto  de  puntos.  La  imagen  de  abajo  contiene  un  conjunto  de  puntos  blancos.  Podemos  aproximarnos  a  
una  línea  recta.

filas,columnas  =  img.forma[:2]  
[vx,vy,x,y]  =  cv2.fitLine(cnt,  cv2.DIST_L2,0,0.01,0.01)  zurdo  =  int((­x*vy/vx)  +  y)  
derecha  =  int(((columnas­x)*vy/vx)+y)  
img  =  cv2.line(img,(columnas­1,derecha),
(0,izquierda),(0,255,0),2)

94 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

Ejercicios

Propiedades  de  contorno

Aquí  aprenderemos  a  extraer  algunas  propiedades  de  objetos  que  se  usan  con  frecuencia,  como  Solidez,  Diámetro  equivalente,  Imagen  de  
máscara,  Intensidad  media,  etc.  Se  pueden  encontrar  más  funciones  en  la  documentación  de  Matlab  regionprops.

(NB:  centroide,  área,  perímetro,  etc.  también  pertenecen  a  esta  categoría,  pero  lo  hemos  visto  en  el  último  capítulo)

1.  Relación  de  aspecto

Es  la  relación  entre  el  ancho  y  la  altura  del  rectángulo  delimitador  del  objeto.

x,y,w,h  =  cv2.boundingRect(cnt)  relación_aspecto  
=  float(w)/h

2.  Extensión

La  extensión  es  la  relación  entre  el  área  del  contorno  y  el  área  del  rectángulo  delimitador.

area  =  cv2.contourArea(cnt)  x,y,w,h  =  
cv2.boundingRect(cnt)  rect_area  =  w*h  extension  
=  float(area)/rect_area

1.4.  Procesamiento  de  imágenes  en  OpenCV 95
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

3.  Solidez

La  solidez  es  la  relación  entre  el  área  del  contorno  y  el  área  convexa  del  casco.

area  =  cv2.contourArea(cnt)  casco  =  
cv2.convexHull(cnt)  casco_area  =  
cv2.contourArea(casco)  solidez  =  float(area)/
hull_area

4.  Diámetro  equivalente

El  diámetro  equivalente  es  el  diámetro  del  círculo  cuya  área  es  igual  al  área  del  contorno.

=  √   4  ×

área  =  cv2.contourArea(cnt)  equi_diameter  
=  np.sqrt(4*area/np.pi)

5.  Orientación

La  orientación  es  el  ángulo  al  que  se  dirige  el  objeto.  El  siguiente  método  también  proporciona  las  longitudes  del  eje  mayor  y  del  eje  
menor.

(x,y),(MA,ma),ángulo  =  cv2.fitEllipse(cnt)

6.  Puntos  de  máscara  y  píxel

En  algunos  casos,  podemos  necesitar  todos  los  puntos  que  componen  ese  objeto.  Se  puede  hacer  de  la  siguiente  manera:

máscara  =  np.zeros(imgray.shape,np.uint8)  
cv2.drawContours(máscara,[cnt],0,255,­1)  puntos  de  
píxeles  =  np.transpose(np.nonzero(máscara))  #pixelpoints  =  
cv2.findNonZero(máscara )

Aquí,  se  dan  dos  métodos,  uno  que  usa  funciones  Numpy,  el  siguiente  que  usa  la  función  OpenCV  (última  línea  comentada)  para  hacer  
lo  mismo.  Los  resultados  también  son  los  mismos,  pero  con  una  ligera  diferencia.  Numpy  da  coordenadas  en  formato  (fila,  columna) ,  
mientras  que  OpenCV  da  coordenadas  en  formato  (x,  y) .  Entonces,  básicamente,  las  respuestas  se  intercambiarán.  Tenga  en  cuenta  
que,  fila  =  x  y  columna  =  y.

7.  Valor  Máximo,  Valor  Mínimo  y  sus  ubicaciones

Podemos  encontrar  estos  parámetros  usando  una  imagen  de  máscara.

min_val,  max_val,  min_loc,  max_loc  =  cv2.minMaxLoc(imgray,máscara  =  máscara)

96 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

8.  Color  medio  o  intensidad  media

Aquí,  podemos  encontrar  el  color  promedio  de  un  objeto.  O  puede  ser  la  intensidad  promedio  del  objeto  en  el  modo  de  escala  de  grises.  Volvemos  
a  utilizar  la  misma  máscara  para  hacerlo.

mean_val  =  cv2.mean(im,máscara  =  máscara)

9.  Puntos  extremos

Puntos  extremos  significa  los  puntos  superior,  inferior,  derecho  e  izquierdo  del  objeto.

extremo  izquierdo  =  tupla(cnt[cnt[:,:,0].argmin()][0])  extremo  derecho  =  
tupla  (cnt[cnt[:,:,0].argmax()][0])  superior  =  tupla( cnt[cnt[:,:,1].argmin()][0])  
inferior  =  tupla(cnt[cnt[:,:,1].argmax()][0])

Por  ejemplo,  si  lo  aplico  a  un  mapa  indio,  obtengo  el  siguiente  resultado:

1.4.  Procesamiento  de  imágenes  en  OpenCV 97
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

Ejercicios

1.  Todavía  quedan  algunas  características  en  el  documento  matlab  regionprops.  Trate  de  implementarlos.

Contornos:  más  funciones

Meta

En  este  capítulo  aprenderemos  sobre

•  Defectos  de  convexidad  y  cómo  encontrarlos.

•  Encontrar  la  distancia  más  corta  de  un  punto  a  un  polígono

98 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

•  Emparejar  diferentes  formas

Teoría  y  Código

1.  Defectos  de  convexidad

Vimos  lo  que  es  un  casco  convexo  en  el  segundo  capítulo  sobre  contornos.  Cualquier  desviación  del  objeto  de  este  casco  se  puede  
considerar  como  un  defecto  de  convexidad.

OpenCV  viene  con  una  función  preparada  para  encontrar  esto,  cv2.convexityDefects().  Una  llamada  de  función  básica  se  vería  a  
continuación:

casco  =  cv2.convexHull(cnt,returnPoints  =  False)  defectos  =  
cv2.convexityDefects(cnt,hull)

Nota:  Recuerde  que  tenemos  que  pasar  returnPoints  =  False  mientras  buscamos  casco  convexo,  para  encontrar  defectos  de  convexidad.

Devuelve  una  matriz  donde  cada  fila  contiene  estos  valores:  [punto  de  inicio,  punto  final,  punto  más  lejano,  distancia  aproximada  al  punto  
más  lejano ].  Podemos  visualizarlo  mediante  una  imagen.  Dibujamos  una  línea  que  une  el  punto  de  inicio  y  el  punto  final,  luego  dibujamos  
un  círculo  en  el  punto  más  lejano.  Recuerde  que  los  primeros  tres  valores  devueltos  son  índices  de  cnt.  Así  que  tenemos  que  traer  esos  
valores  de  cnt.

importar  cv2  
importar  numpy  como  np

img  =  cv2.imread('star.jpg')  img_gray  =  
cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)  ret,  umbral  =  
cv2.threshold(img_gray,  127,  255,0)  contornos,jerarquía  =  
cv2.findContours(umbral,  2,1)  cnt  =  contornos[0]

casco  =  cv2.convexHull(cnt,returnPoints  =  False)  defectos  =  
cv2.convexityDefects(cnt,hull)

para  i  en  el  rango  (defectos.forma[0]):
s,e,f,d  =  defectos[i,0]  inicio  =  
tupla(cnt[s][0])  fin  =  tupla(cnt[e][0])  
lejano  =  tupla(cnt[f][0])  
cv2.line(img,inicio,fin,[0,255,0],2)  
cv2.circle(img,lejos,5,[0,0,255],­1)

cv2.imshow('img',img)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

Y  mira  el  resultado:

1.4.  Procesamiento  de  imágenes  en  OpenCV 99
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

2.  Prueba  de  polígono  de  puntos

Esta  función  encuentra  la  distancia  más  corta  entre  un  punto  de  la  imagen  y  un  contorno.  Devuelve  la  distancia  que  es  negativa  cuando  el  punto  está  
fuera  del  contorno,  positiva  cuando  el  punto  está  dentro  y  cero  si  el  punto  está  en  el  contorno.

Por  ejemplo,  podemos  verificar  el  punto  (50,50)  de  la  siguiente  manera:

dist  =  cv2.pointPolygonTest(cnt,(50,50),Verdadero)

En  la  función,  el  tercer  argumento  es  medirDist.  Si  es  True,  encuentra  la  distancia  con  signo.  Si  es  False,  encuentra  si  el  punto  está  dentro  o  fuera  o  en  
el  contorno  (devuelve  +1,  ­1,  0  respectivamente).

Nota:  si  no  desea  encontrar  la  distancia,  asegúrese  de  que  el  tercer  argumento  sea  Falso,  ya  que  es  un  proceso  que  requiere  mucho  tiempo.  Por  lo  
tanto,  hacerlo  Falso  da  una  aceleración  de  aproximadamente  2­3X.

3.  Combina  formas

OpenCV  viene  con  una  función  cv2.matchShapes()  que  nos  permite  comparar  dos  formas  o  dos  contornos  y  devuelve  una  métrica  que  muestra  la  
similitud.  Cuanto  más  bajo  es  el  resultado,  mejor  coincidencia  es.  Se  calcula  en  base  a  los  valores  de  momento  hu.  Los  diferentes  métodos  de  medición  
se  explican  en  los  documentos.

importar  cv2  
importar  numpy  como  np

img1  =  cv2.imread('estrella.jpg',0)  img2  =  
cv2.imread('estrella2.jpg',0)

ret,  umbral  =  cv2.umbral(img1,  127,  255,0)  ret,  umbral2  =  
cv2.umbral(img2,  127,  255,0)  contornos,jerarquía  =  
cv2.findContours(umbral,2,1)  cnt1  =  contornos[ 0]  contornos,jerarquía  =  
cv2.findContours(thresh2,2,1)  
cnt2  =  contornos[0]

derecha  =  cv2.matchShapes(cnt1,cnt2,1,0.0)  imprimir  
derecha

100 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Intenté  hacer  coincidir  formas  con  diferentes  formas  que  se  dan  a  continuación:

Obtuve  los  siguientes  resultados:

•  Hacer  coincidir  la  imagen  A  consigo  misma  =  0.0

•  Hacer  coincidir  la  imagen  A  con  la  imagen  B  =  0,001946

•  Hacer  coincidir  la  imagen  A  con  la  imagen  C  =  0,326911

Mira,  incluso  la  rotación  de  la  imagen  no  afecta  mucho  en  esta  comparación.

Ver  también:

Hu­Momentos  son  siete  momentos  invariantes  a  la  traslación,  rotación  y  escala.  El  séptimo  es  invariante  al  sesgo.  Esos  valores  se  pueden  
encontrar  usando  la  función  cv2.HuMoments() .

Recursos  adicionales

Ejercicios

1.  Consulte  la  documentación  de  cv2.pointPolygonTest(),  puede  encontrar  una  buena  imagen  en  color  rojo  y  azul.  Representa  la  distancia  
desde  todos  los  píxeles  hasta  la  curva  blanca  en  él.  Todos  los  píxeles  dentro  de  la  curva  son  azules  dependiendo  de  la  distancia.  Del  
mismo  modo,  los  puntos  exteriores  son  rojos.  Los  bordes  del  contorno  están  marcados  con  blanco.  Así  que  el  problema  es  simple.  
Escriba  un  código  para  crear  tal  representación  de  la  distancia.

2.  Compare  imágenes  de  dígitos  o  letras  usando  cv2.matchShapes().  (Eso  sería  un  paso  simple  hacia  OCR)

Jerarquía  de  contornos

Meta

Esta  vez,  aprendemos  sobre  la  jerarquía  de  contornos,  es  decir,  la  relación  padre­hijo  en  Contornos.

Teoría

En  los  últimos  artículos  sobre  contornos,  hemos  trabajado  con  varias  funciones  relacionadas  con  los  contornos  proporcionadas  por  OpenCV.
Pero  cuando  encontramos  los  contornos  en  la  imagen  usando  la  función  cv2.findContours() ,  pasamos  un  argumento,  Modo  de  recuperación  
de  contorno.  Por  lo  general,  pasamos  cv2.RETR_LIST  o  cv2.RETR_TREE  y  funcionó  bien.  Pero,  ¿qué  significa  realmente?

1.4.  Procesamiento  de  imágenes  en  OpenCV 101
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Además,  en  la  salida,  obtuvimos  tres  matrices,  la  primera  es  la  imagen,  la  segunda  son  nuestros  contornos  y  una  salida  más  que  
llamamos  jerarquía  ( consulte  los  códigos  en  artículos  anteriores).  Pero  nunca  usamos  esta  jerarquía  en  ninguna  parte.
Entonces,  ¿qué  es  esta  jerarquía  y  para  qué  sirve?  ¿Cuál  es  su  relación  con  el  argumento  de  función  mencionado  anteriormente?

Eso  es  lo  que  vamos  a  tratar  en  este  artículo.

¿Qué  es  Jerarquía?

Normalmente  usamos  la  función  cv2.findContours()  para  detectar  objetos  en  una  imagen,  ¿verdad?  A  veces  los  objetos  están  en  
diferentes  lugares.  Pero  en  algunos  casos,  algunas  formas  están  dentro  de  otras  formas.  Al  igual  que  las  figuras  anidadas.  En  este  
caso,  llamamos  al  exterior  como  padre  y  al  interior  como  hijo.  De  esta  manera,  los  contornos  de  una  imagen  tienen  alguna  relación  entre  sí.
Y  podemos  especificar  cómo  un  contorno  está  conectado  entre  sí,  por  ejemplo,  si  es  hijo  de  algún  otro  contorno,  o  es  un  padre,  etc.  
La  representación  de  esta  relación  se  llama  Jerarquía .

Considere  una  imagen  de  ejemplo  a  continuación:

En  esta  imagen,  hay  algunas  formas  que  he  numerado  del  0  al  5.  2  y  2a  denota  los  contornos  externo  e  interno  de  la  caja  más  externa.

Aquí,  los  contornos  0,1,2  son  externos  o  exteriores.  Podemos  decir  que  están  en  jerarquía­0  o  simplemente  están  en  el  mismo  nivel  
de  jerarquía.

Luego  viene  el  contorno­2a.  Se  puede  considerar  como  un  hijo  del  contorno­2  (o  de  manera  opuesta,  el  contorno­2  es  el  padre  del  
contorno­2a).  Así  que  sea  en  la  jerarquía­1.  De  manera  similar,  el  contorno­3  es  hijo  del  contorno­2  y  viene  en  la  siguiente  jerarquía.
Finalmente  los  contornos  4,5  son  los  hijos  del  contorno­3a,  y  vienen  en  el  último  nivel  de  jerarquía.  Por  la  forma  en  que  numeré  los  
cuadros,  diría  que  el  contorno­4  es  el  primer  hijo  del  contorno­3a  (también  puede  ser  el  contorno­5).

Mencioné  estas  cosas  para  comprender  términos  como  el  mismo  nivel  de  jerarquía,  contorno  externo,  contorno  secundario,  contorno  
principal,  primer  hijo ,  etc.  Ahora  entremos  en  OpenCV.

102 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Representación  de  jerarquía  en  OpenCV

Entonces,  cada  contorno  tiene  su  propia  información  sobre  qué  jerarquía  es,  quién  es  su  hijo,  quién  es  su  padre,  etc.  OpenCV  lo  representa  como  una  
matriz  de  cuatro  valores:  [ Siguiente,  Anterior,  Primer_hijo,  Padre]

"Siguiente  denota  el  siguiente  contorno  en  el  mismo  nivel  jerárquico".

Por  ejemplo,  tome  el  contorno­0  en  nuestra  imagen.  ¿Quién  es  el  próximo  contorno  en  su  mismo  nivel?  Es  contorno­1.  Así  que  simplemente  ponga  Next  =  
1.  De  manera  similar  para  Contour­1,  next  es  contorno­2.  Entonces  Siguiente  =  2.

¿Qué  pasa  con  el  contorno­2?  No  hay  contorno  siguiente  en  el  mismo  nivel.  Simplemente,  ponga  Siguiente  =  ­1.  ¿Qué  pasa  con  el  contorno  4?  Está  en  el  
mismo  nivel  que  el  contorno­5.  Entonces  su  siguiente  contorno  es  contorno­5,  entonces  Siguiente  =  5.

"Anterior  denota  el  contorno  anterior  en  el  mismo  nivel  jerárquico".

Es  lo  mismo  que  arriba.  El  contorno  anterior  del  contorno­1  es  el  contorno­0  en  el  mismo  nivel.  De  manera  similar  para  el  contorno­2,  es  el  contorno­1.  Y  
para  el  contorno­0,  no  hay  anterior,  así  que  póngalo  como  ­1.

"First_Child  denota  su  primer  contorno  secundario".

No  hay  necesidad  de  ninguna  explicación.  Para  contorno­2,  el  niño  es  contorno­2a.  Entonces  obtiene  el  valor  de  índice  correspondiente  de  contorno­2a.  
¿Qué  pasa  con  el  contorno­3a?  Tiene  dos  hijos.  Pero  tomo  solamente  al  primer  niño.  Y  es  contorno­4.  Entonces  First_Child  =  4  para  contorno­3a.

"Padre  denota  índice  de  su  contorno  padre".

Es  justo  lo  contrario  de  First_Child.  Tanto  para  el  contorno­4  como  para  el  contorno­5,  el  contorno  principal  es  el  contorno­3a.  Para  contorno­3a,  es  
contorno­3  y  así  sucesivamente.

Nota:  si  no  hay  un  hijo  o  un  padre,  ese  campo  se  toma  como  ­1

Entonces,  ahora  que  conocemos  el  estilo  de  jerarquía  utilizado  en  OpenCV,  podemos  verificar  los  modos  de  recuperación  de  contorno  en  OpenCV  con  la  
ayuda  de  la  misma  imagen  que  se  muestra  arriba.  es  decir,  ¿qué  significan  indicadores  como  cv2.RETR_LIST,  cv2.RETR_TREE,  cv2.RETR_CCOMP,  
cv2.RETR_EXTERNAL,  etc.?

Modo  de  recuperación  de  contorno

1.  RETR_LISTA

Esta  es  la  más  simple  de  las  cuatro  banderas  (desde  el  punto  de  vista  de  la  explicación).  Simplemente  recupera  todos  los  contornos,  pero  no  crea  ninguna  
relación  padre­hijo.  Padres  e  hijos  son  iguales  bajo  esta  regla,  y  son  solo  contornos.  es  decir,  todos  pertenecen  al  mismo  nivel  de  jerarquía.

Entonces,  aquí,  el  tercer  y  cuarto  término  en  la  matriz  de  jerarquía  siempre  es  ­1.  Pero  obviamente,  los  términos  Siguiente  y  Anterior  tendrán  sus  valores  
correspondientes.  Solo  compruébalo  tú  mismo  y  compruébalo.

A  continuación  se  muestra  el  resultado  que  obtuve,  y  cada  fila  son  detalles  de  jerarquía  del  contorno  correspondiente.  Por  ejemplo,  la  primera  fila  
corresponde  al  contorno  0.  El  siguiente  contorno  es  el  contorno  1.  Entonces  Siguiente  =  1.  No  hay  contorno  anterior,  entonces  Anterior  =  0.  Y  los  dos  
restantes,  como  se  dijo  antes,  es  ­1.

>>>  matriz  de  
jerarquía  ([[[ 1,  ­1,  ­1,  ­1],  [ 2,  0,  ­1,  ­1],  
[ 3,  1,  ­1,  ­1],  [ 4,  2,  ­1,  
­1],  [5,  3,  ­1,  ­1],  [6,  4,  ­1,  
­1],

1.4.  Procesamiento  de  imágenes  en  OpenCV 103
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

[7,  5,  ­1,  ­1],  [­1,  6,  ­1,  ­1]]])

Esta  es  una  buena  opción  para  usar  en  su  código,  si  no  está  usando  ninguna  función  de  jerarquía.

2.  RETR_EXTERNO

Si  usa  esta  bandera,  solo  devuelve  banderas  externas  extremas.  Todos  los  contornos  secundarios  se  dejan  atrás.  Podemos  decir,  bajo  esta  ley,  
Sólo  se  cuida  al  mayor  de  cada  familia.  No  le  importan  los  demás  miembros  de  la  familia :).

Entonces,  en  nuestra  imagen,  ¿cuántos  contornos  exteriores  extremos  hay?  es  decir,  en  el  nivel  de  jerarquía­0?.  Solo  3,  es  decir,  contornos  0,1,2,  ¿verdad?  
Ahora  intente  encontrar  los  contornos  usando  esta  bandera.  Aquí  también,  los  valores  dados  a  cada  elemento  son  los  mismos  que  los  anteriores.  Compárelo  con  
el  resultado  anterior.  A  continuación  se  muestra  lo  que  obtuve:

>>>  matriz  de  
jerarquía  ([[[ 1,  ­1,  ­1,  ­1],  [ 2,  0,  ­1,  ­1],  
[­1,  1,  ­1,  ­1]]])

Puede  usar  esta  bandera  si  desea  extraer  solo  los  contornos  exteriores.  Puede  ser  útil  en  algunos  casos.

3.  RETR_CCOMP

Esta  bandera  recupera  todos  los  contornos  y  los  organiza  en  una  jerarquía  de  2  niveles.  es  decir,  los  contornos  externos  del  objeto  (es  decir,  su  
límite)  se  colocan  en  la  jerarquía­1.  Y  los  contornos  de  los  agujeros  dentro  del  objeto  (si  los  hay)  se  colocan  en  la  jerarquía­2.  Si  hay  algún  objeto  
dentro  de  él,  su  contorno  se  coloca  nuevamente  en  la  jerarquía­1  solamente.  Y  su  agujero  en  la  jerarquía­2  y  así  sucesivamente.

Solo  considere  la  imagen  de  un  "gran  cero  blanco"  sobre  un  fondo  negro.  El  círculo  exterior  de  cero  pertenece  a  la  primera  jerarquía  y  el  círculo  
interior  de  cero  pertenece  a  la  segunda  jerarquía.

Podemos  explicarlo  con  una  simple  imagen.  Aquí  he  etiquetado  el  orden  de  los  contornos  en  color  rojo  y  la  jerarquía  a  la  que  pertenecen,  en  color  
verde  (ya  sea  1  o  2).  El  orden  es  el  mismo  que  el  orden  en  que  OpenCV  detecta  los  contornos.

104 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Así  que  considere  el  primer  contorno,  es  decir,  el  contorno­0.  Es  jerarquía­1.  Tiene  dos  agujeros,  contornos  1  y  2,  y  pertenecen  a  la  jerarquía  2.  
Entonces,  para  el  contorno­0,  el  siguiente  contorno  en  el  mismo  nivel  de  jerarquía  es  el  contorno­3.  Y  no  hay  anterior.  Y  su  primer  hijo  es  contorno­1  
en  jerarquía­2.  No  tiene  padre,  porque  está  en  la  jerarquía­1.  Entonces  su  matriz  de  jerarquía  es  [3,­1,1,­1]

Ahora  toma  el  contorno­1.  Está  en  la  jerarquía­2.  El  siguiente  en  la  misma  jerarquía  (bajo  la  paternidad  de  contorno­1)  es  contorno­2.
Ninguna  anterior.  Ningún  hijo,  pero  el  padre  es  contorno­0.  Entonces  la  matriz  es  [2,­1,­1,0].

Del  mismo  modo  contorno­2:  Está  en  la  jerarquía­2.  No  existe  el  siguiente  contorno  en  la  misma  jerarquía  bajo  el  contorno­0.  Así  que  no  Siguiente.
El  anterior  es  contorno­1.  Ningún  hijo,  el  padre  es  contorno­0.  Entonces  la  matriz  es  [­1,1,­1,0].

Contorno  ­  3:  El  siguiente  en  la  jerarquía­1  es  el  contorno­5.  El  anterior  es  contorno­0.  El  niño  es  contorno­4  y  no  tiene  padre.  Entonces  la  matriz  es  
[5,0,4,­1].

Contorno  ­  4:  Está  en  la  jerarquía  2  bajo  contorno­3  y  no  tiene  hermanos.  Entonces,  no  hay  siguiente,  no  hay  anterior,  no  hay  hijo,  el  padre  es  
contorno­3.  Entonces  la  matriz  es  [­1,­1,­1,3].

Restante  se  puede  llenar.  Esta  es  la  respuesta  final  que  obtuve:

>>>  matriz  de  
jerarquía  ([[[ 3,  ­1,  1,  ­1],  [ 2,  ­1,  ­1,  0],  [­1,  
1,  ­1,  0],  [ 5,  0,  4 ,  ­1],  [­1,  
­1,  ­1,  3],  [7,  3,  6,  ­1],

[­1,  ­1,  ­1,  5],
[8,  5,  ­1,  ­1],
[­1,  7,  ­1,  ­1]]])

1.4.  Procesamiento  de  imágenes  en  OpenCV 105
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

4.  RETR_ÁRBOL

Y  este  es  el  chico  final,  Mr.Perfect.  Recupera  todos  los  contornos  y  crea  una  lista  de  jerarquía  familiar  completa.  Incluso  dice  quién  es  
el  abuelo,  el  padre,  el  hijo,  el  nieto  e  incluso  más  allá... :).

Por  ejemplo,  tomé  la  imagen  de  arriba,  reescribí  el  código  para  cv2.RETR_TREE,  reordené  los  contornos  según  el  resultado  dado  por  
OpenCV  y  lo  analicé.  Nuevamente,  las  letras  rojas  dan  el  número  de  contorno  y  las  letras  verdes  dan  el  orden  jerárquico.

Tomar  contorno­0:  Está  en  jerarquía­0.  El  siguiente  contorno  en  la  misma  jerarquía  es  el  contorno­7.  Sin  contornos  previos.  El  niño  es  
contorno­1.  Y  sin  padre.  Entonces  la  matriz  es  [7,­1,1,­1].

Tomar  contorno­2:  Está  en  jerarquía­1.  Sin  contorno  en  el  mismo  nivel.  Ninguna  anterior.  El  niño  es  contorno­2.  El  padre  es  contorno­0.  
Entonces  la  matriz  es  [­1,­1,2,0].

Y  restante,  pruébalo  tú  mismo.  A  continuación  se  muestra  la  respuesta  completa:

>>>  matriz  de  
jerarquía  ([[[ 7,  ­1,  1,  ­1],  [­1,  ­1,  2,  0],  [­1,  
­1,  3,  1],  [­1,  ­1 ,  4,  2],

[­1,  ­1,  5,  3],
[6,  ­1,  ­1,  4],
[­1,  5,  ­1,  4],  [8,  0,  ­1,  ­1],

[­1,  7,  ­1,  ­1]]])

Recursos  adicionales

106 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Ejercicios

Histogramas  en  OpenCV

•  Histogramas  ­  1:  ¡Buscar,  Graficar,  Analizar!

Aprende  a  encontrar  y  dibujar  contornos

•  Histogramas  ­  2:  Ecualización  de  histogramas

Aprenda  a  ecualizar  histogramas  para  obtener  un  mejor  contraste  de  las  imágenes

•  Histogramas  ­  3:  Histogramas  2D

Aprenda  a  buscar  y  trazar  histogramas  2D

•  Histograma  ­  4:  retroproyección  de  histograma

Aprenda  la  retroproyección  de  histogramas  para  segmentar  objetos  coloreados

1.4.  Procesamiento  de  imágenes  en  OpenCV 107
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Histogramas  ­  1:  ¡Buscar,  Trazar,  Analizar!

Meta

Aprender  a

•  Encuentra  histogramas,  usando  las  funciones  OpenCV  y  Numpy

•  Trazar  histogramas,  utilizando  las  funciones  de  OpenCV  y  Matplotlib

•  Verá  estas  funciones:  cv2.calcHist(),  np.histogram()  etc.

Teoría

Entonces,  ¿qué  es  el  histograma?  Puede  considerar  el  histograma  como  un  gráfico  o  diagrama,  lo  que  le  da  una  idea  general  sobre  la  distribución  
de  intensidad  de  una  imagen.  Es  un  gráfico  con  valores  de  píxeles  (que  van  de  0  a  255,  no  siempre)  en  el  eje  X  y  el  número  correspondiente  de  
píxeles  en  la  imagen  en  el  eje  Y.

Es  sólo  otra  forma  de  entender  la  imagen.  Al  mirar  el  histograma  de  una  imagen,  obtiene  intuición  sobre  el  contraste,  el  brillo,  la  distribución  de  
intensidad,  etc.  de  esa  imagen.  Casi  todas  las  herramientas  de  procesamiento  de  imágenes  de  hoy  en  día  ofrecen  funciones  de  histograma.  A  
continuación  se  muestra  una  imagen  del  sitio  web  de  Cambridge  in  Color,  y  te  recomiendo  que  visites  el  sitio  para  más  detalles.

Puedes  ver  la  imagen  y  su  histograma.  (Recuerde,  este  histograma  se  dibuja  para  una  imagen  en  escala  de  grises,  no  para  una  imagen  en  color).
La  región  izquierda  del  histograma  muestra  la  cantidad  de  píxeles  más  oscuros  en  la  imagen  y  la  región  derecha  muestra  la  cantidad  de  píxeles  
más  brillantes.  En  el  histograma,  puede  ver  que  la  región  oscura  es  más  que  una  región  más  brillante,  y  la  cantidad  de  tonos  medios  (valores  de  
píxeles  en  el  rango  medio,  digamos  alrededor  de  127)  es  muy  inferior.

108 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Buscar  histograma

Ahora  que  tenemos  una  idea  de  qué  es  un  histograma,  podemos  ver  cómo  encontrarlo.  Tanto  OpenCV  como  Numpy  vienen  con  una  función  
incorporada  para  esto.  Antes  de  usar  esas  funciones,  necesitamos  entender  algunas  terminologías  relacionadas  con  los  histogramas.

BINS :  El  histograma  anterior  muestra  el  número  de  píxeles  para  cada  valor  de  píxel,  es  decir,  de  0  a  255.  Es  decir,  necesita  256  valores  para  
mostrar  el  histograma  anterior.  Pero  considere,  ¿qué  sucede  si  no  necesita  encontrar  la  cantidad  de  píxeles  para  todos  los  valores  de  píxeles  
por  separado,  sino  la  cantidad  de  píxeles  en  un  intervalo  de  valores  de  píxeles?  digamos,  por  ejemplo,  que  necesita  encontrar  el  número  de  
píxeles  entre  0  y  15,  luego  16  a  31, ...,  240  a  255.  Necesitará  solo  16  valores  para  representar  el  histograma.  Y  eso  es  lo  que  se  muestra  en  el  
ejemplo  dado  en  Tutoriales  de  OpenCV  sobre  histogramas.

Entonces,  lo  que  hace  es  simplemente  dividir  todo  el  histograma  en  16  subpartes  y  el  valor  de  cada  subparte  es  la  suma  de  todos  los  píxeles  
que  contiene.  Esta  subparte  se  llama  "BIN".  En  el  primer  caso,  el  número  de  contenedores  era  256  (uno  para  cada  píxel),  mientras  que  en  el  
segundo  caso,  es  solo  16.  BINS  está  representado  por  el  término  histSize  en  los  documentos  de  OpenCV.

DIMS :  Es  la  cantidad  de  parámetros  para  los  cuales  recopilamos  los  datos.  En  este  caso,  recopilamos  datos  sobre  una  sola  cosa,  el  valor  de  
intensidad.  Así  que  aquí  es  1.

RANGO :  Es  el  rango  de  valores  de  intensidad  que  desea  medir.  Normalmente,  es  [0,256],  es  decir,  todos  los  valores  de  intensidad.

1.  Cálculo  de  histograma  en  OpenCV

Así  que  ahora  usamos  la  función  cv2.calcHist()  para  encontrar  el  histograma.  Vamos  a  familiarizarnos  con  la  función  y  sus  parámetros:

cv2.calcHist(imágenes,  canales,  máscara,  tamaño  hist,  rangos[,  hist[,  acumular]])

1.  imágenes:  es  la  imagen  de  origen  de  tipo  uint8  o  float32.  debe  darse  entre  corchetes,  es  decir,  “[img]”.

2.  canales:  también  se  da  entre  corchetes.  Es  el  índice  del  canal  para  el  que  calculamos  el  histograma.  Por  ejemplo,  si  la  entrada  es  una  
imagen  en  escala  de  grises,  su  valor  es  [0].  Para  la  imagen  en  color,  puede  pasar  [0],  [1]  o  [2]  para  calcular  el  histograma  del  canal  azul,  
verde  o  rojo,  respectivamente.

3.  máscara:  imagen  de  máscara.  Para  encontrar  el  histograma  de  la  imagen  completa,  se  da  como  "Ninguno".  Pero  si  desea  encontrar  el  
histograma  de  una  región  particular  de  la  imagen,  debe  crear  una  imagen  de  máscara  para  eso  y  darle  como  máscara.  (Mostraré  un  
ejemplo  más  adelante.)

4.  histSize:  esto  representa  nuestro  conteo  de  BIN.  Debe  darse  entre  corchetes.  Para  la  escala  completa,  pasamos  [256].

5.  gamas:  esta  es  nuestra  GAMA.  Normalmente,  es  [0,256].

Entonces,  comencemos  con  una  imagen  de  muestra.  Simplemente  cargue  una  imagen  en  modo  de  escala  de  grises  y  encuentre  su  histograma  completo.

img  =  cv2.imread('inicio.jpg',0)  hist  =  
cv2.calcHist([img],[0],Ninguno,[256],[0,256])

hist  es  una  matriz  de  256x1,  cada  valor  corresponde  al  número  de  píxeles  en  esa  imagen  con  su  valor  de  píxel  correspondiente.

2.  Cálculo  de  histograma  en  Numpy

Numpy  también  le  proporciona  una  función,  np.histogram().  Entonces,  en  lugar  de  la  función  calcHist  (),  puede  probar  la  siguiente  línea:

hist,bins  =  np.histogram(img.ravel(),256,[0,256])

hist  es  el  mismo  que  calculamos  antes.  Pero  los  contenedores  tendrán  257  elementos,  porque  Numpy  calcula  los  contenedores  como  0­0,99,  
1­1,99,  2­2,99,  etc.  Por  lo  tanto,  el  rango  final  sería  255­255,99.  Para  representar  eso,  también  agregan  256  al  final  de  los  contenedores.  Pero  
no  necesitamos  ese  256.  Hasta  255  es  suficiente.

1.4.  Procesamiento  de  imágenes  en  OpenCV 109
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Ver  también:

Numpy  tiene  otra  función,  np.bincount() ,  que  es  mucho  más  rápida  que  (alrededor  de  10X)  np.histogram().  Entonces,  para  histogramas  
unidimensionales,  es  mejor  que  pruebes  eso.  No  olvide  establecer  minlength  =  256  en  np.bincount.  Por  ejemplo,  hist  =  
np.bincount(img.ravel(),minlength=256)

Nota:  la  función  OpenCV  es  más  rápida  que  (alrededor  de  40X)  que  np.histogram().  Así  que  quédese  con  la  función  OpenCV.

Ahora  deberíamos  trazar  histogramas,  pero  ¿cómo?

Trazado  de  histogramas

Hay  dos  maneras  para  esto,

1.  Camino  corto:  use  las  funciones  de  trazado  de  Matplotlib

2.  Long  Way:  use  las  funciones  de  dibujo  de  OpenCV

1.  Usando  Matplotlib

Matplotlib  viene  con  una  función  de  trazado  de  histogramas:  matplotlib.pyplot.hist()

Encuentra  directamente  el  histograma  y  lo  traza.  No  necesita  usar  la  función  calcHist()  o  np.histogram()  para  encontrar  el  histograma.
Vea  el  código  a  continuación:

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('inicio.jpg',0)  
plt.hist(img.ravel(),256,[0,256]);  plt.mostrar()

Obtendrá  una  trama  de  la  siguiente  manera:

110 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

O  puede  usar  el  gráfico  normal  de  matplotlib,  que  sería  bueno  para  el  gráfico  BGR.  Para  eso,  primero  debe  encontrar  los  datos  del  
histograma.  Pruebe  el  siguiente  código:

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('home.jpg')  color  =  ('b','g','r')  
for  i,col  in  enumerate(color):

histr  =  cv2.calcHist([img],[i],Ninguno,[256],[0,256])  plt.plot(histr,color  =  col)  
plt.xlim([0,256])

plt.mostrar()

Resultado:

Puede  deducir  del  gráfico  anterior  que  el  azul  tiene  algunas  áreas  de  alto  valor  en  la  imagen  (obviamente  debería  ser  debido  al  cielo)

2.  Usando  OpenCV

Bueno,  aquí  ajustas  los  valores  de  los  histogramas  junto  con  sus  valores  bin  para  que  se  vean  como  las  coordenadas  x,  y  para  que  puedas  
dibujarlo  usando  la  función  cv2.line()  o  cv2.polyline()  para  generar  la  misma  imagen  que  arriba.  Esto  ya  está  disponible  con  muestras  
oficiales  de  OpenCV­Python2.  Revisa  el  código

1.4.  Procesamiento  de  imágenes  en  OpenCV 111
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Aplicación  de  Mascarilla

Usamos  cv2.calcHist()  para  encontrar  el  histograma  de  la  imagen  completa.  ¿Qué  sucede  si  desea  encontrar  histogramas  de  algunas  regiones  de  una  
imagen?  Simplemente  cree  una  imagen  de  máscara  con  color  blanco  en  la  región  que  desea  encontrar  en  el  histograma  y  negro  en  caso  contrario.
Luego  pasa  esto  como  la  máscara.

img  =  cv2.imread('inicio.jpg',0)

#  crear  una  máscara  
mask  =  np.zeros(img.shape[:2],  np.uint8)  mask[100:300,  
100:400]  =  255  masked_img  =  
cv2.bitwise_and(img,img,mask  =  mask)

#  Calcular  el  histograma  con  máscara  y  sin  máscara  #  Comprobar  el  tercer  
argumento  de  la  máscara  hist_full  =  
cv2.calcHist([img],[0],Ninguno,[256],[0,256])  hist_mask  =  cv2.calcHist([img],[0 ],máscara,
[256],[0,256])

plt.subplot(221),  plt.imshow(img,  'gris')  plt.subplot(222),  
plt.imshow(máscara,  'gris')  plt.subplot(223),  plt.imshow(masked_img,  
'gris' )  plt.subplot(224),  plt.plot(hist_full),  plt.plot(hist_mask)  plt.xlim([0,256])

plt.mostrar()

Vea  el  resultado.  En  el  gráfico  de  histograma,  la  línea  azul  muestra  el  histograma  de  la  imagen  completa,  mientras  que  la  línea  verde  muestra  el  histograma  de  la  
región  enmascarada.

Recursos  adicionales

1.  Sitio  web  de  Cambridge  en  color

112 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Ejercicios

Histogramas  ­  2:  Ecualización  de  histogramas

Meta

En  esta  sección,

•  Aprenderemos  los  conceptos  de  ecualización  de  histogramas  y  los  utilizaremos  para  mejorar  el  contraste  de  nuestras  imágenes.

Teoría

Considere  una  imagen  cuyos  valores  de  píxel  se  limitan  a  un  rango  específico  de  valores  únicamente.  Por  ejemplo,  una  imagen  más  
brillante  tendrá  todos  los  píxeles  confinados  a  valores  altos.  Pero  una  buena  imagen  tendrá  píxeles  de  todas  las  regiones  de  la  imagen.  Por  
lo  tanto,  debe  estirar  este  histograma  hacia  ambos  extremos  (como  se  muestra  en  la  imagen  a  continuación,  de  wikipedia)  y  eso  es  lo  que  
hace  la  ecualización  de  histograma  (en  palabras  simples).  Esto  normalmente  mejora  el  contraste  de  la  imagen.

Le  recomendaría  que  lea  la  página  de  wikipedia  sobre  la  ecualización  de  histogramas  para  más  detalles  al  respecto.  Tiene  una  muy  buena  
explicación  con  ejemplos  elaborados,  por  lo  que  entenderías  casi  todo  después  de  leer  eso.
En  cambio,  aquí  veremos  su  implementación  de  Numpy.  Después  de  eso,  veremos  la  función  OpenCV.

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('wiki.jpg',0)

hist,bins  =  np.histogram(img.flatten(),256,[0,256])

cdf  =  hist.cumsum()  
cdf_normalizado  =  cdf  *  hist.max()/  cdf.max()

plt.plot(cdf_normalizado,  color  =  'b')  plt.hist(img.flatten(),256,
[0,256],  color  =  'r')  plt.xlim([0,256])  plt.legend(('cdf' ,'histograma'),  loc  =  'arriba  
a  la  izquierda')  plt.show()

1.4.  Procesamiento  de  imágenes  en  OpenCV 113
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Puede  ver  que  el  histograma  se  encuentra  en  la  región  más  brillante.  Necesitamos  el  espectro  completo.  Para  eso,  necesitamos  una  función  de  transformación  
que  mapee  los  píxeles  de  entrada  en  la  región  más  brillante  a  los  píxeles  de  salida  en  la  región  completa.  Eso  es  lo  que  hace  la  ecualización  de  histogramas.

Ahora  encontramos  el  valor  mínimo  del  histograma  (excluyendo  0)  y  aplicamos  la  ecuación  de  ecualización  del  histograma  como  se  indica  en  la  
página  wiki.  Pero  aquí  he  usado  el  concepto  de  matriz  enmascarada  de  Numpy.  Para  una  matriz  enmascarada,  todas  las  operaciones  se  
realizan  en  elementos  no  enmascarados.  Puede  leer  más  sobre  esto  en  los  documentos  de  Numpy  sobre  matrices  enmascaradas.

cdf_m  =  np.ma.masked_equal(cdf,0)  cdf_m  =  
(cdf_m  ­  cdf_m.min())*255/(cdf_m.max()­cdf_m.min())  cdf  =  np.ma.filled(cdf_m,0 ).astype('uint8')

Ahora  tenemos  la  tabla  de  búsqueda  que  nos  brinda  información  sobre  cuál  es  el  valor  de  píxel  de  salida  para  cada  valor  de  píxel  de  entrada.  
Así  que  solo  aplicamos  la  transformación.

img2  =  cdf[img]

Ahora  calculamos  su  histograma  y  cdf  como  antes  (usted  lo  hace)  y  el  resultado  se  ve  a  continuación:

114 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Otra  característica  importante  es  que,  incluso  si  la  imagen  era  una  imagen  más  oscura  (en  lugar  de  una  más  brillante  que  usamos),  después  de  la  
ecualización  obtendremos  casi  la  misma  imagen  que  obtuvimos.  Como  resultado,  esto  se  usa  como  una  "herramienta  de  referencia"  para  hacer  todas  
las  imágenes  con  las  mismas  condiciones  de  iluminación.  Esto  es  útil  en  muchos  casos.  Por  ejemplo,  en  el  reconocimiento  facial,  antes  de  entrenar  
los  datos  faciales,  las  imágenes  de  los  rostros  se  ecualizan  en  histograma  para  que  todos  tengan  las  mismas  condiciones  de  iluminación.

Ecualización  de  histogramas  en  OpenCV

OpenCV  tiene  una  función  para  hacer  esto,  cv2.equalizeHist().  Su  entrada  es  solo  una  imagen  en  escala  de  grises  y  la  salida  es  nuestra  imagen  
ecualizada  de  histograma.

A  continuación  se  muestra  un  fragmento  de  código  simple  que  muestra  su  uso  para  la  misma  imagen  que  usamos:

img  =  cv2.imread('wiki.jpg',0)  equ  =  
cv2.equalizeHist(img)  res  =  
np.hstack((img,equ))  #apilar  imágenes  una  al  lado  de  la  otra  cv2.imwrite('res.png  ',  res)

1.4.  Procesamiento  de  imágenes  en  OpenCV 115
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Así  que  ahora  puedes  tomar  diferentes  imágenes  con  diferentes  condiciones  de  luz,  ecualizarlas  y  comprobar  los  resultados.

La  ecualización  del  histograma  es  buena  cuando  el  histograma  de  la  imagen  se  limita  a  una  región  particular.  No  funcionará  bien  en  lugares  donde  
hay  grandes  variaciones  de  intensidad  donde  el  histograma  cubre  una  gran  región,  es  decir,  están  presentes  píxeles  brillantes  y  oscuros.  Consulte  
los  enlaces  SOF  en  Recursos  adicionales.

CLAHE  (ecualización  de  histograma  adaptativo  limitado  por  contraste)

La  primera  ecualización  de  histograma  que  acabamos  de  ver  considera  el  contraste  global  de  la  imagen.  En  muchos  casos,  no  es  una  buena  idea.  
Por  ejemplo,  la  siguiente  imagen  muestra  una  imagen  de  entrada  y  su  resultado  después  de  la  ecualización  global  del  histograma.

116 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

1.4.  Procesamiento  de  imágenes  en  OpenCV 117
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Es  cierto  que  el  contraste  de  fondo  ha  mejorado  tras  la  ecualización  del  histograma.  Pero  compare  la  cara  de  la  estatua  en  ambas  imágenes.  Perdimos  la  
mayor  parte  de  la  información  allí  debido  al  exceso  de  brillo.  Es  porque  su  histograma  no  se  limita  a  una  región  en  particular  como  vimos  en  casos  anteriores  
(intente  trazar  el  histograma  de  la  imagen  de  entrada,  obtendrá  más  intuición).

Entonces,  para  resolver  este  problema,  se  usa  la  ecualización  de  histograma  adaptativo .  En  este,  la  imagen  se  divide  en  pequeños  bloques  llamados  
"mosaicos" (tileSize  es  8x8  por  defecto  en  OpenCV).  Luego,  cada  uno  de  estos  bloques  se  iguala  en  histograma  como  de  costumbre.  Entonces,  en  un  área  
pequeña,  el  histograma  se  limitaría  a  una  región  pequeña  (a  menos  que  haya  ruido).  Si  hay  ruido,  se  amplificará.
Para  evitar  esto,  se  aplica  la  limitación  de  contraste .  Si  algún  bin  de  histograma  está  por  encima  del  límite  de  contraste  especificado  (por  defecto  40  en  
OpenCV),  esos  píxeles  se  recortan  y  distribuyen  uniformemente  a  otros  bins  antes  de  aplicar  la  ecualización  de  histograma.
Después  de  la  ecualización,  para  eliminar  los  artefactos  en  los  bordes  de  los  mosaicos,  se  aplica  la  interpolación  bilineal.

El  siguiente  fragmento  de  código  muestra  cómo  aplicar  CLAHE  en  OpenCV:

importar  numpy  como  np  
importar  cv2

img  =  cv2.imread('tsukuba_l.png',0)

#  crear  un  objeto  CLAHE  (los  argumentos  son  opcionales).  clahe  =  
cv2.createCLAHE(clipLimit=2.0,  tileGridSize=(8,8))  cl1  =  clahe.apply(img)

cv2.imwrite('clahe_2.jpg',cl1)

Vea  el  resultado  a  continuación  y  compárelo  con  los  resultados  anteriores,  especialmente  la  región  de  la  estatua:

Recursos  adicionales

1.  Página  de  Wikipedia  sobre  ecualización  de  histogramas

2.  Matrices  enmascaradas  en  Numpy

118 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Consulte  también  estas  preguntas  de  SOF  sobre  el  ajuste  de  contraste:

3.  ¿Cómo  puedo  ajustar  el  contraste  en  OpenCV  en  C?

4.  ¿Cómo  igualo  el  contraste  y  el  brillo  de  las  imágenes  usando  opencv?

Ejercicios

Histogramas  ­  3:  Histogramas  2D

Meta

En  este  capítulo,  aprenderemos  a  encontrar  y  trazar  histogramas  2D.  Será  útil  en  los  próximos  capítulos.

Introducción

En  el  primer  artículo,  calculamos  y  representamos  un  histograma  unidimensional.  Se  llama  unidimensional  porque  solo  estamos  
considerando  una  característica,  es  decir,  el  valor  de  intensidad  de  escala  de  grises  del  píxel.  Pero  en  los  histogramas  bidimensionales,  
considera  dos  características.  Normalmente  se  usa  para  encontrar  histogramas  de  color  donde  dos  características  son  valores  de  tono  y  
saturación  de  cada  píxel.

Hay  una  muestra  de  python  en  las  muestras  oficiales.  ya  para  encontrar  histogramas  de  color.  Intentaremos  entender  cómo  crear  un  
histograma  de  color  de  este  tipo,  y  será  útil  para  comprender  otros  temas  como  la  retroproyección  del  histograma.

Histograma  2D  en  OpenCV

Es  bastante  simple  y  se  calcula  usando  la  misma  función,  cv2.calcHist().  Para  histogramas  de  color,  necesitamos  convertir  la  imagen  de  
BGR  a  HSV.  (Recuerde,  para  el  histograma  1D,  convertimos  de  BGR  a  escala  de  grises).  Para  histogramas  2D,  sus  parámetros  se  
modificarán  de  la  siguiente  manera:

•  canales  =  [0,1]  porque  necesitamos  procesar  tanto  el  plano  H  como  el  S.

•  bins  =  [180,256]  180  para  el  plano  H  y  256  para  el  plano  S.

•  rango  =  [0,180,0,256]  El  valor  de  tono  se  encuentra  entre  0  y  180  y  la  saturación  se  encuentra  entre  0  y  256.

Ahora  revisa  el  siguiente  código:

importar  cv2  
importar  numpy  como  np

img  =  cv2.imread('inicio.jpg')  hsv  =  
cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

hist  =  cv2.calcHist([hsv],  [0,  1],  Ninguno,  [180,  256],  [0,  180,  0,  256])

Eso  es  todo.

Histograma  2D  en  Numpy

Numpy  también  proporciona  una  función  específica  para  esto:  np.histogram2d().  (Recuerde,  para  el  histograma  1D  usamos  np.histogram() ).

1.4.  Procesamiento  de  imágenes  en  OpenCV 119
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('inicio.jpg')  hsv  =  
cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

hist,  xbins,  ybins  =  np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])

El  primer  argumento  es  el  plano  H,  el  segundo  es  el  plano  S,  el  tercero  es  el  número  de  contenedores  para  cada  uno  y  el  cuarto  es  su  rango.

Ahora  podemos  comprobar  cómo  trazar  este  histograma  de  color.

Trazado  de  histogramas  2D

Método  ­  1:  Usando  cv2.imshow()

El  resultado  que  obtenemos  es  una  matriz  bidimensional  de  tamaño  180x256.  Entonces  podemos  mostrarlos  como  lo  hacemos  normalmente,  usando  
la  función  cv2.imshow().  Será  una  imagen  en  escala  de  grises  y  no  dará  mucha  idea  de  qué  colores  hay,  a  menos  que  conozca  los  valores  de  Tono  
de  diferentes  colores.

Método  ­  2:  Usando  Matplotlib

Podemos  usar  la  función  matplotlib.pyplot.imshow()  para  trazar  un  histograma  2D  con  diferentes  mapas  de  color.  Nos  da  una  idea  mucho  más  clara  
sobre  las  diferentes  densidades  de  píxeles.  Pero  esto  tampoco  nos  da  una  idea  de  qué  color  hay  en  un  primer  vistazo,  a  menos  que  conozca  los  
valores  de  Tono  de  diferentes  colores.  Aún  así  prefiero  este  método.  Es  simple  y  mejor.

Nota:  Al  usar  esta  función,  recuerde  que  el  indicador  de  interpolación  debe  ser  el  más  cercano  para  obtener  mejores  resultados.

Considere  el  código:

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('inicio.jpg')  hsv  =  
cv2.cvtColor(img,cv2.COLOR_BGR2HSV)  hist  =  
cv2.calcHist( [hsv],  [0,  1],  Ninguno,  [180,  256],  [0 ,  180,  0,  256] )

plt.imshow(hist,interpolación  =  'más  cercano')  plt.show()

A  continuación  se  muestra  la  imagen  de  entrada  y  su  diagrama  de  histograma  de  color.  El  eje  X  muestra  los  valores  S  y  el  eje  Y  muestra  el  tono.

120 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

En  el  histograma,  puedes  ver  algunos  valores  altos  cerca  de  H  =  100  y  S  =  200.  Corresponde  al  azul  del  cielo.  De  igual  manera  se  puede  ver  
otro  pico  cerca  de  H  =  25  y  S  =  100.  Corresponde  al  amarillo  del  palacio.  Puede  verificarlo  con  cualquier  herramienta  de  edición  de  imágenes  
como  GIMP.

Método  3:  ¡estilo  de  muestra  OpenCV!

Hay  un  código  de  muestra  para  el  histograma  de  color  en  las  muestras  de  OpenCV­Python2.  Si  ejecuta  el  código,  puede  ver  que  su  tograma  
también  muestra  el  color  correspondiente.  O  simplemente  genera  un  histograma  codificado  por  colores.  Su  resultado  es  muy  bueno  (aunque  
necesita  agregar  un  montón  de  líneas  extra).

En  ese  código,  el  autor  creó  un  mapa  de  colores  en  HSV.  Luego  lo  convirtió  en  BGR.  La  imagen  del  histograma  resultante  se  multiplica  con  
este  mapa  de  colores.  También  utiliza  algunos  pasos  de  preprocesamiento  para  eliminar  pequeños  píxeles  aislados,  lo  que  da  como  resultado  
un  buen  histograma.

Dejo  que  los  lectores  ejecuten  el  código,  lo  analicen  y  tengan  sus  propios  trucos.  A  continuación  se  muestra  la  salida  de  ese  código  para  la  
misma  imagen  que  la  anterior:

Puede  ver  claramente  en  el  histograma  qué  colores  están  presentes,  el  azul  está  allí,  el  amarillo  está  allí  y  algo  de  blanco  debido  al  tablero  de  
ajedrez  está  allí.  Lindo !!!

Recursos  adicionales

Ejercicios

Histograma  ­  4:  retroproyección  de  histograma

1.4.  Procesamiento  de  imágenes  en  OpenCV 121
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Meta

En  este  capítulo,  aprenderemos  sobre  la  retroproyección  de  histogramas.

Teoría

Fue  propuesto  por  Michael  J.  Swain , Dana  H.  Ballard  en  su  artículo  Indexación  mediante  histogramas  de  color.

¿Qué  es  realmente  en  palabras  simples?  Se  utiliza  para  la  segmentación  de  imágenes  o  para  encontrar  objetos  de  interés  en  una  
imagen.  En  palabras  simples,  crea  una  imagen  del  mismo  tamaño  (pero  de  un  solo  canal)  que  la  de  nuestra  imagen  de  entrada,  donde  
cada  píxel  corresponde  a  la  probabilidad  de  que  ese  píxel  pertenezca  a  nuestro  objeto.  En  mundos  más  simples,  la  imagen  de  salida  
tendrá  nuestro  objeto  de  interés  más  blanco  en  comparación  con  la  parte  restante.  Bueno,  esa  es  una  explicación  intuitiva.  (No  puedo  
hacerlo  más  simple).  La  retroproyección  de  histograma  se  utiliza  con  el  algoritmo  camshift,  etc.

Cómo  lo  hacemos ?  Creamos  un  histograma  de  una  imagen  que  contenga  nuestro  objeto  de  interés  (en  nuestro  caso,  el  suelo,  
dejando  jugador  y  otras  cosas).  El  objeto  debe  llenar  la  imagen  tanto  como  sea  posible  para  obtener  mejores  resultados.  Y  se  prefiere  
un  histograma  de  color  sobre  un  histograma  en  escala  de  grises,  porque  el  color  del  objeto  es  una  mejor  manera  de  definir  el  objeto  
que  su  intensidad  en  escala  de  grises.  Luego,  "reproyectamos"  este  histograma  sobre  nuestra  imagen  de  prueba  donde  necesitamos  
encontrar  el  objeto,  es  decir,  en  otras  palabras,  calculamos  la  probabilidad  de  que  cada  píxel  pertenezca  al  suelo  y  lo  mostramos.  La  
salida  resultante  en  el  umbral  adecuado  nos  da  el  terreno  solo.

Algoritmo  en  Numpy

1.  Primero  necesitamos  calcular  el  histograma  de  color  tanto  del  objeto  que  necesitamos  encontrar  (que  sea  'M')  como  de  la  imagen  
donde  vamos  a  buscar  (que  sea  'I').

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

#roi  es  el  objeto  o  región  del  objeto  que  necesitamos  encontrar  roi  =  cv2.imread('rose_red.png')  
hsv  =  cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)

#target  es  la  imagen  que  buscamos  en  target  =  
cv2.imread('rose.png')  hsvt  =  
cv2.cvtColor(target,cv2.COLOR_BGR2HSV)

#  Encuentra  los  histogramas  usando  calcHist.  Se  puede  hacer  con  np.histogram2d  también  M  =  cv2.calcHist([hsv],[0,  1],  None,  
[180,  256],  [0,  180,  0,  256] )
I  =  cv2.calcHist([hsvt],[0,  1],  Ninguno,  [180,  256],  [0,  180,  0,  256] )

2.  Encuentre  la  relación  =  Luego  
. retroproyecte  R,  es  decir,  use  R  como  paleta  y  cree  una  nueva  imagen  con  cada  píxel  como  su  
probabilidad  correspondiente  de  ser  objetivo.  es  decir,  B(x,y)  =  R[h(x,y),s(x,y)]  donde  h  es  el  matiz  ys  es  la  saturación  del  píxel  en  
(x,y).  Después  de  eso,  aplique  la  condición  ( , )  =  [ ( , ),  1].

h,s,v  =  cv2.split(hsvt)
B  =  R[h.ravel(),s.ravel()]
B  =  np.mínimo(B,1)
B  =  B.reformar(hsvt.forma[:2])

3.  Ahora  aplique  una  convolución  con  un  disco  circular,  =  * , donde  D  es  el  núcleo  del  disco.
disco  =  cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))  cv2.filter2D(B,­1,disco,B)

122 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

B  =  np.uint8(B)  
cv2.normalizar(B,B,0,255,cv2.NORM_MINMAX)

4.  Ahora  la  ubicación  de  máxima  intensidad  nos  da  la  ubicación  del  objeto.  Si  esperamos  una  región  en  la  imagen,  el  umbral  para  un  
valor  adecuado  da  un  buen  resultado.

ret,umbral  =  cv2.umbral(B,50,255,0)

Eso  es  todo !!

Retroproyección  en  OpenCV

OpenCV  proporciona  una  función  incorporada  cv2.calcBackProject().  Sus  parámetros  son  casi  los  mismos  que  los  de  la  función  
cv2.calcHist() .  Uno  de  sus  parámetros  es  el  histograma,  que  es  el  histograma  del  objeto  y  tenemos  que  encontrarlo.  Además,  el  
histograma  del  objeto  debe  normalizarse  antes  de  pasar  a  la  función  backproject.  Devuelve  la  imagen  de  probabilidad.  Luego  
convolucionamos  la  imagen  con  un  núcleo  de  disco  y  aplicamos  el  umbral.  A  continuación  se  muestra  mi  código  y  salida:

importar  cv2  
importar  numpy  como  np

roi  =  cv2.imread('rosa_roja.png')  hsv  =  
cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)

objetivo  =  cv2.imread('rosa.png')  hsvt  =  
cv2.cvtColor(objetivo,cv2.COLOR_BGR2HSV)

#  calculando  el  histograma  del  objeto  roihist  =  
cv2.calcHist([hsv],[0,  1],  None,  [180,  256],  [0,  180,  0,  256] )

#  normaliza  el  histograma  y  aplica  retroproyección  
cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)  dst  =  cv2.calcBackProject([hsvt],
[0,1],roihist,[0,180,0,256],1)

#  Ahora  convoluta  con  disco  circular
disco  =  cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))  cv2.filter2D(dst,­1,disco,dst)

#  umbral  y  AND  binario  ret,thresh  =  
cv2.threshold(dst,50,255,0)  thresh  =  cv2.merge((thresh,thresh,thresh))  
res  =  cv2.bitwise_and(target,thresh)

res  =  np.vstack((objetivo,umbral,res))  cv2.imwrite('res.jpg',res)

A  continuación  se  muestra  un  ejemplo  con  el  que  trabajé.  Usé  la  región  dentro  del  rectángulo  azul  como  objeto  de  muestra  y  quería  
extraer  todo  el  terreno.

1.4.  Procesamiento  de  imágenes  en  OpenCV 123
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

124 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

1.  "Indización  a  través  de  histogramas  de  color",  Swain,  Michael  J. , Tercera  conferencia  internacional  sobre  visión  artificial,  1990.

Ejercicios

Transformaciones  de  imagen  en  OpenCV

•  Transformada  de  Fourier

Aprende  a  encontrar  la  Transformada  de  Fourier  de  imágenes

1.4.  Procesamiento  de  imágenes  en  OpenCV 125
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Transformada  de  Fourier

Meta

En  esta  sección  aprenderemos

•  Para  encontrar  la  Transformada  de  Fourier  de  imágenes  usando  OpenCV

•  Para  utilizar  las  funciones  FFT  disponibles  en  Numpy

•  Algunas  aplicaciones  de  la  Transformada  de  Fourier

•  Veremos  las  siguientes  funciones:  cv2.dft(),  cv2.idft()  etc.

Teoría

La  transformada  de  Fourier  se  utiliza  para  analizar  las  características  de  frecuencia  de  varios  filtros.  Para  las  imágenes,  se  utiliza  la  transformada  
discreta  de  Fourier  (DFT)  2D  para  encontrar  el  dominio  de  la  frecuencia.  Se  utiliza  un  algoritmo  rápido  llamado  Transformada  Rápida  de  Fourier  (FFT)  
para  el  cálculo  de  DFT.  Los  detalles  sobre  estos  se  pueden  encontrar  en  cualquier  libro  de  texto  de  procesamiento  de  imágenes  o  procesamiento  de  señales.
Consulte  la  sección  Recursos  adicionales .

Para  una  señal  sinusoidal,  ( )  =  sin(2 ),  podemos  decir  que  es  la  frecuencia  de  la  señal,  y  si  se  toma  su  dominio  de  frecuencia,  podemos  ver  un  pico  en  
. discreta,  obtenemos  lo  mismo  dominio  de  frecuencia,  pero  es  periódico  en  el  rango  [−, ]  o  [0,  2]  (o  [0, ]  
Si  la  señal  se  muestrea  para  formar  una  señal  
para  DFT  de  N  puntos).  Puede  considerar  una  imagen  como  una  señal  que  se  muestrea  en  dos  direcciones.  Entonces,  tomar  la  transformada  de  Fourier  
en  las  direcciones  X  e  Y  le  da  la  representación  de  frecuencia  de  la  imagen.

Más  intuitivamente,  para  la  señal  sinusoidal,  si  la  amplitud  varía  tan  rápido  en  poco  tiempo,  se  puede  decir  que  es  una  señal  de  alta  frecuencia.  Si  varía  
lentamente,  es  una  señal  de  baja  frecuencia.  Puedes  extender  la  misma  idea  a  las  imágenes.  ¿Dónde  varía  drásticamente  la  amplitud  en  las  imágenes?  
En  los  puntos  de  borde,  o  ruidos.  Entonces  podemos  decir  que  los  bordes  y  los  ruidos  son  contenidos  de  alta  frecuencia  en  una  imagen.  Si  no  hay  
muchos  cambios  en  la  amplitud,  es  un  componente  de  baja  frecuencia.  (Algunos  enlaces  se  agregan  a  Recursos  adicionales  que  explican  la  
transformación  de  frecuencia  de  manera  intuitiva  con  ejemplos).

Ahora  veremos  cómo  encontrar  la  transformada  de  Fourier.

Transformada  de  Fourier  en  Numpy

Primero  veremos  cómo  encontrar  la  Transformada  de  Fourier  usando  Numpy.  Numpy  tiene  un  paquete  FFT  para  hacer  esto.  np.fft.fft2()  nos  proporciona  
la  transformación  de  frecuencia  que  será  una  matriz  compleja.  Su  primer  argumento  es  la  imagen  de  entrada,  que  está  en  escala  de  grises.  El  segundo  
argumento  es  opcional  y  decide  el  tamaño  de  la  matriz  de  salida.  Si  es  mayor  que  el  tamaño  de  la  imagen  de  entrada,  la  imagen  de  entrada  se  rellena  
con  ceros  antes  del  cálculo  de  FFT.  Si  es  menor  que  la  imagen  de  entrada,  la  imagen  de  entrada  se  recortará.
Si  no  se  pasan  argumentos,  el  tamaño  de  la  matriz  de  salida  será  el  mismo  que  el  de  la  entrada.

Ahora,  una  vez  que  obtenga  el  resultado,  el  componente  de  frecuencia  cero  (componente  de  CC)  estará  en  la  esquina  superior  izquierda.  Si  desea  
traerlo  al  centro,  debe  cambiar  el  resultado  en  ambas  direcciones.  Esto  simplemente  lo  hace  la  función  np.fft.fftshift().  (Es  más  fácil  de  analizar).  Una  
2
vez  que  haya  encontrado  la  transformación  de  frecuencia,  puede  encontrar  el  espectro  de  magnitud.

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('messi5.jpg',0)  f  =  np.fft.fft2(img)  
fshift  =  np.fft.fftshift(f)  
magnitud_espectro  =  20*np.log(np.abs(fshift))

126 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

plt.subplot(121),plt.imshow(img,  cmap  =  'gris')  plt.title('  Imagen  de  
entrada'),  plt.xticks([]),  plt.yticks([])  plt.subplot(122) ,plt.imshow(magnitud_espectro,  
cmap  =  'gris')  plt.title('Magnitud  Espectro'),  plt.xticks([]),  plt.yticks([])  plt.show()

El  resultado  se  ve  a  continuación:

Mira,  puedes  ver  una  región  más  blanca  en  el  centro  que  muestra  que  el  contenido  de  baja  frecuencia  es  más.

Así  que  encontraste  la  transformada  de  frecuencia.  Ahora  puedes  hacer  algunas  operaciones  en  el  dominio  de  la  frecuencia,  como  el  filtrado  de  
paso  alto  y  reconstruir  la  imagen,  es  decir,  encontrar  la  DFT  inversa.  Para  eso,  simplemente  elimina  las  frecuencias  bajas  enmascarando  con  
una  ventana  rectangular  de  tamaño  60x60.  Luego  aplique  el  cambio  inverso  usando  np.fft.ifftshift()  para  que  el  componente  DC  vuelva  a  
aparecer  en  la  esquina  superior  izquierda.  Luego  encuentre  la  FFT  inversa  usando  la  función  np.ifft2() .  El  resultado,  de  nuevo,  será  un  número  
complejo.  Puede  tomar  su  valor  absoluto.

filas,  columnas  =  img.forma  
cuervo,ccol  =  filas/2  columnas/2  ,
fshift[cuervo­30:cuervo+30,  ccol­30:ccol+30]  =  0  f_ishift  =  
np.fft.ifftshift(fshift)  img_back  =  np .fft.ifft2(f_ishift)  
img_back  =  np.abs(img_back)

plt.subplot(131),plt.imshow(img,  cmap  =  'gris')  plt.title('  Imagen  de  
entrada'),  plt.xticks([]),  plt.yticks([])  plt.subplot(132) ,plt.imshow(img_back,  cmap  =  'gray')  
plt.title('Imagen  después  de  HPF'),  plt.xticks([]),  plt.yticks([])  
plt.subplot(133),plt.imshow( img_back)  plt.title('Resultado  en  JET'),  plt.xticks([]),  plt.yticks([])

plt.mostrar()

El  resultado  se  ve  a  continuación:

1.4.  Procesamiento  de  imágenes  en  OpenCV 127
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

El  resultado  muestra  que  el  filtrado  de  paso  alto  es  una  operación  de  detección  de  bordes.  Esto  es  lo  que  hemos  visto  en  el  capítulo  Gradientes  
de  imagen.  Esto  también  muestra  que  la  mayoría  de  los  datos  de  imagen  están  presentes  en  la  región  de  baja  frecuencia  del  espectro.  De  
todos  modos,  hemos  visto  cómo  encontrar  DFT,  IDFT,  etc.  en  Numpy.  Ahora  veamos  cómo  hacerlo  en  OpenCV.

Si  observa  de  cerca  el  resultado,  especialmente  la  última  imagen  en  color  JET,  puede  ver  algunos  artefactos  (una  instancia  que  he  marcado  
con  una  flecha  roja).  Muestra  algunas  estructuras  similares  a  ondas  allí,  y  se  llama  efectos  de  llamada.  Es  causado  por  la  ventana  rectangular  
que  usamos  para  enmascarar.  Esta  máscara  se  convierte  en  forma  sincronizada,  lo  que  provoca  este  problema.  Entonces,  las  ventanas  
rectangulares  no  se  usan  para  filtrar.  La  mejor  opción  es  Gaussian  Windows.

Transformada  de  Fourier  en  OpenCV

OpenCV  proporciona  las  funciones  cv2.dft()  y  cv2.idft()  para  esto.  Devuelve  el  mismo  resultado  que  el  anterior,  pero  con  dos  canales.  El  primer  
canal  tendrá  la  parte  real  del  resultado  y  el  segundo  canal  tendrá  la  parte  imaginaria  del  resultado.  La  imagen  de  entrada  debe  convertirse  
primero  a  np.float32.  Veremos  cómo  hacerlo.

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('messi5.jpg',0)

dft  =  cv2.dft(np.float32(img),flags  =  cv2.DFT_COMPLEX_OUTPUT)  dft_shift  =  np.fft.fftshift(dft)

magnitud_espectro  =  20*np.log(cv2.magnitud(dft_shift[:,:,0],dft_shift[:,:,1]))

plt.subplot(121),plt.imshow(img,  cmap  =  'gris')  plt.title('  Imagen  de  
entrada'),  plt.xticks([]),  plt.yticks([])  plt.subplot(122) ,plt.imshow(magnitud_espectro,  
cmap  =  'gris')  plt.title('Magnitud  Espectro'),  plt.xticks([]),  plt.yticks([])  plt.show()

Nota:  también  puede  usar  cv2.cartToPolar()  que  devuelve  tanto  la  magnitud  como  la  fase  en  un  solo  disparo

Entonces,  ahora  tenemos  que  hacer  DFT  inversa.  En  la  sesión  anterior,  creamos  un  HPF,  esta  vez  veremos  cómo  eliminar  los  contenidos  de  
alta  frecuencia  en  la  imagen,  es  decir,  aplicamos  LPF  a  la  imagen.  De  hecho,  desenfoca  la  imagen.  Para  esto,  primero  creamos  una  máscara  
con  valor  alto  (1)  en  bajas  frecuencias,  es  decir,  pasamos  el  contenido  de  LF  y  0  en  la  región  de  HF.

filas,  cols  =  img.shape  cuervo,ccol  
=  filas/2 , columnas/2

128 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

#  crear  una  máscara  primero,  el  cuadrado  central  es  1,  el  resto  todos  los  ceros  mask  =  
np.zeros((rows,cols,2),np.uint8)  mask[crow­30:crow+30,  
ccol­30:ccol+30]  =  1

#  aplicar  máscara  y  DFT  inversa  fshift  =  
dft_shift*mask
f_ishift  =  np.fft.ifftshift(fshift)  img_back  =  cv2.idft(f_ishift)  
img_back  =  
cv2.magnitude(img_back[:,:,0],img_back[:,:,1])

plt.subplot(121),plt.imshow(img,  cmap  =  'gris')  plt.title('  Imagen  de  
entrada'),  plt.xticks([]),  plt.yticks([])  plt.subplot(122) ,plt.imshow(img_back,  cmap  =  'gris')  
plt.title('Espectro  de  magnitud'),  plt.xticks([]),  plt.yticks([])  plt.show()

Vea  el  resultado:

Nota:  Como  de  costumbre,  las  funciones  de  OpenCV  cv2.dft()  y  cv2.idft()  son  más  rápidas  que  las  contrapartes  de  Numpy.  Pero  las  funciones  de  Numpy  son  
más  fáciles  de  usar.  Para  obtener  más  detalles  sobre  los  problemas  de  rendimiento,  consulte  la  sección  a  continuación.

Optimización  del  rendimiento  de  DFT

El  rendimiento  del  cálculo  de  DFT  es  mejor  para  algunos  tamaños  de  matriz.  Es  más  rápido  cuando  el  tamaño  de  la  matriz  es  potencia  de  
dos.  Las  matrices  cuyo  tamaño  es  un  producto  de  2,  3  y  5  también  se  procesan  de  manera  bastante  eficiente.  Entonces,  si  le  preocupa  el  
rendimiento  de  su  código,  puede  modificar  el  tamaño  de  la  matriz  a  cualquier  tamaño  óptimo  (rellenando  con  ceros)  antes  de  encontrar  DFT.  
Para  OpenCV,  debe  rellenar  manualmente  los  ceros.  Pero  para  Numpy,  especifica  el  nuevo  tamaño  del  cálculo  de  FFT,  y  automáticamente  
rellenará  los  ceros  por  usted.

Entonces,  ¿cómo  encontramos  este  tamaño  óptimo?  OpenCV  proporciona  una  función,  cv2.getOptimalDFTSize()  para  esto.  Es  aplicable  
tanto  a  cv2.dft()  como  a  np.fft.fft2().  Verifiquemos  su  rendimiento  usando  el  comando  mágico  de  IPython  %timeit.

En  [16]:  img  =  cv2.imread('messi5.jpg',0)
En  [17]:  filas,columnas  =  img.forma  En  [18]:  
imprimir  filas,columnas
342  548

En  [19]:  nrows  =  cv2.getOptimalDFTSize(filas)
En  [20]:  ncols  =  cv2.getOptimalDFTSize(cols)
En  [21]:  imprimir  nrows,  ncols  360  576

1.4.  Procesamiento  de  imágenes  en  OpenCV 129
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Mira,  el  tamaño  (342,548)  se  modifica  a  (360,  576).  Ahora  rellenémoslo  con  ceros  (para  OpenCV)  y  encontremos  su  rendimiento  de  
cálculo  DFT.  Puede  hacerlo  creando  una  nueva  matriz  de  ceros  grandes  y  copiando  los  datos  en  ella,  o  usando  cv2.copyMakeBorder().

nimg  =  np.zeros((nrows,ncols))  nimg[:rows,:cols]  
=  img

O:

derecha  =  ncols  ­  cols  bottom  
=  nrows  ­  filas
bordertype  =  cv2.BORDER_CONSTANT  #solo  para  evitar  la  separación  de  líneas  en  el  archivo  PDF  nimg  =  
cv2.copyMakeBorder(img,0,bottom,0,right,bordertype,  value  =  0)

Ahora  calculamos  la  comparación  de  rendimiento  DFT  de  la  función  Numpy:

En  [22]:  %timeit  fft1  =  np.fft.fft2(img)  10  bucles,  lo  mejor  de  3:  
40,9  ms  por  bucle  En  [23]:  %timeit  fft2  =  np.fft.fft2(img,
[nrows,ncols] )  100  bucles,  lo  mejor  de  3:  10,4  ms  por  bucle

Muestra  una  aceleración  de  4x.  Ahora  intentaremos  lo  mismo  con  las  funciones  de  OpenCV.

En  [24]:  %timeit  dft1=  cv2.dft(np.float32(img),flags=cv2.DFT_COMPLEX_OUTPUT)  100  bucles,  lo  mejor  de  3:  13,5  ms  
por  bucle  En  [27]:  %timeit  dft2=  
cv2.dft( np.float32(nimg),flags=cv2.DFT_COMPLEX_OUTPUT)  100  bucles,  lo  mejor  de  3:  3,11  ms  por  bucle

También  muestra  una  aceleración  de  4x.  También  puede  ver  que  las  funciones  de  OpenCV  son  alrededor  de  3  veces  más  rápidas  que  las  funciones  de  
Numpy.  Esto  también  se  puede  probar  para  FFT  inversa,  y  eso  se  deja  como  ejercicio  para  usted.

¿Por  qué  Laplacian  es  un  filtro  de  paso  alto?

Se  hizo  una  pregunta  similar  en  un  foro.  La  pregunta  es,  ¿por  qué  Laplacian  es  un  filtro  de  paso  alto?  ¿Por  qué  Sobel  es  una  HPF?  etc.  
Y  la  primera  respuesta  que  se  le  dio  fue  en  términos  de  la  Transformada  de  Fourier.  Simplemente  tome  la  transformada  de  Fourier  de  
Laplacian  para  un  tamaño  mayor  de  FFT.  Analízalo:

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

#  filtro  promedio  simple  sin  parámetro  de  escala  mean_filter  =  np.ones((3,3))

#  creando  un  filtro  guassiano  x  =  
cv2.getGaussianKernel(5,10)  gaussian  =  x*xT

#  diferentes  filtros  de  detección  de  bordes  #  scharr  en  
dirección  x  scharr  =  np.array([[­3,  0,  
3],  [­10,0,10],  [­3,  0,  3]])  #  sobel  en  x  dirección

sobel_x=  np.matriz([[­1,  0,  1],  [­2,  0,  2],  [­1,  0,  
1]])

130 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

#  sobel  en  dirección  y  sobel_y=  
np.array([[­1,­2,­1],  [0,  0,  0],  [1,  2,  1]])

#  laplacian  
laplacian=np.array([[0,  1,  0],  [1,­4,  1],  [0,  1,  0]])

filtros  =  [filtro_medio,  gaussiano,  laplaciano,  sobel_x,  sobel_y,  scharr]  nombre_filtro  =  ['filtro_medio',  
'gaussiano','laplaciano',  'sobel_x',  \  'sobel_y',  'scharr_x']

fft_filters  =  [np.fft.fft2(x)  para  x  en  filtros]  fft_shift  =  [np.fft.fftshift(y)  para  y  
en  fft_filters]  mag_spectrum  =  [np.log(np.abs(z)+1)  para  z  en  fft_shift]

para  i  en  xrange(6):  
plt.subplot(2,3,i+1),plt.imshow(mag_spectrum[i],cmap  =  'gray')  plt.title(filter_name[i]),  plt.xticks( []),  
plt.yticks([])

plt.mostrar()

Vea  el  resultado:

En  la  imagen,  puede  ver  qué  región  de  frecuencia  bloquea  cada  kernel  y  qué  región  pasa.  A  partir  de  esa  información,  podemos  decir  por  
qué  cada  kernel  es  un  HPF  o  un  LPF

1.4.  Procesamiento  de  imágenes  en  OpenCV 131
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

1.  Una  explicación  intuitiva  de  la  teoría  de  Fourier  por  Steven  Lehar

2.  Transformada  de  Fourier  en  HIPR

3.  ¿Qué  denota  el  dominio  de  la  frecuencia  en  el  caso  de  las  imágenes?

Ejercicios

Comparación  de  plantillas

Objetivos

En  este  capítulo,  aprenderá

•  Para  buscar  objetos  en  una  imagen  mediante  Coincidencia  de  plantillas

•  Verá  estas  funciones:  cv2.matchTemplate(),  cv2.minMaxLoc()

Teoría

Coincidencia  de  plantillas  es  un  método  para  buscar  y  encontrar  la  ubicación  de  una  imagen  de  plantilla  en  una  imagen  más  grande.  OpenCV  
viene  con  una  función  cv2.matchTemplate()  para  este  propósito.  Simplemente  desliza  la  imagen  de  la  plantilla  sobre  la  imagen  de  entrada  (como  
en  la  convolución  2D)  y  compara  la  plantilla  y  el  parche  de  la  imagen  de  entrada  debajo  de  la  imagen  de  la  plantilla.  Varios  métodos  de  
comparación  están  implementados  en  OpenCV.  (Puede  consultar  los  documentos  para  obtener  más  detalles).  Devuelve  una  imagen  en  escala  
de  grises,  donde  cada  píxel  indica  cuánto  coincide  la  vecindad  de  ese  píxel  con  la  plantilla.

Si  la  imagen  de  entrada  tiene  un  tamaño  (ancho  x  alto)  y  la  imagen  de  la  plantilla  tiene  un  tamaño  (ancho  x  alto),  la  imagen  de  salida  tendrá  un  tamaño  de  (ancho­ancho+1,  alto­alto+1).

Una  vez  que  obtuvo  el  resultado,  puede  usar  la  función  cv2.minMaxLoc()  para  encontrar  dónde  está  el  valor  máximo/mínimo.  Tómelo  como  la  
esquina  superior  izquierda  del  rectángulo  y  tome  (w,h)  como  ancho  y  alto  del  rectángulo.  Ese  rectángulo  es  su  región  de  plantilla.

Nota:  si  utiliza  cv2.TM_SQDIFF  como  método  de  comparación,  el  valor  mínimo  proporciona  la  mejor  coincidencia.

Coincidencia  de  plantillas  en  OpenCV

Aquí,  como  ejemplo,  buscaremos  la  cara  de  Messi  en  su  foto.  Así  que  creé  una  plantilla  de  la  siguiente  manera:

Probaremos  todos  los  métodos  de  comparación  para  que  podamos  ver  cómo  se  ven  sus  resultados:

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('messi5.jpg',0)  img2  =  img.copia()  
plantilla  =  
cv2.imread('plantilla.jpg',0)

132 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

w,  h  =  plantilla.forma[::­1]

#  Los  6  métodos  para  comparar  en  una  lista  de  métodos  =  
['cv2.TM_CCOEFF',  'cv2.TM_CCOEFF_NORMED',  'cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED',  'cv2.TM_SQDIFF',  'cv2.TM_SQDIFF_NORMED']

para  metanfetamina  en  métodos:

img  =  img2.copy()  método  
=  eval(meth)

#  Aplicar  plantilla  Coincidencia  res  =  
cv2.matchTemplate(img,plantilla,método)  min_val,  max_val,  min_loc,  
max_loc  =  cv2.minMaxLoc(res)

#  Si  el  método  es  TM_SQDIFF  o  TM_SQDIFF_NORMED,  tome  el  método  mínimo  si  en  
[cv2.TM_SQDIFF,  cv2.TM_SQDIFF_NORMED]:  top_left  =  min_loc  else:

top_left  =  max_loc
abajo_derecha  =  (arriba_izquierda[0]  +  w,  arriba_izquierda[1]  +  h)

cv2.rectangle(img,arriba_izquierda,  abajo_derecha,  255,  2)

plt.subplot(121),plt.imshow(res,cmap  =  'gray')  plt.title('  Resultado  coincidente  
'),  plt.xticks([]),  plt.yticks([])  plt.subplot(122) ,plt.imshow(img,cmap  =  'gray')  plt.title('  Punto  detectado  
'),  plt.xticks([]),  plt.yticks([])  plt.suptitle(meth)

plt.mostrar()

Vea  los  resultados  a  continuación:

•  cv2.TM_CCOEFF

•  cv2.TM_CCOEFF_NORMED

1.4.  Procesamiento  de  imágenes  en  OpenCV 133
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

•  cv2.TM_CCORR

•  cv2.TM_CCORR_NORMED

•  cv2.TM_SQDIFF

134 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

•  cv2.TM_SQDIFF_NORMED

Puede  ver  que  el  resultado  usando  cv2.TM_CCORR  no  es  tan  bueno  como  esperábamos.

Coincidencia  de  plantillas  con  varios  objetos

En  la  sección  anterior,  buscamos  la  imagen  de  la  cara  de  Messi,  que  aparece  solo  una  vez  en  la  imagen.  Suponga  que  está  buscando  
un  objeto  que  tiene  múltiples  ocurrencias,  cv2.minMaxLoc()  no  le  dará  todas  las  ubicaciones.  En  ese  caso,  utilizaremos  el  umbral.  
Entonces,  en  este  ejemplo,  usaremos  una  captura  de  pantalla  del  famoso  juego  Mario  y  encontraremos  las  monedas  en  él.

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img_rgb  =  cv2.imread('mario.png')  img_gray  =  
cv2.cvtColor(img_rgb,  cv2.COLOR_BGR2GRAY)  template  =  
cv2.imread('mario_coin.png',0)  w,  h  =  template.shape[::­1 ]

res  =  cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)  umbral  =  0,8

1.4.  Procesamiento  de  imágenes  en  OpenCV 135
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

loc  =  np.where(res  >=  umbral)  para  pt  en  
zip(*loc[::­1]):
cv2.rectangle(img_rgb,  pt,  (pt[0]  +  w,  pt[1]  +  h),  (0,0,255),  2)

cv2.imwrite('res.png',img_rgb)

Resultado:

Recursos  adicionales

Ejercicios

Transformación  de  línea  de  Hough

Meta

En  este  capítulo,

•  Comprenderemos  el  concepto  de  Transformada  de  Hough.

•  Veremos  cómo  usarlo  para  detectar  líneas  en  una  imagen.

•  Veremos  las  siguientes  funciones:  cv2.HoughLines(),  cv2.HoughLinesP()

Teoría

Hough  Transform  es  una  técnica  popular  para  detectar  cualquier  forma,  si  puede  representar  esa  forma  en  forma  matemática.  Puede  
detectar  la  forma  incluso  si  está  rota  o  distorsionada  un  poco.  Veremos  cómo  funciona  para  una  línea.

Una  recta  se  puede  representar  como  =  +  o  en  forma  paramétrica,  como  =  cos  +  sin  donde  es  la  distancia  perpendicular  desde  el  origen  
hasta  la  recta,  y  es  el  ángulo  formado  por  esta  recta  perpendicular  y  el  eje  horizontal  medido  en  sentido  contrario  a  las  agujas  del  reloj  
(esa  dirección  varía  sobre  cómo  representas  el  sistema  de  coordenadas.  Esta  representación  se  usa  en  OpenCV).  Compruebe  la  
imagen  de  abajo:

136 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Entonces,  si  la  línea  pasa  por  debajo  del  origen,  tendrá  un  rho  positivo  y  un  ángulo  menor  de  180.  Si  pasa  por  encima  del  origen,  en  lugar  de  
tomar  un  ángulo  mayor  de  180,  se  toma  un  ángulo  menor  de  180  y  rho  se  toma  negativo.  Cualquier  línea  vertical  tendrá  0  grados  y  las  líneas  
horizontales  tendrán  90  grados.

Ahora  veamos  cómo  funciona  Hough  Transform  para  las  líneas.  Cualquier  línea  se  puede  representar  en  estos  dos  términos,  ( , ).  Entonces,  
primero  crea  una  matriz  o  acumulador  2D  (para  contener  valores  de  dos  parámetros)  y  se  establece  en  0  inicialmente.  Deje  que  las  filas  
indiquen  y  las  columnas   .  El  tamaño  de  la  matriz  depende  de  la  precisión  que  necesite.  Supongamos  que  desea  la  precisión  de  los  
indiquen  que  sea  1  grado,  necesita  180  columnas.   , ángulos,  la  distancia  máxima  posible  es  la  longitud  diagonal  de  la  imagen.  Entonces
Para  obtener  una  precisión  de  un  píxel,  el  número  de  filas  puede  ser  la  longitud  diagonal  de  la  imagen.

Considere  una  imagen  de  100x100  con  una  línea  horizontal  en  el  medio.  Toma  el  primer  punto  de  la  línea.  Conoces  sus  valores  (x,  y).  Ahora  
en  la  ecuación  de  la  línea,  pon  los  valores  =  0,  1,  2, ....,  180  y  comprueba  lo  que  obtienes.  Por  cada  par  ( , ),  incrementas  el  valor  en  uno  en  
nuestro  acumulador  en  sus  celdas  correspondientes  ( , ).  Así  que  ahora  en  el  acumulador,  la  celda  (50,90)  =  1  junto  con  algunas  otras  celdas.

Ahora  toma  el  segundo  punto  de  la  línea.  Haz  lo  mismo  que  arriba.  Incrementa  los  valores  en  las  celdas  correspondientes  a  ( , )  que  obtuviste.  
Esta  vez,  la  celda  (50,90)  =  2.  Lo  que  realmente  haces  es  votar  los  valores  ( , ).  Continúa  este  proceso  para  cada  punto  de  la  línea.  En  cada  
punto,  la  celda  (50,90)  se  incrementará  o  votará  a  favor,  mientras  que  otras  celdas  pueden  o  no  votarse  a  favor.  Así,  al  final,  la  celda  (50,90)  
tendrá  el  máximo  de  votos.  Entonces,  si  busca  en  el  acumulador  el  máximo  de  votos,  obtiene  el  valor  (50,90)  que  dice  que  hay  una  línea  en  
esta  imagen  a  una  distancia  de  50  desde  el  origen  y  en  un  ángulo  de  90  grados.  Se  muestra  bien  en  la  siguiente  animación  (Imagen  cortesía:  
Amos  Storkey) )

Así  es  como  funciona  Hough  transform  for  lines.  Es  simple,  y  puede  ser  que  puedas  implementarlo  usando  Numpy  por  tu  cuenta.  A  
continuación  se  muestra  una  imagen  que  muestra  el  acumulador.  Los  puntos  brillantes  en  algunos  lugares  indican  que  son  los  parámetros  
de  posibles  líneas  en  la  imagen.  (Imagen  cortesía:  Wikipedia )

Transformada  de  Hough  en  OpenCV

Todo  lo  explicado  anteriormente  está  encapsulado  en  la  función  OpenCV,  cv2.HoughLines().  Simplemente  devuelve  una  matriz  de  valores  
( , ).  se  mide  en  píxeles  y  se  mide  en  radianes.  El  primer  parámetro,  la  imagen  de  entrada  debe  ser  una  imagen  binaria,  por  lo  tanto,  aplique  
el  umbral  o  use  la  detección  de  bordes  astutos  antes  de  encontrar  la  aplicación  de  la  transformación  Hough.  Los  parámetros  segundo  y  
tercero  son  y  precisiones  respectivamente.  El  cuarto  argumento  es  el  umbral,  lo  que  significa  el  voto  mínimo  que  debe  obtener  para  que  se  
considere  como  una  línea.  Recuerde,  el  número  de  votos  depende  del  número  de  puntos  en  la  línea.  Por  lo  tanto,  representa  la  longitud  
mínima  de  línea  que  debe  detectarse.

importar  cv2  
importar  numpy  como  np

1.4.  Procesamiento  de  imágenes  en  OpenCV 137
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

img  =  cv2.imread('dave.jpg')  gris  =  
cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)  bordes  =  
cv2.Canny(gray,50,150,apertureSize  =  3)

líneas  =  cv2.HoughLines(bordes,1,np.pi/180,200)  para  rho,theta  en  
líneas[0]:  a  =  np.cos(theta)  b  =  
np.sin(theta)  x0  =  a*rho

y0  =  b*rho  x1  =  
int(x0  +  1000*(­b))  y1  =  int(y0  +  
1000*(a))  x2  =  int(x0  ­  1000*(­b))  y2  
=  int(y0  ­  1000  *(a))

cv2.línea(img,(x1,y1),(x2,y2),(0,0,255),2)

cv2.imwrite('houghlines3.jpg',img)

Compruebe  los  resultados  a  continuación:

138 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Transformada  probabilística  de  Hough

En  la  transformada  de  Hough,  puede  ver  que  incluso  para  una  línea  con  dos  argumentos,  se  necesitan  muchos  cálculos.  
Probabilistic  Hough  Transform  es  una  optimización  de  Hough  Transform  que  vimos.  No  tiene  en  cuenta  todos  los  puntos,  sino  que  
toma  solo  un  subconjunto  aleatorio  de  puntos  y  eso  es  suficiente  para  la  detección  de  líneas.  Solo  tenemos  que  disminuir  el  umbral.  
Vea  la  imagen  a  continuación  que  compara  la  Transformada  de  Hough  y  la  Transformada  de  Hough  probabilística  en  el  espacio  de  Hough.
(Imagen  cortesía:  página  de  inicio  de  Franck  Bettinger

1.4.  Procesamiento  de  imágenes  en  OpenCV 139
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

La  implementación  de  OpenCV  se  basa  en  la  detección  robusta  de  líneas  utilizando  la  transformada  de  Hough  probabilística  progresiva  de  Matas

•  minLineLength  ­  Longitud  mínima  de  la  línea.  Los  segmentos  de  línea  más  cortos  que  esto  son  rechazados.

•  maxLineGap :  espacio  máximo  permitido  entre  segmentos  de  línea  para  tratarlos  como  una  sola  línea.

Lo  mejor  es  que  devuelve  directamente  los  dos  extremos  de  las  líneas.  En  el  caso  anterior,  solo  obtuvo  los  parámetros  de  las  líneas  y  tuvo  
que  encontrar  todos  los  puntos.  Aquí,  todo  es  directo  y  simple.

140 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

importar  cv2  
importar  numpy  como  np

img  =  cv2.imread('dave.jpg')  gris  =  
cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)  bordes  =  
cv2.Canny(gray,50,150,apertureSize  =  3)  minLineLength  =  100  
maxLineGap  =  10  líneas  =  

cv2.HoughLinesP( bordes,1,np.pi/180,100,minLineLength,maxLineGap)  para  x1,y1,x2,y2  en  líneas[0]:  
cv2.line(img,(x1,y1),(x2,y2),(0,255,0 ),2)

cv2.imwrite('houghlines5.jpg',img)

Vea  los  resultados  a  continuación:

1.4.  Procesamiento  de  imágenes  en  OpenCV 141
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

1.  Transformada  de  Hough  en  Wikipedia

Ejercicios

Transformación  del  círculo  de  Hough

Meta

En  este  capítulo,

•  Aprenderemos  a  usar  la  Transformada  de  Hough  para  encontrar  círculos  en  una  imagen.

•  Veremos  estas  funciones:  cv2.HoughCircles()

Teoría

2 2 = 2
Un  círculo  se  representa  matemáticamente  como  ( −  +  ( −  donde  
) ( )  es  el  centro  del  
)círculo   ,
y  es  el  radio  del  círculo.  
A  partir  de  la  
ecuación,  podemos  ver  que  tenemos  3  parámetros,  por  lo  que  necesitamos  un  acumulador  3D  para  la  transformación  Hough,  lo  que  
sería  muy  ineficaz  Por  lo  tanto,  OpenCV  utiliza  un  método  más  complicado,  el  Método  de  gradiente  de  Hough ,  que  utiliza  la  información  
de  gradiente  de  los  bordes.

La  función  que  usamos  aquí  es  cv2.HoughCircles().  Tiene  muchos  argumentos  que  están  bien  explicados  en  la  documentación.  Así  
que  vamos  directamente  al  código.

importar  cv2  
importar  numpy  como  np

img  =  cv2.imread('opencv_logo.png',0)  img  =  cv2.medianBlur(img,5)  
cimg  =  cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)

círculos  =  cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,20,  
param1=50,param2=30,minRadius=0,maxRadius=0)

círculos  =  np.uint16(np.alrededor(círculos))  para  i  en  círculos[0,:]:

#  dibujar  el  círculo  exterior
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)  #  dibujar  el  centro  del  círculo

cv2.círculo(cimg,(i[0],i[1]),2,(0,0,255),3)

cv2.imshow('  círculos  detectados',cimg)  cv2.waitKey(0)  
cv2.destroyAllWindows()

El  resultado  se  muestra  a  continuación:

142 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

Ejercicios

Segmentación  de  imágenes  con  algoritmo  Watershed

Meta

En  este  capítulo,

•  Aprenderemos  a  usar  la  segmentación  de  imágenes  basada  en  marcadores  usando  el  algoritmo  de  cuencas  hidrográficas

•  Veremos:  cv2.watershed()

Teoría

Cualquier  imagen  en  escala  de  grises  se  puede  ver  como  una  superficie  topográfica  donde  la  alta  intensidad  denota  picos  y  colinas,  mientras  
que  la  baja  intensidad  denota  valles.  Empiezas  llenando  cada  valle  aislado  (mínimo  local)  con  agua  de  diferentes  colores  (etiquetas).
A  medida  que  el  agua  sube,  dependiendo  de  los  picos  (gradientes)  cercanos,  el  agua  de  diferentes  valles,  obviamente  con  diferentes  colores,  
comenzará  a  fusionarse.  Para  evitar  eso,  construye  barreras  en  los  lugares  donde  el  agua  se  fusiona.  Continúas  el  trabajo  de  llenar  de  agua  
y  construir  barreras  hasta  que  todos  los  picos  estén  bajo  el  agua.  Luego,  las  barreras  que  creaste  te  dan  el  resultado  de  la  segmentación.  
Esta  es  la  “filosofía”  detrás  de  la  línea  divisoria  de  aguas.  Puede  visitar  la  página  web  de  CMM  sobre  la  cuenca  para  entenderlo  con  la  ayuda  
de  algunas  animaciones.

Pero  este  enfoque  le  brinda  un  resultado  sobresegmentado  debido  al  ruido  o  cualquier  otra  irregularidad  en  la  imagen.  Entonces,  OpenCV  
implementó  un  algoritmo  de  cuenca  hidrográfica  basado  en  marcadores  en  el  que  especifica  cuáles  son  todos  los  puntos  del  valle  que  se  
fusionarán  y  cuáles  no.  Es  una  segmentación  de  imágenes  interactiva.  Lo  que  hacemos  es  dar  diferentes  etiquetas  a  nuestro  objeto  que  conocemos.
Etiquetar  la  región  que  estamos  seguros  de  ser  el  primer  plano  u  objeto  con  un  color  (o  intensidad),  etiquetar  la  región  que  estamos  seguros  
de  ser  el  fondo  o  no  objeto  con  otro  color  y  finalmente  la  región  de  la  que  no  estamos  seguros  de  nada,  etiquételo  con  0.  Ese  es  nuestro  
marcador.  Luego  aplique  el  algoritmo  de  cuenca  hidrográfica.  Luego,  nuestro  marcador  se  actualizará  con  las  etiquetas  que  le  dimos,  y  los  
límites  de  los  objetos  tendrán  un  valor  de  ­1.

1.4.  Procesamiento  de  imágenes  en  OpenCV 143
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Código

A  continuación,  veremos  un  ejemplo  de  cómo  usar  la  Transformación  de  distancia  junto  con  la  línea  divisoria  de  aguas  para  segmentar  objetos  
que  se  tocan  entre  sí.

Considere  la  imagen  de  las  monedas  a  continuación,  las  monedas  se  tocan  entre  sí.  Incluso  si  lo  limita,  se  tocarán  entre  sí.

Empezamos  por  encontrar  una  estimación  aproximada  de  las  monedas.  Para  eso,  podemos  usar  la  binarización  de  Otsu.

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('monedas.png')  gris  =  
cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)  ret,  thresh  =  
cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

Resultado:

144 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Ahora  necesitamos  eliminar  cualquier  pequeño  ruido  blanco  en  la  imagen.  Para  eso  podemos  usar  la  apertura  morfológica.  Para  eliminar  
pequeños  agujeros  en  el  objeto,  podemos  usar  el  cierre  morfológico.  Entonces,  ahora  sabemos  con  certeza  que  la  región  cercana  al  centro  
de  los  objetos  está  en  primer  plano  y  la  región  muy  alejada  del  objeto  está  en  segundo  plano.  La  única  región  de  la  que  no  estamos  seguros  
es  la  región  límite  de  las  monedas.

Entonces  necesitamos  extraer  el  área  que  estamos  seguros  de  que  son  monedas.  La  erosión  elimina  los  píxeles  del  límite.  Entonces,  lo  que  
quede,  podemos  estar  seguros  de  que  es  moneda.  Eso  funcionaría  si  los  objetos  no  se  tocaran  entre  sí.  Pero  dado  que  se  tocan  entre  sí,  
otra  buena  opción  sería  encontrar  la  transformación  de  distancia  y  aplicar  un  umbral  adecuado.  A  continuación,  debemos  encontrar  el  área  
en  la  que  estamos  seguros  de  que  no  son  monedas.  Para  eso,  dilatamos  el  resultado.  La  dilatación  aumenta  el  límite  del  objeto  al  fondo.  De  
esta  manera,  podemos  asegurarnos  de  que  cualquier  región  en  el  fondo  que  resulte  sea  realmente  un  fondo,  ya  que  se  elimina  la  región  
límite.  Vea  la  imagen  a  continuación.

1.4.  Procesamiento  de  imágenes  en  OpenCV 145
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Las  regiones  restantes  son  aquellas  de  las  que  no  tenemos  idea,  ya  sean  monedas  o  fondo.  El  algoritmo  Watershed  debería  encontrarlo.  
Estas  áreas  normalmente  se  encuentran  alrededor  de  los  límites  de  las  monedas  donde  se  encuentran  el  primer  plano  y  el  fondo  (o  
incluso  se  encuentran  dos  monedas  diferentes).  Lo  llamamos  frontera.  Se  puede  obtener  restando  el  área  sure_fg  del  área  sure_bg.

#  eliminación  de  ruido
kernel  =  np.ones((3,3),np.uint8)  apertura  =  
cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel,  iteraciones  =  2)

#  sure  background  area  sure_bg  
=  cv2.dilate(opening,kernel,iterations=3)

#  Encontrar  un  área  de  primer  plano  segura  
dist_transform  =  cv2.distanceTransform(opening,cv2.DIST_L2,5)  ret,  sure_fg  =  
cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)

#  Encontrar  región  desconocida  
sure_fg  =  np.uint8(sure_fg)  unknown  =  
cv2.subtract(sure_bg,sure_fg)

Vea  el  resultado.  En  la  imagen  umbralizada,  tenemos  algunas  regiones  de  monedas  de  las  que  estamos  seguros  y  ahora  están  separadas.  
(En  algunos  casos,  es  posible  que  solo  le  interese  la  segmentación  del  primer  plano,  no  la  separación  de  los  objetos  que  se  tocan  entre  
sí.  En  ese  caso,  no  necesita  usar  la  transformación  de  distancia,  solo  la  erosión  es  suficiente.  La  erosión  es  solo  otro  método  para  extraer  
un  área  de  primer  plano  segura,  eso  es  todo.)

146 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Ahora  sabemos  con  certeza  cuáles  son  la  región  de  las  monedas,  cuáles  son  el  fondo  y  todo.  Entonces  creamos  un  marcador  (es  una  matriz  del  
mismo  tamaño  que  la  imagen  original,  pero  con  tipo  de  datos  int32)  y  etiquetamos  las  regiones  dentro  de  él.  Las  regiones  que  sabemos  con  
seguridad  (ya  sea  en  primer  plano  o  en  segundo  plano)  están  etiquetadas  con  números  enteros  positivos,  pero  con  números  enteros  diferentes,  y  el  
área  que  no  sabemos  con  certeza  se  deja  como  cero.  Para  esto  usamos  cv2.connectedComponents().  Etiqueta  el  fondo  de  la  imagen  con  0,  luego  
otros  objetos  se  etiquetan  con  números  enteros  a  partir  de  1.

Pero  sabemos  que  si  el  fondo  está  marcado  con  0,  la  cuenca  lo  considerará  como  un  área  desconocida.  Entonces  queremos  marcarlo  con  un  entero  
diferente.  En  su  lugar,  marcaremos  la  región  desconocida,  definida  por  desconocido,  con  0.

#  Marcador  etiquetado  ret,  
marcadores  =  cv2.connectedComponents(sure_fg)

#  Agregue  uno  a  todas  las  etiquetas  para  que  el  fondo  seguro  no  sea  0,  sino  1  marcadores  =  
marcadores  +  1

#  Ahora,  marca  la  región  de  desconocido  con  cero  
marcadores[desconocido==255]  =  0

Vea  el  resultado  que  se  muestra  en  el  mapa  de  colores  JET.  La  región  azul  oscuro  muestra  una  región  desconocida.  Las  monedas  seguras  están  
coloreadas  con  diferentes  valores.  El  área  restante  que  es  un  fondo  seguro  se  muestra  en  azul  más  claro  en  comparación  con  la  región  desconocida.

1.4.  Procesamiento  de  imágenes  en  OpenCV 147
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Ahora  nuestro  marcador  está  listo.  Es  hora  del  paso  final,  aplicar  la  cuenca  hidrográfica.  Luego  se  modificará  la  imagen  del  marcador.  La  región  
límite  se  marcará  con  ­1.

marcadores  =  cv2.watershed(img,marcadores)  
img[marcadores  ==  ­1]  =  [255,0,0]

Vea  el  resultado  a  continuación.  Para  algunas  monedas,  la  región  donde  se  tocan  está  segmentada  correctamente  y  para  algunas  no  lo  están.

148 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

1.  Página  del  CMM  sobre  Transformación  de  Cuencas  Hidrográficas

Ejercicios

1.  Las  muestras  de  OpenCV  tienen  una  muestra  interactiva  sobre  la  segmentación  de  cuencas  hidrográficas,  watershed.py.  Ejecútalo,  disfrútalo,  luego
aprenderlo.

Extracción  interactiva  de  primer  plano  utilizando  el  algoritmo  GrabCut

Meta

En  este  capítulo

•  Veremos  el  algoritmo  GrabCut  para  extraer  el  primer  plano  en  las  imágenes

•  Crearemos  una  aplicación  interactiva  para  esto.

Teoría

El  algoritmo  GrabCut  fue  diseñado  por  Carsten  Rother,  Vladimir  Kolmogorov  y  Andrew  Blake  de  Microsoft  Research  Cambridge,  Reino  Unido.  en  su  
.
artículo,  "GrabCut":  extracción  interactiva  de  primer  plano  utilizando  cortes  de  gráfico  iterados  Se  necesitaba  un  algoritmo  para  la  extracción  
de  primer  
plano  con  una  interacción  mínima  del  usuario,  y  el  resultado  fue  GrabCut.

¿Cómo  funciona  desde  el  punto  de  vista  del  usuario?  Inicialmente,  el  usuario  dibuja  un  rectángulo  alrededor  de  la  región  de  primer  plano  (la  región  de  
primer  plano  debe  estar  completamente  dentro  del  rectángulo).  Luego,  el  algoritmo  lo  segmenta  iterativamente  para  obtener  el  mejor  resultado.  Hecho.
Pero  en  algunos  casos,  la  segmentación  no  estará  bien,  por  ejemplo,  puede  haber  marcado  alguna  región  de  primer  plano  como  fondo.

1.4.  Procesamiento  de  imágenes  en  OpenCV 149
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

y  viceversa.  En  ese  caso,  el  usuario  necesita  hacer  retoques  finos.  Simplemente  dé  algunos  trazos  en  las  imágenes  donde  haya  algunos  resultados  
defectuosos.  Strokes  básicamente  dice  "Oye,  esta  región  debería  estar  en  primer  plano,  la  marcaste  como  fondo,  corrígela  en  la  próxima  iteración"  o  
su  opuesto  para  el  fondo.  Luego,  en  la  siguiente  iteración,  obtendrá  mejores  resultados.

Vea  la  imagen  a  continuación.  El  primer  jugador  y  el  balón  de  fútbol  están  encerrados  en  un  rectángulo  azul.  Luego,  se  realizan  algunos  retoques  
finales  con  trazos  blancos  (que  denotan  el  primer  plano)  y  trazos  negros  (que  denotan  el  fondo).  Y  obtenemos  un  buen  resultado.

Entonces,  ¿qué  sucede  en  segundo  plano?

•  El  usuario  ingresa  el  rectángulo.  Todo  lo  que  esté  fuera  de  este  rectángulo  se  tomará  como  fondo  seguro  (esa  es  la  razón  por  la  que  se  mencionó  
antes  que  su  rectángulo  debe  incluir  todos  los  objetos).  Todo  lo  que  está  dentro  del  rectángulo  es  desconocido.  Del  mismo  modo,  cualquier  
entrada  del  usuario  que  especifique  el  primer  plano  y  el  fondo  se  considera  de  etiquetado  estricto,  lo  que  significa  que  no  cambiará  en  el  
proceso.

•  La  computadora  hace  un  etiquetado  inicial  dependiendo  de  los  datos  que  le  dimos.  Etiqueta  los  píxeles  de  primer  plano  y  de  fondo.
(o  etiquetas  duras)

•  Ahora  se  utiliza  un  modelo  de  mezcla  gaussiana  (GMM)  para  modelar  el  primer  plano  y  el  fondo.

•  Dependiendo  de  los  datos  que  proporcionamos,  GMM  aprende  y  crea  una  nueva  distribución  de  píxeles.  Es  decir,  los  píxeles  desconocidos  se  
etiquetan  como  primer  plano  probable  o  fondo  probable  según  su  relación  con  los  otros  píxeles  etiquetados  de  forma  rígida  en  términos  de  
estadísticas  de  color  (es  como  agrupar).

•  Se  construye  un  gráfico  a  partir  de  esta  distribución  de  píxeles.  Los  nodos  en  los  gráficos  son  píxeles.  Se  agregan  dos  nodos  adicionales,  el  
nodo  de  origen  y  el  nodo  de  receptor.  Cada  píxel  de  primer  plano  está  conectado  al  nodo  Fuente  y  cada  píxel  de  fondo  está  conectado  al  nodo  
Sumidero.

•  Los  pesos  de  los  bordes  que  conectan  los  píxeles  al  nodo  de  origen/nodo  final  se  definen  por  la  probabilidad  de  que  un  píxel  esté  en  primer  
plano/fondo.  Los  pesos  entre  los  píxeles  se  definen  por  la  información  del  borde  o  la  similitud  de  píxeles.
Si  hay  una  gran  diferencia  en  el  color  de  los  píxeles,  el  borde  entre  ellos  tendrá  un  peso  bajo.

•  Luego  se  usa  un  algoritmo  mincut  para  segmentar  el  gráfico.  Corta  el  gráfico  en  dos  nodos  fuente  y  nodo  sumidero  separados  con  una  función  
de  costo  mínimo.  La  función  de  costo  es  la  suma  de  todos  los  pesos  de  los  bordes  que  se  cortan.  Después  del  corte,  todos  los  píxeles  
conectados  al  nodo  Fuente  pasan  a  primer  plano  y  los  conectados  al  nodo  Sumidero  pasan  a  segundo  plano.

•  El  proceso  continúa  hasta  que  la  clasificación  converge.

Se  ilustra  en  la  imagen  de  abajo  (Imagen  cortesía:  http://www.cs.ru.ac.za/research/g02m1682/)

150 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Manifestación

Ahora  vamos  por  el  algoritmo  Grabcut  con  OpenCV.  OpenCV  tiene  la  función  cv2.grabCut()  para  esto.  Primero  veremos  sus  argumentos:

•  img  ­  Imagen  de  entrada

•  máscara:  es  una  imagen  de  máscara  donde  especificamos  qué  áreas  son  fondo,  primer  plano  o  probable  fondo/primer  plano,  etc.  Se  realiza  
mediante  las  siguientes  banderas,  cv2.GC_BGD,  cv2.GC_FGD,  cv2.GC_PR_BGD,  cv2.GC_PR_FGD,  o  simplemente  pase  0,1,2,3  a  la  imagen.

•  rect  ­  Son  las  coordenadas  de  un  rectángulo  que  incluye  el  objeto  de  primer  plano  en  el  formato  (x,y,w,h)

•  bdgModel,  fgdModel:  estas  son  matrices  utilizadas  por  el  algoritmo  internamente.  Simplemente  crea  dos  matrices  de  tipo  cero  np.float64  de  tamaño  
(1,65).

•  iterCount:  número  de  iteraciones  que  debe  ejecutar  el  algoritmo.

•  modo  ­  Debe  ser  cv2.GC_INIT_WITH_RECT  o  cv2.GC_INIT_WITH_MASK  o  combinados  que  de
decide  si  estamos  dibujando  un  rectángulo  o  trazos  finales  de  retoque.

Primero  veamos  con  el  modo  rectangular.  Cargamos  la  imagen,  creamos  una  imagen  de  máscara  similar.  Creamos  fgdModel  y  bgdModel.  Damos  los  
parámetros  del  rectángulo.  Todo  es  sencillo.  Deje  que  el  algoritmo  se  ejecute  durante  5  iteraciones.  El  modo  debe  ser  cv2.GC_INIT_WITH_RECT  ya  que  
estamos  usando  un  rectángulo.  Luego  ejecute  el  agarre.  Modifica  la  imagen  de  la  máscara.
En  la  nueva  imagen  de  máscara,  los  píxeles  se  marcarán  con  cuatro  banderas  que  denotan  fondo/primer  plano  como  se  especificó  anteriormente.  Entonces

1.4.  Procesamiento  de  imágenes  en  OpenCV 151
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

modificamos  la  máscara  de  modo  que  todos  los  píxeles  0  y  2  píxeles  se  ponen  a  0  (es  decir,  fondo)  y  todos  los  píxeles  1  y  3  píxeles  se  ponen  a  1  (es  
decir,  píxeles  de  primer  plano).  Ahora  nuestra  máscara  final  está  lista.  Simplemente  multiplíquelo  con  la  imagen  de  entrada  para  obtener  la  imagen  
segmentada.

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('messi5.jpg')  máscara  =  
np.zeros(img.forma[:2],np.uint8)

bgdModel  =  np.zeros((1,65),np.float64)  fgdModel  =  
np.zeros((1,65),np.float64)

rect  =  (50,50,450,290)  
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)

máscara2  =  np.where((máscara==2)|(máscara==0),0,1).astype('uint8')  img  =  
img*máscara2[:,:,np.nuevoeje]

plt.imshow(img),plt.colorbar(),plt.show()

Vea  los  resultados  a  continuación:

Vaya,  el  pelo  de  Messi  se  ha  ido.  ¿A  quién  le  gusta  Messi  sin  pelo?  Tenemos  que  traerlo  de  vuelta.  Así  que  le  daremos  un  buen  retoque  con  1  píxel  
(primer  plano  seguro).  Al  mismo  tiempo,  una  parte  del  terreno  ha  llegado  a  la  imagen  que  no  queremos,  y  también  un  logotipo.  Necesitamos  eliminarlos.  
Allí  le  damos  algún  retoque  de  0  píxeles  (fondo  seguro).  Entonces  modificamos  nuestra  máscara  resultante  en  el  caso  anterior  como  dijimos  ahora.

Lo  que  realmente  hice  es  que  abrí  la  imagen  de  entrada  en  la  aplicación  de  pintura  y  agregué  otra  capa  a  la  imagen.  Usando  la  herramienta  de  pincel  
en  la  pintura,  marqué  el  primer  plano  perdido  (pelo,  zapatos,  pelota,  etc.)  con  blanco  y  el  fondo  no  deseado  (como  logotipo,  suelo,  etc.)  con  negro  en  
esta  nueva  capa.  Luego  llenó  el  fondo  restante  con  gris.  Luego  cargó  esa  imagen  de  máscara  en  OpenCV,  la  imagen  de  máscara  original  editada  que  
obtuvimos  con  los  valores  correspondientes  en  la  imagen  de  máscara  recién  agregada.  Verifique  el  código  a  continuación:

152 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

#  newmask  es  la  imagen  de  máscara  que  etiqueté  manualmente  newmask  =  
cv2.imread('newmask.png',0)

#  donde  sea  que  esté  marcado  en  blanco  (seguro  en  primer  plano),  cambie  la  máscara  =  1  #  donde  sea  
que  esté  marcado  en  negro  (seguro  en  el  fondo),  cambie  la  máscara  =  0  máscara  [nueva  máscara  ==  0]  =  
0
máscara[nueva  máscara  ==  255]  =  1

máscara,  bgdModel,  fgdModel  =  cv2.grabCut(img,máscara,Ninguno,bgdModel,fgdModel,5,cv2.GC_INIT_
→CON_MASCARILLA)

máscara  =  np.where((máscara==2)|(máscara==0),0,1).astype('uint8')  img  =  
img*máscara[:,:,np.nuevoeje]  
plt.imshow(img ),plt.colorbar(),plt.show()

Vea  el  resultado  a  continuación:

Eso  es  todo.  Aquí,  en  lugar  de  inicializar  en  modo  rect,  puede  pasar  directamente  al  modo  de  máscara.  Simplemente  marque  el  área  del  
rectángulo  en  la  imagen  de  la  máscara  con  2  o  3  píxeles  (fondo/primer  plano  probable).  Luego  marque  nuestro  primer  plano  seguro  con  1  píxel  
como  lo  hicimos  en  el  segundo  ejemplo.  Luego  aplique  directamente  la  función  grabCut  con  el  modo  máscara.

Recursos  adicionales

Ejercicios

1.  Las  muestras  de  OpenCV  contienen  una  muestra  grabcut.py,  que  es  una  herramienta  interactiva  que  utiliza  grabcut.  Revisalo.  También
mira  este  video  de  youtube  sobre  cómo  usarlo.

2.  Aquí,  puede  convertir  esto  en  una  muestra  interactiva  dibujando  un  rectángulo  y  trazos  con  el  mouse,  crear  una  barra  de  seguimiento  
para  ajustar  el  ancho  del  trazo,  etc.

Detección  y  descripción  de  características

•  Comprensión  de  las  funciones

1.5.  Detección  y  descripción  de  características 153
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

¿Cuáles  son  las  características  principales  de  una  imagen?  ¿Cómo  nos  puede  ser  útil  encontrar  esas  
características?

•  Detección  de  esquina  Harris

Bien,  ¿las  esquinas  son  buenas  características?  Pero,  ¿cómo  los  encontramos?

•  Detector  de  esquinas  Shi­Tomasi  y  buenas  características  para  rastrear

Analizaremos  la  detección  de  esquinas  de  Shi­Tomasi

•  Introducción  a  SIFT  (Transformación  de  características  de  escala  invariable)

El  detector  de  esquina  Harris  no  es  lo  suficientemente  bueno  cuando  cambia  la  escala  de  la  imagen.
Lowe  desarrolló  un  método  innovador  para  encontrar  características  invariantes  de  escala  y  se  llama  
SIFT

•  Introducción  a  SURF  (funciones  robustas  aceleradas)

SIFT  es  realmente  bueno,  pero  no  lo  suficientemente  rápido,  por  lo  que  a  la  gente  se  le  ocurrió  una  
versión  acelerada  llamada  SURF.

•  Algoritmo  FAST  para  detección  de  esquinas

154 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Todos  los  métodos  de  detección  de  características  anteriores  son  buenos  de  alguna  manera.  Pero  no  
son  lo  suficientemente  rápidos  para  trabajar  en  aplicaciones  en  tiempo  real  como  SLAM.  Ahí  viene  el  
algoritmo  FAST,  que  es  realmente  “FAST”.

•  BRIEF  (Características  elementales  independientes  sólidas  binarias)

SIFT  utiliza  un  descriptor  de  características  con  128  números  de  punto  flotante.  Considere  miles  de  
tales  características.  Se  necesita  mucha  memoria  y  más  tiempo  para  hacer  coincidir.  Podemos  
comprimirlo  para  hacerlo  más  rápido.  Pero  todavía  tenemos  que  calcularlo  primero.  Viene  BRIEF,  
que  brinda  el  atajo  para  encontrar  descriptores  binarios  con  menos  memoria,  una  coincidencia  más  
rápida  y  una  tasa  de  reconocimiento  aún  más  alta.

•  ORB  (RÁPIDO  Orientado  y  BREVE  Girado)

SIFT  y  SURF  son  buenos  en  lo  que  hacen,  pero  ¿qué  sucede  si  tiene  que  pagar  unos  cuantos  dólares  
cada  año  para  usarlos  en  sus  aplicaciones?  ¡¡¡Sí,  están  patentados!!!  Para  resolver  ese  problema,  los  
desarrolladores  de  OpenCV  idearon  una  nueva  alternativa  "GRATUITA"  a  SIFT  &  SURF,  y  es  ORB.

•  Coincidencia  de  características

Sabemos  mucho  sobre  detectores  y  descriptores  de  características.  Es  hora  de  aprender  a  hacer  
coincidir  diferentes  descriptores.  OpenCV  proporciona  dos  técnicas,  el  comparador  de  fuerza  bruta  y  
el  comparador  basado  en  FLANN.

•  Coincidencia  de  características  +  Homografía  para  encontrar  objetos

Ahora  sabemos  acerca  de  la  coincidencia  de  características.  Combinémoslo  con  el  módulo  calib3d  
para  encontrar  objetos  en  una  imagen  compleja.

1.5.  Detección  y  descripción  de  características 155
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Características  de  comprensión

Meta

En  este  capítulo,  solo  intentaremos  comprender  qué  son  las  características,  por  qué  son  importantes,  por  qué  las  esquinas  son  importantes,  etc.

Explicación

La  mayoría  de  ustedes  habrán  jugado  a  los  juegos  de  rompecabezas.  Obtiene  muchas  piezas  pequeñas  de  imágenes,  donde  necesita  
ensamblarlas  correctamente  para  formar  una  gran  imagen  real.  La  pregunta  es,  ¿cómo  lo  haces?  ¿Qué  pasa  con  la  proyección  de  la  misma  
teoría  a  un  programa  de  computadora  para  que  la  computadora  pueda  jugar  rompecabezas?  Si  la  computadora  puede  jugar  rompecabezas,  
¿por  qué  no  podemos  darle  muchas  imágenes  de  la  vida  real  de  un  buen  paisaje  natural  a  la  computadora  y  decirle  que  una  todas  esas  
imágenes  en  una  sola  imagen  grande?  Si  la  computadora  puede  unir  varias  imágenes  naturales  a  una,  ¿qué  hay  de  dar  muchas  imágenes  de  
un  edificio  o  cualquier  estructura  y  decirle  a  la  computadora  que  cree  un  modelo  3D  a  partir  de  eso?

Bueno,  las  preguntas  y  las  imaginaciones  continúan.  ¿Pero  todo  depende  de  la  pregunta  más  básica?  ¿Cómo  juegas  a  los  rompecabezas?  
¿Cómo  se  organizan  muchas  piezas  de  imágenes  revueltas  en  una  sola  imagen  grande?  ¿Cómo  se  pueden  unir  muchas  imágenes  naturales  a  
una  sola  imagen?

La  respuesta  es  que  estamos  buscando  patrones  específicos  o  características  específicas  que  sean  únicas,  que  se  puedan  rastrear  fácilmente,  
que  se  puedan  comparar  fácilmente.  Si  buscamos  una  definición  de  tal  característica,  puede  que  nos  resulte  difícil  expresarla  con  palabras,  
pero  sabemos  cuáles  son.  Si  alguien  le  pide  que  señale  una  buena  característica  que  se  pueda  comparar  en  varias  imágenes,  puede  señalar  
una.  Por  eso,  incluso  los  niños  pequeños  pueden  simplemente  jugar  estos  juegos.  Buscamos  estas  características  en  una  imagen,  las  
encontramos,  encontramos  las  mismas  características  en  otras  imágenes,  las  alineamos.  Eso  es  todo.  (En  rompecabezas,  nos  fijamos  más  en  
la  continuidad  de  diferentes  imágenes).  Todas  estas  habilidades  están  presentes  en  nosotros  inherentemente.

Entonces,  nuestra  única  pregunta  básica  se  expande  a  más  en  número,  pero  se  vuelve  más  específica.  ¿Cuáles  son  estas  características?.  (La  
respuesta  también  debe  ser  comprensible  para  una  computadora).

Bueno,  es  difícil  decir  cómo  los  humanos  encuentran  estas  características.  Ya  está  programado  en  nuestro  cerebro.  Pero  si  miramos  
profundamente  en  algunas  imágenes  y  buscamos  diferentes  patrones,  encontraremos  algo  interesante.  Por  ejemplo,  tome  la  imagen  de  abajo:

156 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

La  imagen  es  muy  simple.  En  la  parte  superior  de  la  imagen,  se  proporcionan  seis  pequeños  parches  de  imagen.  La  pregunta  para  usted  es  encontrar  
la  ubicación  exacta  de  estos  parches  en  la  imagen  original.  ¿Cuántos  resultados  correctos  puedes  encontrar?

A  y  B  son  superficies  planas  y  están  distribuidas  en  una  gran  área.  Es  difícil  encontrar  la  ubicación  exacta  de  estos  parches.

C  y  D  son  mucho  más  simples.  Son  bordes  del  edificio.  Puede  encontrar  una  ubicación  aproximada,  pero  la  ubicación  exacta  sigue  siendo  difícil.  Es  
porque,  a  lo  largo  del  borde,  es  igual  en  todas  partes.  Normal  al  borde,  es  diferente.  Por  lo  tanto,  el  borde  es  una  característica  mucho  mejor  en  
comparación  con  el  área  plana,  pero  no  lo  suficientemente  bueno  (es  bueno  en  el  rompecabezas  para  comparar  la  continuidad  de  los  bordes).

Finalmente,  E  y  F  son  algunas  esquinas  del  edificio.  Y  se  pueden  descubrir  fácilmente.  Porque  en  las  esquinas,  donde  sea  que  muevas  este  parche,  
se  verá  diferente.  Así  que  pueden  ser  considerados  como  una  buena  característica.  Así  que  ahora  pasamos  a  una  imagen  más  simple  (y  ampliamente  
utilizada)  para  una  mejor  comprensión.

1.5.  Detección  y  descripción  de  características 157
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Al  igual  que  arriba,  el  parche  azul  es  un  área  plana  y  difícil  de  encontrar  y  rastrear.  Dondequiera  que  mueva  el  parche  azul,  se  ve  igual.  Para  
el  parche  negro,  es  un  borde.  Si  lo  mueve  en  dirección  vertical  (es  decir,  a  lo  largo  del  gradiente),  cambia.  Poner  a  lo  largo  del  borde  (paralelo  
al  borde),  se  ve  igual.  Y  para  el  parche  rojo,  es  una  esquina.  Dondequiera  que  muevas  el  parche,  se  ve  diferente,  significa  que  es  único.  
Básicamente,  las  esquinas  se  consideran  buenas  características  en  una  imagen.  (No  solo  las  esquinas,  en  algunos  casos  los  blobs  se  
consideran  buenas  características).

Así  que  ahora  respondimos  a  nuestra  pregunta,  "¿cuáles  son  estas  características?".  Pero  surge  la  siguiente  pregunta.  ¿Cómo  los  encontramos?  O  
¿cómo  encontramos  las  esquinas?.  Eso  también  lo  respondimos  de  una  manera  intuitiva,  es  decir,  busque  las  regiones  en  las  imágenes  que  tienen  
la  máxima  variación  cuando  se  mueven  (en  una  pequeña  cantidad)  en  todas  las  regiones  a  su  alrededor.  Esto  se  proyectaría  en  lenguaje  informático  
en  los  próximos  capítulos.  Entonces,  encontrar  estas  características  de  imagen  se  llama  Detección  de  características.

Entonces  encontramos  las  características  en  la  imagen  (supongamos  que  lo  hizo).  Una  vez  que  lo  encontraste,  deberías  encontrar  lo  mismo  
en  las  otras  imágenes.  ¿Qué  hacemos?  Tomamos  una  región  alrededor  de  la  característica,  la  explicamos  con  nuestras  propias  palabras,  
como  "la  parte  superior  es  el  cielo  azul,  la  parte  inferior  es  la  región  del  edificio,  en  ese  edificio  hay  algunos  vasos,  etc."  y  buscas  la  misma  
área  en  otras  imágenes.  Básicamente,  estás  describiendo  la  función.  De  manera  similar,  la  computadora  también  debe  describir  la  región  
alrededor  de  la  característica  para  que  pueda  encontrarla  en  otras  imágenes.  La  llamada  descripción  se  llama  Descripción  de  funciones.  Una  
vez  que  tenga  las  características  y  su  descripción,  puede  encontrar  las  mismas  características  en  todas  las  imágenes  y  alinearlas,  unirlas  o  
hacer  lo  que  quiera.

Entonces,  en  este  módulo,  estamos  buscando  diferentes  algoritmos  en  OpenCV  para  encontrar  características,  describirlas,  unirlas,  etc.

Recursos  adicionales

Ejercicios

Detección  de  esquina  Harris

Meta

En  este  capítulo,

•  Comprenderemos  los  conceptos  detrás  de  Harris  Corner  Detection.

•  Veremos  las  funciones:  cv2.cornerHarris(),  cv2.cornerSubPix()

158 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Teoría

En  el  último  capítulo,  vimos  que  las  esquinas  son  regiones  de  la  imagen  con  una  gran  variación  de  intensidad  en  todas  las  direcciones.  
Uno  de  los  primeros  intentos  de  encontrar  estas  esquinas  fue  realizado  por  Chris  Harris  y  Mike  Stephens  en  su  artículo  A  Combined  
Corner  and  Edge  Detector  en  1988,  por  lo  que  ahora  se  llama  Harris  Corner  Detector.  Llevó  esta  idea  simple  a  una  forma  matemática.  
Básicamente  encuentra  la  diferencia  de  intensidad  para  un  desplazamiento  de  ( , )  en  todas  las  direcciones.  Esto  se  expresa  como  
sigue:

2
( , )  =  ∑    ( , ) [ ( + , + )  −  ( , ) ]

,
función  de  ventana intensidad  cambiada intensidad

La  función  de  ventana  es  una  ventana  rectangular  o  una  ventana  gaussiana  que  otorga  pesos  a  los  píxeles  que  se  encuentran  debajo.

,detección  de  esquinas.  Eso  significa  que  tenemos  que  maximizar  el  segundo  término.
Tenemos  que  maximizar  esta  función  ( )  para  la  
Aplicando  la  Expansión  de  Taylor  a  la  ecuación  anterior  y  usando  algunos  pasos  matemáticos  (consulte  cualquier  libro  de  texto  estándar  que  
desee  para  una  derivación  completa),  obtenemos  la  ecuación  final  como:

( , )  ≈  [ ]
[ ]

dónde

=  ∑ ( , )
[ ]
,

Aquí,  y  son  derivadas  de  imágenes  en  las  direcciones  x  e  y  respectivamente.  (Se  puede  encontrar  fácilmente  usando  cv2.Sobel()).

Luego  viene  la  parte  principal.  Luego  de  esto,  crearon  una  partitura,  básicamente  una  ecuación,  que  determinará  si  una  ventana  
puede  contener  una  esquina  o  no.

=  ( )  −  ( ( ))2

dónde

• ( )   1  2

( = )  = 1  +  2

• 1
y 2  son  los  valores  propios  de  M

Entonces,  los  valores  de  estos  valores  propios  deciden  si  una  región  es  esquina,  borde  o  plana.

•  Cuando  | |  es  pequeño,  lo  que  sucede  cuando y  1 2  son  pequeños,  la  región  es  plana.

•  Cuando  <  0,  lo  que  ocurre  cuando 1  >>  2  o  viceversa,  la  región  es  borde.

•  Cuando  es  grande,  lo  que  sucede  cuando y  1 2  son  grandes  y 2, la  región  es  una  esquina.


1

Se  puede  representar  en  una  bonita  imagen  de  la  siguiente  manera:

1.5.  Detección  y  descripción  de  características 159
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Entonces,  el  resultado  de  Harris  Corner  Detection  es  una  imagen  en  escala  de  grises  con  estas  puntuaciones.  Umbral  para  una  adecuada  darle  las  
esquinas  de  la  imagen.  Lo  haremos  con  una  simple  imagen.

Detector  de  esquina  Harris  en  OpenCV

OpenCV  tiene  la  función  cv2.cornerHarris()  para  este  propósito.  Sus  argumentos  son:

•  img  ­  Imagen  de  entrada,  debe  ser  en  escala  de  grises  y  tipo  float32.

•  blockSize  ­  Es  el  tamaño  del  vecindario  considerado  para  la  detección  de  esquinas

•  ksize  ­  Parámetro  de  apertura  de  la  derivada  de  Sobel  utilizada.

•  k  ­  Parámetro  libre  del  detector  de  Harris  en  la  ecuación.

Vea  el  ejemplo  a  continuación:

importar  cv2  
importar  numpy  como  np

nombre  de  archivo  =  'tablero  de  ajedrez.jpg'  
img  =  cv2.imread  (nombre  de  archivo)

160 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

gris  =  cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

gris  =  np.float32(gris)  dst  =  
cv2.cornerHarris(gris,2,3,0.04)

#resultado  se  dilata  para  marcar  las  esquinas,  no  es  importante  dst  =  cv2.dilate(dst,None)

#  Umbral  para  un  valor  óptimo,  puede  variar  según  la  imagen.  img[dst>0.01*dst.max()]=[0,0,255]

cv2.imshow('dst',img)  si  
cv2.waitKey(0)  &  0xff  ==  27:  cv2.destroyAllWindows()

A  continuación  se  muestran  los  tres  resultados:

1.5.  Detección  y  descripción  de  características 161
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Esquina  con  precisión  de  subpíxeles

A  veces,  es  posible  que  necesite  encontrar  las  esquinas  con  la  máxima  precisión.  OpenCV  viene  con  una  función  cv2.cornerSubPix()  
que  refina  aún  más  las  esquinas  detectadas  con  una  precisión  de  subpíxeles.  A  continuación  se  muestra  un  ejemplo.  Como  de  
costumbre,  primero  tenemos  que  encontrar  las  esquinas  de  harris.  Luego  pasamos  los  centroides  de  estas  esquinas  (puede  haber  un  
montón  de  píxeles  en  una  esquina,  tomamos  su  centroide)  para  refinarlos.  Las  esquinas  de  Harris  están  marcadas  en  píxeles  rojos  y  
las  esquinas  refinadas  están  marcadas  en  píxeles  verdes.  Para  esta  función,  tenemos  que  definir  los  criterios  de  cuándo  detener  la  
iteración.  Lo  detenemos  después  de  un  número  específico  de  iteraciones  o  se  logra  cierta  precisión,  lo  que  ocurra  primero.  También  
necesitamos  definir  el  tamaño  del  vecindario  que  buscaría  para  las  esquinas.

importar  cv2  
importar  numpy  como  np

nombre  de  archivo  =  'tablero  de  ajedrez2.jpg'  img  
=  cv2.imread(nombre  de  archivo)  gris  =  
cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#  encuentra  las  esquinas  de  Harris  
grises  =  np.float32(gray)  dst  =  
cv2.cornerHarris(gray,2,3,0.04)  dst  =  cv2.dilate(dst,None)

ret,  dst  =  cv2.threshold(dst,0.01*dst.max(),255,0)  dst  =  np.uint8(dst)

#  encontrar  centroides  ret,  
etiquetas,  estadísticas,  centroides  =  cv2.connectedComponentsWithStats(dst)

#  definir  los  criterios  para  detener  y  refinar  las  esquinas  criterio  =  (cv2.TERM_CRITERIA_EPS  
+  cv2.TERM_CRITERIA_MAX_ITER,  100,  0.001)  esquinas  =  cv2.cornerSubPix(gray,np.float32(centroids),(5,5),(­1,  ­1),  criterios)

#  Ahora  dibújalos
res  =  np.hstack((centroides,esquinas))  res  =  np.int0(res)  
img[res[:,1],res[:,0]]=[0,0,255]  
img[res[:,3] ,res[:,2]]  =  [0,255,0]

cv2.imwrite('subpixel5.png',img)

A  continuación  se  muestra  el  resultado,  donde  se  muestran  algunas  ubicaciones  importantes  en  una  ventana  ampliada  para  visualizar:

162 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

Ejercicios

Detector  de  esquinas  Shi­Tomasi  y  buenas  características  para  rastrear

Meta

En  este  capítulo,
•  Aprenderemos  sobre  el  otro  detector  de  esquinas:  Detector  de  esquinas  Shi­Tomasi

•  Veremos  la  función:  cv2.goodFeaturesToTrack()

Teoría

En  el  último  capítulo,  vimos  Harris  Corner  Detector.  Más  tarde,  en  1994,  J.  Shi  y  C.  Tomasi  le  hicieron  una  pequeña  modificación  
en  su  artículo  Good  Features  to  Track ,  que  muestra  mejores  resultados  en  comparación  con  Harris  Corner  Detector.  La  función  
de  puntuación  en  Harris  Corner  Detector  estuvo  dada  por:

= 1  2  −  ( 1  +  2)
2

En  lugar  de  esto,  Shi­Tomasi  propuso:

=  ( 1,  2)

Si  es  mayor  que  un  valor  de  umbral,  se  considera  como  una  esquina.  Si  lo  trazamos  en  Corner   1  −  2  espacios  como  hicimos  en  Harris
Detector,  obtenemos  una  imagen  como  la  siguiente:

1.5.  Detección  y  descripción  de  características 163
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

En  la  figura,  puede  ver  que  solo  cuando  está  en  la   1 y 2  están  por  encima  de  un  valor  mínimo, , se  considera  como  un


esquina  (región  verde).

Código

OpenCV  tiene  una  función,  cv2.goodFeaturesToTrack().  Encuentra  N  esquinas  más  fuertes  en  la  imagen  mediante  el  método  Shi­
Tomasi  (o  Detección  de  esquinas  de  Harris,  si  lo  especifica).  Como  de  costumbre,  la  imagen  debe  ser  una  imagen  en  escala  de  grises.  
Luego  especifica  el  número  de  esquinas  que  desea  encontrar.  Luego,  especifica  el  nivel  de  calidad,  que  es  un  valor  entre  0  y  1,  que  
denota  la  calidad  mínima  de  la  esquina  por  debajo  de  la  cual  todos  son  rechazados.  Luego  proporcionamos  la  distancia  euclidiana  
mínima  entre  las  esquinas  detectadas.

Con  toda  esta  información,  la  función  encuentra  esquinas  en  la  imagen.  Todas  las  esquinas  por  debajo  del  nivel  de  calidad  son  
rechazadas.  Luego,  ordena  las  esquinas  restantes  según  la  calidad  en  orden  descendente.  Luego,  la  función  toma  la  primera  esquina  
más  fuerte,  desecha  todas  las  esquinas  cercanas  en  el  rango  de  distancia  mínima  y  devuelve  N  esquinas  más  fuertes.

En  el  siguiente  ejemplo,  intentaremos  encontrar  las  25  mejores  esquinas:

importar  numpy  como  np  importar  
cv2  desde  matplotlib  
importar  pyplot  como  plt

img  =  cv2.imread('simple.jpg')  gris  =  
cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

esquinas  =  cv2.goodFeaturesToTrack(gray,25,0.01,10)  esquinas  =  np.int0(esquinas)

para  i  en  las  esquinas:

x,y  =  i.ravel()  cv2.circle(img,
(x,y),3,255,­1)

164 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

plt.imshow(img),plt.show()

Vea  el  resultado  a  continuación:

Esta  función  es  más  apropiada  para  el  seguimiento.  Eso  lo  veremos  cuando  llegue  su  momento.

Recursos  adicionales

Ejercicios

Introducción  a  SIFT  (Transformación  de  características  de  escala  invariable)

Meta

En  este  capítulo,

•  Aprenderemos  sobre  los  conceptos  del  algoritmo  SIFT

•  Aprenderemos  a  encontrar  puntos  clave  y  descriptores  SIFT.

Teoría

En  los  últimos  dos  capítulos,  vimos  algunos  detectores  de  esquinas  como  Harris,  etc.  Son  invariantes  a  la  rotación,  lo  que  significa  que,  incluso  si  
se  gira  la  imagen,  podemos  encontrar  las  mismas  esquinas.  Es  obvio  porque  las  esquinas  siguen  siendo  esquinas  en  la  imagen  girada  también.  
Pero,  ¿qué  pasa  con  la  escala?  Una  esquina  puede  no  ser  una  esquina  si  la  imagen  está  escalada.  Por  ejemplo,  verifique  una  imagen  simple  a  
continuación.  Una  esquina  en  una  imagen  pequeña  dentro  de  una  ventana  pequeña  es  plana  cuando  se  amplía  en  la  misma  ventana.  Entonces,  
la  esquina  de  Harris  no  es  invariante  de  escala.

1.5.  Detección  y  descripción  de  características 165
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Entonces,  en  2004,  D.  Lowe,  de  la  Universidad  de  British  Columbia,  ideó  un  nuevo  algoritmo,  Scale  Invariant  Feature  Trans  form  (SIFT)  en  su  
artículo,  Distinctive  Image  Features  from  Scale­Invariant  Keypoints,  que  extrae  puntos  clave  y  calcula  sus  descriptores.  (Este  documento  es  fácil  
de  entender  y  se  considera  el  mejor  material  disponible  en  SIFT.  Por  lo  tanto,  esta  explicación  es  solo  un  breve  resumen  de  este  documento).

Hay  principalmente  cuatro  pasos  involucrados  en  el  algoritmo  SIFT.  Los  veremos  uno  por  uno.

1.  Detección  de  extremos  de  espacio  de  escala

De  la  imagen  de  arriba,  es  obvio  que  no  podemos  usar  la  misma  ventana  para  detectar  puntos  clave  con  diferente  escala.  Está  bien  con  una  
esquina  pequeña.  Pero  para  detectar  esquinas  más  grandes  necesitamos  ventanas  más  grandes.  Para  esto,  se  utiliza  el  filtrado  de  espacio  de  escala.
En  él  se  encuentra  el  Laplaciano  de  Gauss  para  la  imagen  con  varios  valores.  LoG  actúa  como  un  detector  de  manchas  que  detecta  manchas  en  
varios  tamaños  debido  a  cambios  en  En  resumen,  .actúa  como  un  parámetro  de  escala.  Por  ejemplo,  en  la  imagen  de  arriba,  el  núcleo  gaussiano  
con  bajo  da  un  valor  alto  para  la  esquina  pequeña,  mientras  que  el  núcleo  guassiano  con  alto  se  adapta  bien  a  la  esquina  más  grande.  Entonces,  
,
podemos  encontrar  los  máximos  locales  a  lo  largo  de  la  escala  y  el  espacio,  lo  que  nos  da  una  lista  de  valores  
( , )  lo  que  significa  que  hay  un  
punto  clave  potencial  en  (x,y)  a  escala.

Pero  este  LoG  es  un  poco  costoso,  por  lo  que  el  algoritmo  SIFT  usa  Diferencia  de  gaussianas,  que  es  una  aproximación  de  LoG.
La  diferencia  de  gaussiana  se  obtiene  como  la  diferencia  de  desenfoque  gaussiano  de  una  imagen  con  dos , déjalo  ser
. Este  proceso  se  realiza  para  diferentes  octavas  de  la  imagen  en  la  Pirámide  Gaussiana.  Se  representa  en  la  siguiente  imagen:

166 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Una  vez  que  se  encuentran  estos  DoG,  se  buscan  imágenes  extremas  locales  sobre  escala  y  espacio.  Por  ejemplo,  un  píxel  en  una  
imagen  se  compara  con  sus  8  vecinos  así  como  con  9  píxeles  en  la  escala  siguiente  y  9  píxeles  en  escalas  anteriores.  Si  es  un  extremo  
local,  es  un  punto  clave  potencial.  Básicamente  significa  que  el  punto  clave  se  representa  mejor  en  esa  escala.  Se  muestra  en  la  siguiente  imagen:

Con  respecto  a  los  diferentes  parámetros,  el  documento  brinda  algunos  datos  empíricos  que  se  pueden  resumir  como,  número  de  octavas  
=  4,  número  de  niveles  de  escala  =  5,  inicial  =  1.6,  =  √  2,  etc.  como  valores  óptimos.

1.5.  Detección  y  descripción  de  características 167
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

2.  Localización  de  puntos  clave

Una  vez  que  se  encuentran  las  ubicaciones  de  puntos  clave  potenciales,  deben  refinarse  para  obtener  resultados  más  precisos.  Usaron  la  expansión  
de  la  serie  de  Taylor  del  espacio  de  escala  para  obtener  una  ubicación  más  precisa  de  los  extremos,  y  si  la  intensidad  en  este  extremo  es  menor  
que  un  valor  de  umbral  (0.03  según  el  documento),  se  rechaza.  Este  umbral  se  llama  contrastThreshold  en  OpenCV

DoG  tiene  una  mayor  respuesta  para  los  bordes,  por  lo  que  también  es  necesario  eliminar  los  bordes.  Para  ello  se  utiliza  un  concepto  similar  al  
detector  de  esquina  Harris.  Usaron  una  matriz  hessiana  de  2x2  (H)  para  calcular  la  curvatura  principal.  Sabemos  por  el  detector  de  esquinas  de  
Harris  que,  para  las  aristas,  un  valor  propio  es  mayor  que  el  otro.  Así  que  aquí  usaron  una  función  simple,

Si  esta  relación  es  mayor  que  un  umbral,  llamado  edgeThreshold  en  OpenCV,  ese  punto  clave  se  descarta.  Se  da  como  10  en  papel.

Por  lo  tanto,  elimina  los  puntos  clave  de  bajo  contraste  y  los  puntos  clave  de  borde  y  lo  que  queda  son  puntos  de  gran  interés.

3.  Asignación  de  orientación

Ahora  se  asigna  una  orientación  a  cada  punto  clave  para  lograr  la  invariancia  a  la  rotación  de  la  imagen.  Se  toma  un  vecindario  alrededor  de  la  
ubicación  del  punto  clave  según  la  escala,  y  se  calcula  la  magnitud  y  la  dirección  del  gradiente  en  esa  región.  Se  crea  un  histograma  de  orientación  
con  36  contenedores  que  cubren  360  grados.  (Está  ponderado  por  la  magnitud  del  gradiente  y  la  ventana  circular  con  ponderación  gaussiana  igual  
a  1,5  veces  la  escala  del  punto  clave.  Se  toma  el  pico  más  alto  en  el  histograma  y  cualquier  pico  por  encima  del  80%  también  se  considera  para  
calcular  la  orientación.  Crea  puntos  clave  con  la  misma  ubicación  y  escala,  pero  diferentes  direcciones  Contribuye  a  la  estabilidad  del  emparejamiento.

4.  Descriptor  de  punto  clave

Ahora  se  crea  el  descriptor  de  punto  clave.  Se  toma  una  vecindad  de  16x16  alrededor  del  punto  clave.  Se  divide  en  16  subbloques  de  tamaño  4x4.  
Para  cada  subbloque,  se  crea  un  histograma  de  orientación  de  8  bins.  Por  lo  tanto,  hay  un  total  de  128  valores  de  bin  disponibles.  Se  representa  
como  un  vector  para  formar  un  descriptor  de  punto  clave.  Además  de  esto,  se  toman  varias  medidas  para  lograr  robustez  frente  a  cambios  de  
iluminación,  rotación,  etc.

5.  Coincidencia  de  puntos  clave

Los  puntos  clave  entre  dos  imágenes  se  emparejan  mediante  la  identificación  de  sus  vecinos  más  cercanos.  Pero  en  algunos  casos,  la  segunda  
coincidencia  más  cercana  puede  estar  muy  cerca  de  la  primera.  Puede  ocurrir  debido  al  ruido  u  otras  razones.  En  ese  caso,  se  toma  la  relación  entre  
la  distancia  más  cercana  y  la  segunda  distancia  más  cercana.  Si  es  superior  a  0,8,  se  rechazan.  Elimina  alrededor  del  90%  de  las  coincidencias  
falsas,  mientras  que  descarta  solo  el  5%  de  las  coincidencias  correctas,  según  el  documento.

Este  es  un  resumen  del  algoritmo  SIFT.  Para  obtener  más  detalles  y  comprensión,  se  recomienda  encarecidamente  leer  el  artículo  original.  Recuerde  
una  cosa,  este  algoritmo  está  patentado.  Entonces,  este  algoritmo  está  incluido  en  el  módulo  Non­free  en  OpenCV.

TAMIZAR  en  OpenCV

Así  que  ahora  veamos  las  funcionalidades  SIFT  disponibles  en  OpenCV.  Comencemos  con  la  detección  de  puntos  clave  y  dibujémoslos.  Primero  
tenemos  que  construir  un  objeto  SIFT.  Podemos  pasarle  diferentes  parámetros  que  son  opcionales  y  están  bien  explicados  en  docs.

importar  cv2  
importar  numpy  como  np

img  =  cv2.imread('inicio.jpg')

168 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

gris=  cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

sift  =  cv2.SIFT()  kp  =  
sift.detect(gris,Ninguno)

img=cv2.drawKeypoints(gris,kp)

cv2.imwrite('sift_puntos  clave.jpg',img)

La  función  sift.detect()  encuentra  el  punto  clave  en  las  imágenes.  Puede  pasar  una  máscara  si  desea  buscar  solo  una  parte  de  la  
imagen.  Cada  punto  clave  es  una  estructura  especial  que  tiene  muchos  atributos  como  sus  coordenadas  (x,y),  el  tamaño  del  
vecindario  significativo,  el  ángulo  que  especifica  su  orientación,  la  respuesta  que  especifica  la  fuerza  de  los  puntos  clave,  etc.

OpenCV  también  proporciona  la  función  cv2.drawKeyPoints()  que  dibuja  pequeños  círculos  en  las  ubicaciones  de  los  puntos  clave.  
Si  le  pasa  una  bandera,  cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ,  dibujará  un  círculo  con  el  tamaño  del  punto  
clave  e  incluso  mostrará  su  orientación.  Vea  el  siguiente  ejemplo.

img=cv2.drawKeypoints(gray,kp,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)  
cv2.imwrite('sift_keypoints.jpg',img)

Vea  los  dos  resultados  a  continuación:

Ahora,  para  calcular  el  descriptor,  OpenCV  proporciona  dos  métodos.

1.  Como  ya  encontró  los  puntos  clave,  puede  llamar  a  sift.compute() ,  que  calcula  los  descriptores  a  partir  de  los  puntos  clave  
que  hemos  encontrado.  Por  ejemplo:  kp,des  =  sift.compute(gray,kp)

2.  Si  no  encontró  puntos  clave,  busque  directamente  puntos  clave  y  descriptores  en  un  solo  paso  con  la  función,
sift.detectAndCompute().

1.5.  Detección  y  descripción  de  características 169
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Veremos  el  segundo  método:

sift  =  cv2.SIFT()  kp,  des  
=  sift.detectAndCompute(gris,Ninguno)

Aquí  kp  será  una  lista  de  puntos  clave  y  des  es  una  matriz  numpy  de  formas _  _ ×  128.

Así  que  obtuvimos  puntos  clave,  descriptores,  etc.  Ahora  queremos  ver  cómo  hacer  coincidir  los  puntos  clave  en  diferentes  imágenes.  Eso  lo  
aprenderemos  en  los  próximos  capítulos.

Recursos  adicionales

Ejercicios

Introducción  a  SURF  (funciones  robustas  aceleradas)

Meta

En  este  capítulo,

•  Veremos  las  bases  del  SURF

•  Veremos  funcionalidades  SURF  en  OpenCV

Teoría

En  el  último  capítulo,  vimos  SIFT  para  la  detección  y  descripción  de  puntos  clave.  Pero  fue  comparativamente  lento  y  la  gente  necesitaba  
una  versión  más  acelerada.  En  2006,  tres  personas,  Bay,  H.,  Tuytelaars,  T.  y  Van  Gool,  L,  publicaron  otro  artículo,  "SURF:  Speeded  Up  
Robust  Features"  que  introdujo  un  nuevo  algoritmo  llamado  SURF.  Como  sugiere  su  nombre,  es  una  versión  acelerada  de  SIFT.

En  SIFT,  Lowe  aproximó  Laplacian  of  Gaussian  con  Difference  of  Gaussian  para  encontrar  el  espacio  de  escala.  SURF  va  un  poco  más  
allá  y  se  aproxima  a  LoG  con  Box  Filter.  La  imagen  de  abajo  muestra  una  demostración  de  tal  aproximación.
Una  gran  ventaja  de  esta  aproximación  es  que  la  convolución  con  filtro  de  caja  se  puede  calcular  fácilmente  con  la  ayuda  de  imágenes  
integrales.  Y  se  puede  hacer  en  paralelo  para  diferentes  escalas.  Además,  SURF  se  basa  en  el  determinante  de  la  matriz  hessiana  
tanto  para  la  escala  como  para  la  ubicación.

170 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Para  la  asignación  de  orientación,  SURF  utiliza  respuestas  de  wavelet  en  dirección  horizontal  y  vertical  para  una  vecindad  de  tamaño  
6s.  También  se  le  aplican  pesos  guassianos  adecuados.  Luego  se  trazan  en  un  espacio  como  se  muestra  en  la  imagen  a  continuación.
La  orientación  dominante  se  estima  calculando  la  suma  de  todas  las  respuestas  dentro  de  una  ventana  de  orientación  deslizante  de  
un  ángulo  de  60  grados.  Lo  interesante  es  que  la  respuesta  wavelet  se  puede  encontrar  usando  imágenes  integrales  muy  fácilmente  
a  cualquier  escala.  Para  muchas  aplicaciones,  no  se  requiere  invariancia  de  rotación,  por  lo  que  no  es  necesario  encontrar  esta  
orientación,  lo  que  acelera  el  proceso.  SURF  proporciona  una  funcionalidad  llamada  Upright­SURF  o  U­SURF.  Mejora  la  velocidad  y  
es  robusto  hasta  ±15  .  OpenCV  admite  ambos,  dependiendo  de  la  bandera,  en  posición  vertical.  Si  es  0,  se  calcula  la  orientación.  
Si  es  1,  no  se  calcula  la  orientación  y  es  más  rápido.

1.5.  Detección  y  descripción  de  características 171
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Para  la  descripción  de  características,  SURF  usa  respuestas  Wavelet  en  dirección  horizontal  y  vertical  (nuevamente,  el  uso  de  imágenes  integrales  
facilita  las  cosas).  Se  toma  una  vecindad  de  tamaño  20sX20s  alrededor  del  punto  clave  donde  s  es  el  tamaño.  Se  divide  en  subregiones  4x4.  Para  
cada  subregión,  se  toman  las  respuestas  wavelet  horizontal  y  vertical  y  se  forma  un  vector  como  este,  =  (∑  ,  ∑  ,  ∑ |  |,  ∑ |  |).  Esto,  cuando  
se  representa  como  un  vector,  da  un  descriptor  de  características  SURF  con  un  total  de  64  dimensiones.  Reduzca  la  dimensión,  aumente  la  
velocidad  de  cálculo  y  coincidencia,  pero  proporcione  una  mejor  distinción  de  las  características.

Para  mayor  distinción,  el  descriptor  de  características  SURF  tiene  una  versión  extendida  de  128  dimensiones.  Las  sumas  de  y  |  |  se  calculan  por  
separado  para  <  0  y  ≥  0.  De  manera  similar,  las  sumas  de  y  |  |  se  dividen  según  el  signo  de ,  duplicando  así  el  número  de  entidades.  No  agrega  
mucha  complejidad  de  cálculo.  OpenCV  admite  ambos  estableciendo  el  valor  de  la  bandera  extendida  con  0  y  1  para  64­dim  y  128­dim  
respectivamente  (el  valor  predeterminado  es  128­dim)

Otra  mejora  importante  es  el  uso  del  signo  de  Laplacian  (traza  de  Hessian  Matrix)  para  el  punto  de  interés  subyacente.
No  agrega  ningún  costo  de  cálculo  ya  que  ya  se  calcula  durante  la  detección.  El  signo  del  Laplaciano  distingue  las  manchas  brillantes  sobre  
fondos  oscuros  de  la  situación  inversa.  En  la  etapa  de  comparación,  solo  comparamos  características  si  tienen  el  mismo  tipo  de  contraste  (como  
se  muestra  en  la  imagen  a  continuación).  Esta  información  mínima  permite  una  coincidencia  más  rápida,  sin  reducir  el  rendimiento  del  descriptor.

En  definitiva,  SURF  añade  un  montón  de  funciones  para  mejorar  la  velocidad  en  cada  paso.  El  análisis  muestra  que  es  3  veces  más  rápido  que  
SIFT,  mientras  que  el  rendimiento  es  comparable  al  de  SIFT.  SURF  es  bueno  para  manejar  imágenes  con  desenfoque  y  rotación,  pero  no  es  
bueno  para  manejar  el  cambio  de  punto  de  vista  y  el  cambio  de  iluminación.

SURF  en  OpenCV

OpenCV  proporciona  funcionalidades  SURF  al  igual  que  SIFT.  Inicia  un  objeto  SURF  con  algunas  condiciones  opcionales  como  descriptores  de  
64/128  dim,  SURF  vertical/normal,  etc.  Todos  los  detalles  se  explican  bien  en  los  documentos.  Luego,  como  hicimos  en  SIFT,  podemos  usar  
SURF.detect(),  SURF.compute(),  etc.  para  encontrar  puntos  clave  y  descriptores.

Primero  veremos  una  demostración  simple  sobre  cómo  encontrar  puntos  clave  y  descriptores  SURF  y  dibujarlos.  Todos  los  ejemplos  se  muestran  
en  la  terminal  de  Python,  ya  que  es  igual  que  SIFT  solamente.

>>>  img  =  cv2.imread('volar.png',0)

#  Crear  objeto  SURF.  Puede  especificar  parámetros  aquí  o  más  tarde.
#  Aquí  configuro  el  umbral  de  Hessian  en  400
>>>  navegar  =  cv2.SURF(400)

#  Encuentra  puntos  clave  y  descriptores  directamente  >>>  kp,  des  =  
surf.detectAndCompute(img,None)

172 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

>>>  largo(kp)  
699

1199  puntos  clave  es  demasiado  para  mostrar  en  una  imagen.  Lo  reducimos  a  unos  50  para  dibujarlo  en  una  imagen.  Mientras  emparejamos,  es  posible  
que  necesitemos  todas  esas  características,  pero  no  ahora.  Entonces  aumentamos  el  Umbral  de  Hesse.

#  Verifique  el  umbral  actual  de  Hessian  >>>  print  
surf.hessianThreshold  400.0

#  Lo  configuramos  en  unos  50000.  Recuerde,  es  solo  para  representar  en  la  imagen.
#  En  casos  reales,  es  mejor  tener  un  valor  300­500  >>>  surf.hessianThreshold  =  50000

#  Calcule  nuevamente  los  puntos  clave  y  verifique  su  número.  >>>  kp,  des  
=  surf.detectAndCompute(img,Ninguno)

>>>  imprimir  len(kp)  47

Es  menos  de  50.  Dibujémoslo  en  la  imagen.

>>>  img2  =  cv2.drawKeypoints(img,kp,Ninguno,(255,0,0),4)

>>>  plt.imshow(img2),plt.show()

Vea  el  resultado  a  continuación.  Puede  ver  que  SURF  es  más  como  un  detector  de  manchas.  Detecta  las  manchas  blancas  en  las  alas  de  
las  mariposas.  Puedes  probarlo  con  otras  imágenes.

Ahora  quiero  aplicar  U­SURF,  para  que  no  encuentre  la  orientación.

1.5.  Detección  y  descripción  de  características 173
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

#  Verifique  la  bandera  vertical,  si  es  Falso,  configúrelo  como  Verdadero  >>>  
print  surf.upright  Falso

>>>  navegar.upright  =  True

#  Vuelva  a  calcular  los  puntos  característicos  y  dibújelos  >>>  kp  =  
surf.detect(img,None)  >>>  img2  =  
cv2.drawKeypoints(img,kp,None,(255,0,0),4)

>>>  plt.imshow(img2),plt.show()

Vea  los  resultados  a  continuación.  Todas  las  orientaciones  se  muestran  en  la  misma  dirección.  Es  más  rápido  que  el  anterior.  Si  está  
trabajando  en  casos  en  los  que  la  orientación  no  es  un  problema  (como  la  costura  panorámica),  etc.,  esto  es  mucho  mejor.

Finalmente  verificamos  el  tamaño  del  descriptor  y  lo  cambiamos  a  128  si  es  solo  64­dim.

#  Encuentra  el  tamaño  del  descriptor  
>>>  print  surf.descriptorSize()
64

#  Eso  significa  bandera,  "extendida"  es  Falso.
>>>  navegar.extendido
FALSO

#  Entonces  lo  hacemos  a  True  para  obtener  descriptores  de  128  dim.  >>>  
navegar.extendido  =  Verdadero
>>>  kp,  des  =  surf.detectAndCompute(img,Ninguno)  >>>  print  
surf.descriptorSize()  128

174 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

>>>  imprimir  des.forma  (47,  
128)

La  parte  restante  es  emparejar,  lo  que  haremos  en  otro  capítulo.

Recursos  adicionales

Ejercicios

Algoritmo  FAST  para  detección  de  esquinas

Meta

En  este  capítulo,

•  Comprenderemos  los  conceptos  básicos  del  algoritmo  FAST

•  Encontraremos  esquinas  utilizando  las  funcionalidades  de  OpenCV  para  el  algoritmo  FAST.

Teoría

Vimos  varios  detectores  de  características  y  muchos  de  ellos  son  realmente  buenos.  Pero  cuando  se  mira  desde  el  punto  de  vista  de  una  
aplicación  en  tiempo  real,  no  son  lo  suficientemente  rápidos.  Un  mejor  ejemplo  sería  el  robot  móvil  SLAM  (localización  y  mapeo  simultáneos)  
que  tiene  recursos  computacionales  limitados.

Como  solución  a  esto,  Edward  Rosten  y  Tom  Drummond  propusieron  el  algoritmo  FAST  (características  de  la  prueba  de  segmento  acelerado)  
en  su  artículo  "Aprendizaje  automático  para  la  detección  de  esquinas  de  alta  velocidad"  en  2006  (luego  revisado  en  2010).
A  continuación  se  presenta  un  resumen  básico  del  algoritmo.  Consulte  el  papel  original  para  obtener  más  detalles  (Todas  las  imágenes  están  
tomadas  del  papel  original).

Detección  de  características  usando  FAST

1.  Seleccione  un  píxel  en  la  imagen  que  se  identificará  como  un  punto  de  interés  o  no.  Sea  su  intensidad .

2.  Seleccione  el  valor  de  umbral  apropiado.

3.  Considere  un  círculo  de  16  píxeles  alrededor  del  píxel  bajo  prueba.  (Ver  la  imagen  de  abajo)

1.5.  Detección  y  descripción  de  características 175
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

4.  Ahora  el  píxel  es  una  esquina  si  existe  un  conjunto  de  píxeles  contiguos  en  el  círculo  (de  16  píxeles)  que  son  todos  o  todos  más  
más  brillante  que  +   , oscuros  que .  (Se  muestra  como  líneas  discontinuas  blancas  en  la  imagen  de  arriba).  fue  elegido  para  ser
12.

5.  Se  propuso  una  prueba  de  alta  velocidad  para  excluir  una  gran  cantidad  de  no  esquinas.  Esta  prueba  examina  solo  los  cuatro  píxeles  
en  1,  9,  5  y  13  (los  primeros  1  y  9  se  prueban  si  son  demasiado  brillantes  o  demasiado  oscuros.  Si  es  así,  luego  verifique  5  y  13).
Si  es  una  esquina,  al  menos  tres  de  ellos  deben  ser  más  brillantes  que  +  o  más  oscuros  que  Si  ninguno  de  estos  es  .el  caso,  entonces  
no  puede  ser  una  esquina.  A  continuación,  se  puede  aplicar  el  criterio  de  prueba  de  segmento  completo  a  los  candidatos  aprobados  
examinando  todos  los  píxeles  del  círculo.  Este  detector  en  sí  mismo  exhibe  un  alto  rendimiento,  pero  tiene  varias  debilidades:

•  No  rechaza  tantos  candidatos  para  n  <  12.

•  La  elección  de  los  píxeles  no  es  óptima  porque  su  eficiencia  depende  del  orden  de  las  preguntas  y  la  distribución.
butión  de  las  apariciones  en  las  esquinas.

•  Los  resultados  de  las  pruebas  de  alta  velocidad  se  desechan.

•  Se  detectan  varias  características  adyacentes  entre  sí.

Los  primeros  3  puntos  se  abordan  con  un  enfoque  de  aprendizaje  automático.  El  último  se  aborda  mediante  supresión  no  máxima.

Aprendizaje  automático  de  un  detector  de  esquinas

1.  Seleccione  un  conjunto  de  imágenes  para  el  entrenamiento  (preferiblemente  del  dominio  de  la  aplicación  de  destino)

2.  Ejecute  el  algoritmo  FAST  en  cada  imagen  para  encontrar  puntos  característicos.

3.  Para  cada  punto  característico,  almacene  los  16  píxeles  a  su  alrededor  como  un  vector.  Hazlo  para  que  todas  las  imágenes  obtengan  un  vector  de  características.

4.  Cada  píxel  (digamos)  en  estos  16  píxeles  puede  tener  uno  de  los  siguientes  tres  estados:

176 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

5.  Dependiendo  de  estos  estados,  el  vector  de  características  se  subdivide  en  3  subconjuntos, , , .

6.  Defina  una  nueva  variable  booleana, , lo  cual  es  verdadero  si  es  una  esquina  y  falso  en  caso  contrario.

7.  Use  el  algoritmo  ID3  (clasificador  de  árboles  de  decisión)  para  consultar  cada  subconjunto  usando  la  variable por  el  conocimiento  
de  la  verdadera  clase.  Selecciona  el  que  arroja  la  mayor  información  sobre  si  el  píxel  candidato  es  una  esquina,  medida  por  la  
entropía  de .

8.  Esto  se  aplica  recursivamente  a  todos  los  subconjuntos  hasta  que  su  entropía  sea  cero.

9.  El  árbol  de  decisión  así  creado  se  utiliza  para  la  detección  rápida  en  otras  imágenes.

Supresión  no  máxima

La  detección  de  múltiples  puntos  de  interés  en  ubicaciones  adyacentes  es  otro  problema.  Se  soluciona  utilizando  Supresión  No  Máxima.

1.  Calcule  una  función  de  puntuación  para  todos  los  puntos  característicos  detectados. es  la  suma  de  la  diferencia  absoluta  entre
y  16  valores  de  píxeles  circundantes.

2.  Considere  dos  puntos  significativos  adyacentes  y  calcule  sus  valores.

3.  Descartar  el  de  menor  valor.

Resumen

Es  varias  veces  más  rápido  que  otros  detectores  de  esquina  existentes.

Pero  no  es  resistente  a  altos  niveles  de  ruido.  Depende  de  un  umbral.

Detector  de  características  FAST  en  OpenCV

Se  llama  como  cualquier  otro  detector  de  características  en  OpenCV.  Si  lo  desea,  puede  especificar  el  umbral,  si  se  aplicará  o  no  la  supresión  
no  máxima,  el  vecindario  que  se  usará,  etc.

Para  el  vecindario,  se  definen  tres  banderas,  cv2.FAST_FEATURE_DETECTOR_TYPE_5_8,  cv2.
FAST_FEATURE_DETECTOR_TYPE_7_12  y  cv2.FAST_FEATURE_DETECTOR_TYPE_9_16.  A  continuación  se  muestra  un  código  simple  
sobre  cómo  detectar  y  dibujar  los  puntos  de  función  FAST.

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('simple.jpg',0)

#  Iniciar  objeto  FAST  con  valores  predeterminados

1.5.  Detección  y  descripción  de  características 177
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

rápido  =  cv2.FastFeatureDetector()

#  encuentra  y  dibuja  los  puntos  clave  kp  =  
fast.detect(img,None)  img2  =  
cv2.drawKeypoints(img,  kp,  color=(255,0,0))

#  Imprimir  todos  los  parámetros  
predeterminados  print  "Umbral:  ",  fast.getInt('threshold')  print  
"nonmaxSuppression:  ",  fast.getBool('nonmaxSuppression')  print  "vecindario:  ",  fast.getInt('type')  print  
"Total  Puntos  clave  con  nonmaxSuppression:  ",  len(kp)

cv2.imwrite('fast_true.png',img2)

#  Deshabilitar  nonmaxSuppression  
fast.setBool('nonmaxSuppression',0)  kp  =  
fast.detect(img,Ninguno)

imprimir  "Puntos  clave  totales  sin  no  maxSuppression:  ",  len  (kp)

img3  =  cv2.drawKeypoints(img,  kp,  color=(255,0,0))

cv2.imwrite('fast_false.png',img3)

Vea  los  resultados.  La  primera  imagen  muestra  FAST  con  nonmaxSuppression  y  la  segunda  sin  nonmaxSuppression:

Recursos  adicionales

1.  Edward  Rosten  y  Tom  Drummond,  “Aprendizaje  automático  para  la  detección  de  esquinas  a  alta  velocidad”  en  el  9.º  Congreso  Europeo
Conferencia  sobre  Visión  por  Computador,  vol.  1,  2006,  págs.  430–443.

2.  Edward  Rosten,  Reid  Porter  y  Tom  Drummond,  "Más  rápido  y  mejor:  un  enfoque  de  aprendizaje  automático  para  la  detección  de  
esquinas"  en  IEEE  Trans.  Análisis  de  patrones  e  inteligencia  artificial,  2010,  vol  32,  pp.  105­119.

Ejercicios

BREVE  (Características  elementales  independientes  robustas  binarias)

178 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Meta

En  este  capítulo

•  Veremos  los  fundamentos  del  algoritmo  BREVE

Teoría

Sabemos  que  SIFT  usa  un  vector  de  128  dim  para  los  descriptores.  Dado  que  utiliza  números  de  punto  flotante,  se  necesitan  básicamente  512  
bytes.  De  manera  similar,  SURF  también  requiere  un  mínimo  de  256  bytes  (para  64  dim).  La  creación  de  un  vector  de  este  tipo  para  miles  de  
funciones  requiere  una  gran  cantidad  de  memoria  que  no  es  factible  para  aplicaciones  con  restricciones  de  recursos,  especialmente  para  sistemas  
integrados.  Cuanto  mayor  sea  la  memoria,  mayor  será  el  tiempo  que  se  tarda  en  hacer  coincidir.

Pero  todas  estas  dimensiones  pueden  no  ser  necesarias  para  la  coincidencia  real.  Podemos  comprimirlo  usando  varios  métodos  como  PCA,  LDA,  
etc.  Incluso  otros  métodos  como  hashing  usando  LSH  (Locality  Sensitive  Hashing)  se  usan  para  convertir  estos  descriptores  SIFT  en  números  de  
coma  flotante  en  cadenas  binarias.  Estas  cadenas  binarias  se  utilizan  para  hacer  coincidir  entidades  mediante  la  distancia  de  Hamming.  Esto  
proporciona  una  mejor  aceleración  porque  encontrar  la  distancia  de  hamming  es  solo  aplicar  XOR  y  el  recuento  de  bits,  que  son  muy  rápidos  en  las  
CPU  modernas  con  instrucciones  SSE.  Pero  aquí,  primero  debemos  encontrar  los  descriptores,  luego  solo  podemos  aplicar  hash,  lo  que  no  resuelve  
nuestro  problema  inicial  en  la  memoria.

BREVE  entra  en  escena  en  este  momento.  Proporciona  un  atajo  para  encontrar  cadenas  binarias  directamente  sin  encontrar  descriptores.  Toma  un  
parche  de  imagen  suavizado  y  selecciona  un  conjunto  de  pares  de  ubicaciones  (x,  y)  de  una  manera  única  (explicado  en  papel).  Luego  se  realizan  
algunas  comparaciones  de  intensidad  de  píxeles  en  estos  pares  de  ubicaciones.  Por  ejemplo,  deje  que  los  primeros  pares  de  ubicación  sean  y  Si  ( )  
. <  ( ),  entonces  su  resultado  es  1,  de  lo  contrario  es  0.  Esto  se  aplica  a  todos  los  pares  de  ubicación  para  obtener  una  cadena  de  bits  de  dimensión.

Esto  puede  ser  128,  256  o  512.  OpenCV  admite  todos  estos,  pero  por  defecto,  sería  256  (OpenCV  lo  representa  en  bytes.  Por  lo  tanto,  los  valores  
serán  16,  32  y  64).  Entonces,  una  vez  que  obtenga  esto,  puede  usar  Hamming  Distance  para  hacer  coincidir  estos  descriptores.

Un  punto  importante  es  que  BRIEF  es  un  descriptor  de  funciones,  no  proporciona  ningún  método  para  encontrar  las  funciones.  Por  lo  tanto,  tendrá  
que  usar  cualquier  otro  detector  de  características  como  SIFT,  SURF,  etc.  El  documento  recomienda  usar  CenSurE,  que  es  un  detector  rápido  y  
BRIEF  funciona  incluso  un  poco  mejor  para  los  puntos  CenSurE  que  para  los  puntos  SURF.

En  resumen,  BRIEF  es  un  método  más  rápido  de  cálculo  y  coincidencia  de  descriptores  de  características.  También  proporciona  una  alta  tasa  de  reconocimiento  
a  menos  que  haya  una  gran  rotación  en  el  plano.

BREVE  en  OpenCV

El  siguiente  código  muestra  el  cálculo  de  los  descriptores  BREVE  con  la  ayuda  del  detector  CenSurE.  (El  detector  CenSurE  se  llama  detector  STAR  
en  OpenCV)

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('simple.jpg',0)

#  Iniciar  detector  STAR
estrella  =  cv2.FeatureDetector_create("ESTRELLA")

#  Iniciar  breve  extractor  BREVE  =  
cv2.DescriptorExtractor_create("BRIEF")

#  encuentra  los  puntos  clave  con  STAR  kp  =  
star.detect(img,None)

1.5.  Detección  y  descripción  de  características 179
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

#  calcular  los  descriptores  con  BRIEF  kp,  des  =  
brief.compute(img,  kp)

imprimir  resumen.getInt('bytes')  imprimir  
des.forma

La  función  brief.getInt('bytes')  proporciona  el  tamaño  utilizado  en  bytes.  Por  defecto  es  32.  El  siguiente  es  el  emparejamiento,  que  se  hará  en  otro  
capítulo.

Recursos  adicionales

1.  Michael  Calonder,  Vincent  Lepetit,  Christoph  Strecha  y  Pascal  Fua,  "BRIEF:  Binary  Robust  Independent  Elementary  Features",  11.ª  
Conferencia  Europea  sobre  Visión  por  Computador  (ECCV),  Heraklion,  Creta.  LNCS  Springer,  septiembre  de  2010.

2.  LSH  (Locality  Sensitive  Hasing)  en  wikipedia.

ORB  (RÁPIDO  Orientado  y  BREVE  Girado)

Meta

En  este  capítulo,

•  Veremos  los  conceptos  básicos  de  ORB

Teoría

Como  entusiasta  de  OpenCV,  lo  más  importante  del  ORB  es  que  proviene  de  "OpenCV  Labs".  Este  algoritmo  fue  mencionado  por  Ethan  Rublee,  
Vincent  Rabaud,  Kurt  Konolige  y  Gary  R.  Bradski  en  su  artículo  ORB:  una  alternativa  eficiente  a  SIFT  o  SURF  en  2011.  Como  dice  el  título,  es  una  
buena  alternativa  a  SIFT  y  SURF  en  computación.  costo,  rendimiento  coincidente  y  principalmente  las  patentes.  Sí,  SIFT  y  SURF  están  patentados  
y  se  supone  que  debes  pagarles  por  su  uso.  ¡Pero  ORB  no  lo  es!

ORB  es  básicamente  una  fusión  del  detector  de  puntos  clave  RÁPIDO  y  el  descriptor  BREVE  con  muchas  modificaciones  para  mejorar  el  rendimiento.  
Primero  usa  FAST  para  encontrar  puntos  clave,  luego  aplica  la  medida  de  la  esquina  de  Harris  para  encontrar  los  N  puntos  principales  entre  ellos.
También  utiliza  la  pirámide  para  producir  características  multiescala.  Pero  un  problema  es  que  FAST  no  calcula  la  orientación.
Entonces,  ¿qué  pasa  con  la  invariancia  de  rotación?  A  los  autores  se  les  ocurrió  la  siguiente  modificación.

Calcula  el  centroide  ponderado  por  intensidad  del  parche  con  la  esquina  ubicada  en  el  centro.  La  dirección  del  vector  desde  este  punto  de  esquina  
hasta  el  centroide  da  la  orientación.  Para  mejorar  la  invariancia  de  rotación,  los  momentos  se  calculan  con  x  e  y,  que  deben  estar  en  una  región  
circular  de  radio , donde  está  el  tamaño  del  parche.
Ahora,  para  los  descriptores,  ORB  usa  descriptores  BREVE.  Pero  ya  hemos  visto  que  BRIEF  funciona  mal  con  la  rotación.
Entonces,  lo  que  hace  ORB  es  "dirigir"  BREVE  de  acuerdo  con  la  orientación  de  los  puntos  clave.  Para  cualquier  conjunto  de  características  de  
pruebas  binarias  en  la  ubicación  ( , ),  defina  una  matriz  de  2  ×  que  contenga  las  coordenadas  de  estos  píxeles.  Luego,  usando  la  orientación  del  
parche,  se  encuentra  su  matriz  de  rotación  y  gira  para  obtener  la  versión  dirigida  (girada).

ORB  discretiza  el  ángulo  en  incrementos  de  2/30  (12  grados)  y  construye  una  tabla  de  búsqueda  de  patrones  BREVE  precalculados.  Siempre  que  
la  orientación  del  punto  clave  sea  coherente  en  todas  las  vistas,  se  utilizará  el  conjunto  correcto  de  puntos  para  calcular  su  descriptor.

BREVE  tiene  una  propiedad  importante  de  que  cada  característica  de  bit  tiene  una  gran  variación  y  una  media  cercana  a  0,5.  Pero  una  vez  que  se  
orienta  a  lo  largo  de  la  dirección  del  punto  clave,  pierde  esta  propiedad  y  se  distribuye  más.  Una  varianza  alta  hace  que  una  característica  sea  más  
discriminatoria,  ya  que  responde  de  manera  diferente  a  las  entradas.  Otra  propiedad  deseable  es  que  las  pruebas  no  estén  correlacionadas,  ya  que  
cada  prueba  contribuirá  al  resultado.  Para  resolver  todo  esto,  ORB  ejecuta  una  búsqueda  codiciosa  entre  todos  los  posibles

180 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Pruebas  binarias  para  encontrar  las  que  tienen  una  varianza  alta  y  medias  cercanas  a  0,5,  además  de  no  estar  correlacionadas.  El  
resultado  se  llama  rBRIEF.

Para  la  coincidencia  de  descriptores,  se  utiliza  LSH  de  sonda  múltiple  que  mejora  el  LSH  tradicional.  El  documento  dice  que  ORB  es  
mucho  más  rápido  que  SURF  y  SIFT  y  el  descriptor  ORB  funciona  mejor  que  SURF.  ORB  es  una  buena  opción  en  dispositivos  de  
bajo  consumo  para  costura  panorámica,  etc.

ORB  en  OpenCV

Como  de  costumbre,  tenemos  que  crear  un  objeto  ORB  con  la  función,  cv2.ORB()  o  usando  la  interfaz  común  de  feature2d.  Tiene  una  
serie  de  parámetros  opcionales.  Los  más  útiles  son  nFeatures,  que  indica  el  número  máximo  de  funciones  que  se  conservarán  (de  
forma  predeterminada,  500),  scoreType,  que  indica  si  la  puntuación  de  Harris  o  FAST  para  clasificar  las  funciones  (de  forma  
predeterminada,  puntuación  de  Harris),  etc.  Otro  parámetro,  WTA_K,  decide  la  cantidad  de  puntos  que  producen  cada  elemento  del  
descriptor  BREVE  orientado.  Por  defecto  es  dos,  es  decir,  selecciona  dos  puntos  a  la  vez.  En  ese  caso,  para  la  coincidencia,  se  utiliza  
la  distancia  NORM_HAMMING.  Si  WTA_K  es  3  o  4,  lo  que  requiere  3  o  4  puntos  para  producir  un  descriptor  BREVE,  entonces  la  
distancia  de  coincidencia  se  define  mediante  NORM_HAMMING2.

A  continuación  se  muestra  un  código  simple  que  muestra  el  uso  de  ORB.

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('simple.jpg',0)

#  Iniciar  detector  STAR
orbe  =  cv2.ORB()

#  encuentra  los  puntos  clave  con  ORB  kp  =  
orb.detect(img,Ninguno)

#  calcular  los  descriptores  con  ORB  kp,  des  =  
orb.compute(img,  kp)

#  dibujar  solo  la  ubicación  de  los  puntos  clave,  no  el  tamaño  ni  la  orientación  img2  =  
cv2.drawKeypoints(img,kp,color=(0,255,0),  flags=0)  plt.imshow(img2),plt.show()

Vea  el  resultado  a  continuación:

1.5.  Detección  y  descripción  de  características 181
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Coincidencia  de  características  de  ORB,  lo  haremos  en  otro  capítulo.

Recursos  adicionales

1.  Ethan  Rublee,  Vincent  Rabaud,  Kurt  Konolige,  Gary  R.  Bradski:  ORB:  una  alternativa  eficiente  a  SIFT  o
NAVEGAR.  ICCV  2011:  2564­2571.

Ejercicios

Coincidencia  de  características

Meta

En  este  capítulo

•  Veremos  cómo  hacer  coincidir  las  características  de  una  imagen  con  otras.

•  Usaremos  Brute­Force  Matcher  y  FLANN  Matcher  en  OpenCV

Conceptos  básicos  de  Brute­Force  Matcher

El  comparador  de  fuerza  bruta  es  simple.  Toma  el  descriptor  de  una  característica  en  el  primer  conjunto  y  se  compara  con  todas  las  demás  
características  en  el  segundo  conjunto  utilizando  algún  cálculo  de  distancia.  Y  se  devuelve  el  más  cercano.

182 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Para  BF  Matcher,  primero  tenemos  que  crear  el  objeto  BFMatcher  usando  cv2.BFMatcher().  Se  necesitan  dos  parámetros  opcionales.
El  primero  es  normType.  Especifica  la  medida  de  distancia  a  utilizar.  Por  defecto,  es  cv2.NORM_L2.  Es  bueno  para  SIFT,  SURF,  etc.  (cv2.NORM_L1  
también  está  ahí).  Para  descriptores  basados  en  cadenas  binarias  como  ORB,  BRIEF,  BRISK,  etc.,  se  debe  usar  cv2.NORM_HAMMING,  que  usó  la  
distancia  de  Hamming  como  medida.  Si  ORB  usa  VTA_K  ==  3  o  4,  se  debe  usar  cv2.NORM_HAMMING2.

El  segundo  parámetro  es  una  variable  booleana,  CrossCheck,  que  es  falso  de  forma  predeterminada.  Si  es  cierto,  Matcher  devuelve  solo  aquellas  
coincidencias  con  valor  (i,  j)  de  modo  que  el  i­ésimo  descriptor  en  el  conjunto  A  tiene  el  j­ésimo  descriptor  en  el  conjunto  B  como  la  mejor  coincidencia  y  viceversa.
Es  decir,  las  dos  características  de  ambos  conjuntos  deben  coincidir  entre  sí.  Proporciona  resultados  consistentes  y  es  una  buena  alternativa  a  la  prueba  
de  relación  propuesta  por  D.  Lowe  en  el  documento  SIFT.

Una  vez  que  se  crea,  dos  métodos  importantes  son  BFMatcher.match()  y  BFMatcher.knnMatch().  El  primero  devuelve  la  mejor  coincidencia.  El  segundo  
método  devuelve  las  mejores  coincidencias  k  donde  el  usuario  especifica  k.  Puede  ser  útil  cuando  necesitamos  hacer  un  trabajo  adicional  al  respecto.

Al  igual  que  usamos  cv2.drawKeypoints()  para  dibujar  puntos  clave,  cv2.drawMatches()  nos  ayuda  a  dibujar  las  coincidencias.  Apila  dos  imágenes  
horizontalmente  y  dibuja  líneas  desde  la  primera  imagen  hasta  la  segunda  mostrando  las  mejores  coincidencias.  También  está  cv2.drawMatchesKnn ,  que  
dibuja  todas  las  k  mejores  coincidencias.  Si  k=2,  dibujará  dos  líneas  de  coincidencia  para  cada  punto  clave.  Entonces  tenemos  que  pasar  una  máscara  si  
queremos  dibujarla  selectivamente.

Veamos  un  ejemplo  para  cada  uno  de  SURF  y  ORB  (Ambos  usan  diferentes  medidas  de  distancia).

Coincidencia  de  fuerza  bruta  con  descriptores  ORB

Aquí,  veremos  un  ejemplo  simple  sobre  cómo  hacer  coincidir  las  características  entre  dos  imágenes.  En  este  caso,  tengo  una  imagen  de  consulta  y  una  
imagen  de  tren.  Intentaremos  encontrar  queryImage  en  trainImage  usando  la  coincidencia  de  características.  (Las  imágenes  son /samples/c/box.png  y /
samples/c/box_in_scene.png)

Estamos  utilizando  descriptores  SIFT  para  hacer  coincidir  las  características.  Entonces,  comencemos  con  la  carga  de  imágenes,  la  búsqueda  de  descriptores,  etc.

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

img1  =  cv2.imread('box.png',0)  img2  =   #  consultaImagen  
cv2.imread('box_in_scene.png',0)  #  trenImagen

#  Iniciar  detector  SIFT  orb  =  cv2.ORB()

#  encuentre  los  puntos  clave  y  descriptores  con  SIFT  kp1,  des1  =  
orb.detectAndCompute(img1,None)  kp2,  des2  =  
orb.detectAndCompute(img2,None)

A  continuación,  creamos  un  objeto  BFMatcher  con  medición  de  distancia  cv2.NORM_HAMMING  (ya  que  estamos  usando  ORB)  y  se  activa  CrossCheck  
para  obtener  mejores  resultados.  Luego  usamos  el  método  Matcher.match()  para  obtener  las  mejores  coincidencias  en  dos  imágenes.  Los  clasificamos  
en  orden  ascendente  de  sus  distancias  para  que  las  mejores  coincidencias  (con  distancia  baja)  estén  al  frente.
Luego,  sorteamos  solo  los  primeros  10  partidos  (solo  por  visibilidad.  Puede  aumentarlo  como  desee)

#  crear  objeto  BFMatcher  bf  =  
cv2.BFMatcher(cv2.NORM_HAMMING,  crossCheck=True)

#  Coincide  con  los  descriptores.  
coincidencias  =  bf.coincidencia(des1,des2)

#  Clasificarlos  en  el  orden  de  su  distancia.  coincidencias  =  
ordenado(coincidencias,  clave  =  lambda  x:x.distancia)

1.5.  Detección  y  descripción  de  características 183
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

#  Dibuja  los  primeros  10  partidos.
img3  =  cv2.drawMatches(img1,kp1,img2,kp2,coincidencias[:10],  banderas=2)

plt.imshow(img3),plt.show()

A  continuación  se  muestra  el  resultado  que  obtuve:

¿Qué  es  este  objeto  Matcher?

El  resultado  de  la  línea  matches  =  bf.match(des1,des2)  es  una  lista  de  objetos  DMatch.  Este  objeto  DMatch  tiene  los  siguientes  
atributos:

•  DMatch.distance  ­  Distancia  entre  descriptores.  Cuanto  más  bajo,  mejor.

•  DMatch.trainIdx  ­  Índice  del  descriptor  en  descriptores  de  tren

•  DMatch.queryIdx:  índice  del  descriptor  en  los  descriptores  de  consulta

•  DMatch.imgIdx  ­  Índice  de  la  imagen  del  tren.

Coincidencia  de  fuerza  bruta  con  descriptores  SIFT  y  prueba  de  relación

Esta  vez,  usaremos  BFMatcher.knnMatch()  para  obtener  k  mejores  coincidencias.  En  este  ejemplo,  tomaremos  k=2  para  que  podamos  
aplicar  la  prueba  de  razón  explicada  por  D.  Lowe  en  su  artículo.

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

184 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

img1  =  cv2.imread('box.png',0)  #  consultaImagen  img2  =  cv2.imread('box_in_scene.png',0)  #  
trenImagen

#  Iniciar  detector  SIFT
tamizar  =  cv2.TAMINAR()

#  encuentre  los  puntos  clave  y  descriptores  con  SIFT  kp1,  des1  =  
sift.detectAndCompute(img1,None)  kp2,  des2  =  sift.detectAndCompute(img2,None)

#  BFMatcher  con  parámetros  predeterminados  bf  =  
cv2.BFMatcher()
coincidencias  =  bf.knnCoincidencia(des1,des2,  k=2)

#  Aplicar  prueba  de  relación  
buena  =  []  para  
m,n  en  partidos:
si  distancia  m  <  0,75*distancia  n:
bueno.append([m])

#  cv2.drawMatchesKnn  espera  una  lista  de  listas  como  coincidencias.  img3  =  
cv2.drawMatchesKnn(img1,kp1,img2,kp2,bueno,banderas=2)

plt.imshow(img3),plt.show()

Vea  el  resultado  a  continuación:

Comparador  basado  en  FLANN

FLANN  significa  Biblioteca  rápida  para  vecinos  más  cercanos  aproximados.  Contiene  una  colección  de  algoritmos  optimizados  para  la  
búsqueda  rápida  de  vecinos  más  cercanos  en  grandes  conjuntos  de  datos  y  para  características  de  alta  dimensión.  Funciona  más  rápido  que  
BF  Matcher  para  grandes  conjuntos  de  datos.  Veremos  el  segundo  ejemplo  con  el  comparador  basado  en  FLANN.

Para  el  comparador  basado  en  FLANN,  necesitamos  pasar  dos  diccionarios  que  especifican  el  algoritmo  a  usar,  sus  parámetros  relacionados,  
etc.  El  primero  es  IndexParams.  Para  varios  algoritmos,  la  información  que  se  debe  pasar  se  explica  en  los  documentos  de  FLANN.  Como  
resumen,  para  algoritmos  como  SIFT,  SURF,  etc.,  puede  pasar  lo  siguiente:

1.5.  Detección  y  descripción  de  características 185
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

index_params  =  dict(algoritmo  =  FLANN_INDEX_KDTREE,  árboles  =  5)

Mientras  usa  ORB,  puede  pasar  lo  siguiente.  Los  valores  comentados  se  recomiendan  según  los  documentos,  pero  en  algunos  casos  no  
proporcionaron  los  resultados  requeridos.  Otros  valores  funcionaron  bien.:

index_params=  dict(algoritmo  =  FLANN_INDEX_LSH,  table_number  =  6,  #  12  
key_size  =  12,  #  20  multi_probe_level  
=  1)  #2

El  segundo  diccionario  es  SearchParams.  Especifica  el  número  de  veces  que  se  deben  recorrer  recursivamente  los  árboles  del  índice.  Los  
valores  más  altos  brindan  una  mejor  precisión,  pero  también  requieren  más  tiempo.  Si  desea  cambiar  el  valor,  pase  search_params  =  
dict(checks=100).

Con  esta  información,  estamos  listos  para  comenzar.

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

img1  =  cv2.imread('box.png',0)  #  consultaImagen  img2  =  cv2.imread('box_in_scene.png',0)  
#  trenImagen

#  Iniciar  detector  SIFT
tamizar  =  cv2.TAMINAR()

#  encuentre  los  puntos  clave  y  descriptores  con  SIFT  kp1,  des1  =  
sift.detectAndCompute(img1,None)  kp2,  des2  =  
sift.detectAndCompute(img2,None)

#  Parámetros  FLANN
FLANN_INDEX_KDTREE  =  0  
index_params  =  dict(algoritmo  =  FLANN_INDEX_KDTREE,  árboles  =  5)  search_params  =  
dict(checks=50)  #  o  pasar  diccionario  vacío

flann  =  cv2.FlannBasedMatcher(index_params,search_params)

coincidencias  =  flann.knnCoincidencia(des1,des2,k=2)

#  Necesita  dibujar  solo  buenas  coincidencias,  así  que  cree  una  máscara  
matchesMask  =  [[0,0]  for  i  in  xrange(len(matches))]

#  prueba  de  proporción  según  el  artículo  de  Lowe  
para  i,(m,n)  en  enumerar(coincidencias):
si  distancia  m  <  0.7*distancia  n:
máscara  de  coincidencias[i]=[1,0]

dibujar_parámetros  =  dict(matchColor  =  (0,255,0),
singlePointColor  =  (255,0,0),  MatchMask  =  
MatchMask,
banderas  =  0)

img3  =  cv2.drawMatchesKnn(img1,kp1,img2,kp2,coincidencias,Ninguno,**draw_params)

plt.imshow(img3,),plt.show()

Vea  el  resultado  a  continuación:

186 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

Ejercicios

Coincidencia  de  características  +  Homografía  para  encontrar  objetos

Meta

En  este  capítulo,

•  Combinaremos  la  combinación  de  características  y  findHomography  del  módulo  calib3d  para  encontrar  objetos  conocidos  en
una  imagen  compleja

Lo  esencial

Entonces,  ¿qué  hicimos  en  la  última  sesión?  Usamos  una  imagen  de  consulta,  encontramos  algunos  puntos  de  características  en  ella,  tomamos  otra  
imagen  de  tren,  encontramos  las  características  en  esa  imagen  también  y  encontramos  las  mejores  coincidencias  entre  ellas.  En  resumen,  encontramos  
ubicaciones  de  algunas  partes  de  un  objeto  en  otra  imagen  desordenada.  Esta  información  es  suficiente  para  encontrar  el  objeto  exactamente  en  la  imagen  del  tren.

Para  eso,  podemos  usar  una  función  del  módulo  calib3d,  es  decir,  cv2.findHomography().  Si  pasamos  el  conjunto  de  puntos  de  ambas  imágenes,  
encontrará  la  transformación  de  perspectiva  de  ese  objeto.  Luego  podemos  usar  cv2.perspectiveTransform()  para  encontrar  el  objeto.  Se  
necesitan  al  menos  cuatro  puntos  correctos  para  encontrar  la  transformación.

Hemos  visto  que  puede  haber  algunos  posibles  errores  durante  la  coincidencia  que  pueden  afectar  el  resultado.  Para  resolver  este  problema,  el  
algoritmo  usa  RANSAC  o  LAST_MEDIAN  (que  puede  decidirse  por  las  banderas).  Por  lo  tanto,  las  buenas  coincidencias  que  proporcionan  una  
estimación  correcta  se  denominan  valores  internos  y  las  restantes  se  denominan  valores  atípicos.  cv2.findHomography()  devuelve  una  máscara  
que  especifica  los  puntos  internos  y  externos.

Hagamoslo !!!

Código

Primero,  como  de  costumbre,  busquemos  características  SIFT  en  imágenes  y  apliquemos  la  prueba  de  proporción  para  encontrar  las  mejores  coincidencias.

1.5.  Detección  y  descripción  de  características 187
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

MIN_PARTIDO_CUENTA  =  10

img1  =  cv2.imread('box.png',0)  img2  =   #  consultaImagen  
cv2.imread('box_in_scene.png',0)  #  trenImagen

#  Iniciar  detector  SIFT
tamizar  =  cv2.TAMINAR()

#  encuentre  los  puntos  clave  y  descriptores  con  SIFT  kp1,  des1  =  
sift.detectAndCompute(img1,None)  kp2,  des2  =  
sift.detectAndCompute(img2,None)

FLANN_INDEX_KDTREE  =  0  
index_params  =  dict(algoritmo  =  FLANN_INDEX_KDTREE,  árboles  =  5)  search_params  =  
dict(comprobaciones  =  50)

flann  =  cv2.FlannBasedMatcher(index_params,  search_params)

coincidencias  =  flann.knnCoincidencia(des1,des2,k=2)

#  almacenar  todas  las  buenas  coincidencias  según  la  prueba  de  proporción  de  
Lowe.  bueno  
=  []  para  m,  n  en  coincidencias:
si  distancia  m  <  0.7*distancia  n:
bien.anexar(m)

Ahora  establecemos  una  condición  de  que  al  menos  10  coincidencias  (definidas  por  MIN_MATCH_COUNT)  deben  estar  allí  para  encontrar  el  objeto.
De  lo  contrario,  simplemente  muestre  un  mensaje  que  diga  que  no  hay  suficientes  coincidencias.

Si  se  encuentran  suficientes  coincidencias,  extraemos  las  ubicaciones  de  los  puntos  clave  coincidentes  en  ambas  imágenes.  Se  pasan  para  encontrar  la  
transformación  de  perspectiva.  Una  vez  que  obtengamos  esta  matriz  de  transformación  de  3x3,  la  usaremos  para  transformar  las  esquinas  de  queryImage  
en  los  puntos  correspondientes  en  trainImage.  Luego  lo  dibujamos.

si  len(bueno)>MIN_MATCH_COUNT:
src_pts  =  np.float32([ kp1[m.queryIdx].pt  for  m  in  good ]).reshape(­1,1,2)  dst_pts  =  np.float32([ kp2[m.trainIdx].pt  for  m  in  
good ]).reforma(­1,1,2)

M,  máscara  =  cv2.findHomography(src_pts,  dst_pts,  cv2.RANSAC,5.0)  coincidenciasMask  =  
máscara.ravel().tolist()

h,w  =  img1.shape  pts  =  
np.float32([ [0,0],[0,h­1],[w­1,h­1],[w­1,0] ]).  reshape( ­1,1,2)  dst  =  cv2.perspectiveTransform(pts,M)

img2  =  cv2.polylines(img2,[np.int32(dst)],Verdadero,255,3,  cv2.LINE_AA)

demás:
print  "No  se  encontraron  suficientes  coincidencias  ­  %d/%d"  %  (len(bien),MIN_MATCH_COUNT)
MatchMask  =  Ninguno

Finalmente,  dibujamos  nuestros  inliers  (si  encontramos  el  objeto  con  éxito)  o  los  puntos  clave  coincidentes  (si  fallamos).

draw_params  =  dict(matchColor  =  (0,255,0),  #  dibujar  coincidencias  en  color  verde
singlePointColor  =  Ninguno,

188 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

MatchMask  =  MatchMask,  #  dibujar  solo  banderas  internas  =  2)

img3  =  cv2.drawMatches(img1,kp1,img2,kp2,bueno,Ninguno,**draw_params)

plt.imshow(img3,  'gris'),plt.show()

Vea  el  resultado  a  continuación.  El  objeto  está  marcado  en  color  blanco  en  una  imagen  desordenada:

Recursos  adicionales

Ejercicios

Análisis  de  vídeo

•  Mediashift  y  Camshift

Ya  hemos  visto  un  ejemplo  de  seguimiento  basado  en  colores.  es  mas  simple
Esta  vez,  vemos  algoritmos  mucho  mejores  como  "Meanshift"  y  su  versión  mejorada,  
"Camshift"  para  encontrarlos  y  rastrearlos.

•  Flujo  óptico

1.6.  Análisis  de  vídeo 189
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Ahora  analicemos  un  concepto  importante,  "Flujo  óptico",  que  está  relacionado  con  
videos  y  tiene  muchas  aplicaciones.

•  Sustracción  de  fondo

En  varias  aplicaciones,  necesitamos  extraer  el  primer  plano  para  otras  operaciones  
como  el  seguimiento  de  objetos.  La  sustracción  de  fondo  es  un  método  bien  conocido  
en  esos  casos.

190 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Mediashift  y  Camshift

Meta

En  este  capítulo,

•  Aprenderemos  sobre  los  algoritmos  Meanshift  y  Camshift  para  encontrar  y  rastrear  objetos  en  videos.

cambio  de  media

La  intuición  detrás  del  cambio  de  media  es  simple.  Considere  que  tiene  un  conjunto  de  puntos.  (Puede  ser  una  distribución  de  píxeles  como  una  
retroproyección  de  histograma).  Aparece  una  pequeña  ventana  (puede  ser  un  círculo)  y  debe  mover  esa  ventana  al  área  de  máxima  densidad  de  
píxeles  (o  número  máximo  de  puntos).  Se  ilustra  en  la  imagen  simple  que  se  muestra  a  continuación:

La  ventana  inicial  se  muestra  en  un  círculo  azul  con  el  nombre  “C1”.  Su  centro  original  está  marcado  en  un  rectángulo  azul,  denominado  “C1_o”.  
Pero  si  encuentra  el  centroide  de  los  puntos  dentro  de  esa  ventana,  obtendrá  el  punto  "C1_r" (marcado  en  un  pequeño  círculo  azul)  que  es  el  
centroide  real  de  la  ventana.  Seguro  que  no  coinciden.  Así  que  mueva  su  ventana  de  manera  que  el  círculo  de  la  nueva  ventana  coincida  con  el  
centroide  anterior.  Nuevamente  encuentre  el  nuevo  centroide.  Lo  más  probable  es  que  no  coincida.  Así  que  muévalo  nuevamente  y  continúe  las  
iteraciones  de  manera  que  el  centro  de  la  ventana  y  su  centroide  caigan  en  la  misma  ubicación  (o  con  un  pequeño  error  deseado).  Entonces,  
finalmente,  lo  que  obtienes  es  una  ventana  con  la  máxima  distribución  de  píxeles.  Está  marcado  con  un  círculo  verde,  denominado  “C2”.  Como  
puede  ver  en  la  imagen,  tiene  un  número  máximo  de  puntos.  Todo  el  proceso  se  demuestra  en  una  imagen  estática  a  continuación:

Por  lo  tanto,  normalmente  pasamos  la  imagen  retroproyectada  del  histograma  y  la  ubicación  inicial  del  objetivo.  Cuando  el  objeto  se  mueve,  
obviamente  el  movimiento  se  refleja  en  la  imagen  retroproyectada  del  histograma.  Como  resultado,  el  algoritmo  de  desplazamiento  medio  mueve  
nuestra  ventana  a  la  nueva  ubicación  con  la  máxima  densidad.

1.6.  Análisis  de  vídeo 191
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Cambio  de  media  en  OpenCV

Para  usar  el  desplazamiento  medio  en  OpenCV,  primero  debemos  configurar  el  objetivo,  encontrar  su  histograma  para  que  podamos  retroproyectar  el  
objetivo  en  cada  cuadro  para  el  cálculo  del  desplazamiento  medio.  También  necesitamos  proporcionar  la  ubicación  inicial  de  la  ventana.  Para  el  
histograma,  aquí  solo  se  considera  Hue.  Además,  para  evitar  valores  falsos  debido  a  la  poca  luz,  los  valores  de  poca  luz  se  descartan  mediante  la  
función  cv2.inRange() .

importar  numpy  como  np  
importar  cv2

cap  =  cv2.VideoCapture('lento.flv')

#  toma  el  primer  fotograma  del  video  ret,frame  =  
cap.read()

#  configurar  la  ubicación  inicial  de  la  ventana  r,h,c,w  =  
250,90,400,125  #  simplemente  codificar  los  valores  track_window  =  (c,r,w,h)

#  configurar  el  ROI  para  el  seguimiento  roi  =  
frame[r:r+h,  c:c+w]  hsv_roi  =  
cv2.cvtColor(frame,  cv2.COLOR_BGR2HSV)  mask  =  cv2.inRange(hsv_roi,  
np.array((0. ,  60.,32.)),  np.array((180.,255.,255.)))  roi_hist  =  cv2.calcHist([hsv_roi],[0],máscara,[180],[0,180])  
cv2 .normalizar(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX)

#  Configure  los  criterios  de  finalización,  ya  sea  10  iteraciones  o  avance  al  menos  1  punto  term_crit  =  ( cv2.TERM_CRITERIA_EPS  
|  cv2.TERM_CRITERIA_COUNT,  10,  1 )

mientras(1):
derecha,  cuadro  =  cap.read()

si  ret  ==  Verdadero:
hsv  =  cv2.cvtColor(marco,  cv2.COLOR_BGR2HSV)
dst  =  cv2.calcBackProject([hsv],[0],roi_hist,[0,180],1)

#  aplicar  el  desplazamiento  medio  para  obtener  la  nueva  ubicación  
ret,  track_window  =  cv2.meanShift(dst,  track_window,  term_crit)

#  Dibujarlo  en  la  imagen  
x,y,w,h  =  track_window  img2  =  
cv2.rectangle(frame,  (x,y),  (x+w,y+h),  255,2)  cv2.imshow('img2',  img2)

k  =  cv2.waitKey(60)  &  0xff  si  k  ==  27:

romper
demás:
cv2.imwrite(chr(k)+".jpg",img2)

demás:
romper

cv2.destroyAllWindows()  cap.release()

Tres  cuadros  en  un  video  que  utilicé  se  dan  a  continuación:

192 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

1.6.  Análisis  de  vídeo 193
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Cambio  de  levas

¿Seguiste  de  cerca  el  último  resultado?  Hay  un  problema.  Nuestra  ventana  siempre  tiene  el  mismo  tamaño  cuando  el  coche  está  más  lejos  y  está  muy  cerca  de  
la  cámara.  Eso  no  es  bueno.  Necesitamos  adaptar  el  tamaño  de  la  ventana  con  el  tamaño  y  la  rotación  del  objetivo.  Una  vez  más,  la  solución  provino  de  "OpenCV  
Labs"  y  se  llama  CAMshift  (Continuously  Adaptive  Meanshift)  publicado  por  Gary  Bradsky  en  su  artículo  "Seguimiento  facial  de  visión  por  computadora  para  uso  
en  una  interfaz  de  usuario  perceptual"  en  1988.

También
Se  aplica  el  desplazamiento  medio  primero.  Una  vez  que  el  desplazamiento  medio  converge,  actualiza  el  tamaño  de  la  ventana  como,  =  2  ×  √   0256 .
0
calcula  la  orientación  de  la  elipse  que  mejor  se  ajusta  a  ella.  De  nuevo,  aplica  el  desplazamiento  medio  con  la  nueva  ventana  de  búsqueda  escalada  y  la  ubicación  
de  la  ventana  anterior.  El  proceso  continúa  hasta  que  se  alcanza  la  precisión  requerida.

Camshift  en  OpenCV

Es  casi  lo  mismo  que  el  cambio  medio,  pero  devuelve  un  rectángulo  rotado  (que  es  nuestro  resultado)  y  parámetros  de  cuadro  (solía  pasar  como  ventana  de  
búsqueda  en  la  siguiente  iteración).  Vea  el  código  a  continuación:

importar  numpy  como  np  
importar  cv2

cap  =  cv2.VideoCapture('lento.flv')

#  toma  el  primer  fotograma  del  video  ret,frame  =  
cap.read()

#  configurar  la  ubicación  inicial  de  la  ventana  r,h,c,w  =  
250,90,400,125  #  simplemente  codificar  los  valores  track_window  =  (c,r,w,h)

#  configurar  el  ROI  para  el  seguimiento  roi  =  
frame[r:r+h,  c:c+w]  hsv_roi  =  
cv2.cvtColor(frame,  cv2.COLOR_BGR2HSV)  mask  =  cv2.inRange(hsv_roi,  
np.array((0. ,  60.,32.)),  np.array((180.,255.,255.)))  roi_hist  =  cv2.calcHist([hsv_roi],[0],máscara,[180],[0,180])  
cv2 .normalizar(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX)

#  Configure  los  criterios  de  finalización,  ya  sea  10  iteraciones  o  avance  al  menos  1  punto  term_crit  =  
( cv2.TERM_CRITERIA_EPS  |  cv2.TERM_CRITERIA_COUNT,  10,  1 )

while(1):  
ret ,marco  =  cap.read()

si  ret  ==  Verdadero:
hsv  =  cv2.cvtColor(marco,  cv2.COLOR_BGR2HSV)  dst  =  
cv2.calcBackProject([hsv],[0],roi_hist,[0,180],1)

#  aplicar  el  desplazamiento  medio  para  obtener  la  nueva  ubicación  
ret,  track_window  =  cv2.CamShift(dst,  track_window,  term_crit)

#  Dibujarlo  en  la  imagen  pts  
=  cv2.boxPoints(ret)  pts  =  np.int0(pts)  
img2  =  cv2.polylines(frame,
[pts],True,  255,2)  cv2.imshow('img2',img2)

194 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

k  =  cv2.waitKey(60)  &  0xff  si  k  ==  27:

romper
demás:
cv2.imwrite(chr(k)+".jpg",img2)

demás:
romper

cv2.destroyAllWindows()  
cap.release()

A  continuación  se  muestran  tres  fotogramas  del  resultado:

1.6.  Análisis  de  vídeo 195
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

196 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

1.  Página  de  Wikipedia  en  francés  sobre  Camshift.  (Las  dos  animaciones  están  tomadas  de  aquí)

2.  Bradski,  GR,  "Seguimiento  de  rostros  y  objetos  en  tiempo  real  como  componente  de  una  interfaz  de  usuario  perceptual",  Aplicaciones  
de  visión  por  computadora,  1998.  WACV  '98.  Actas.,  Cuarto  Taller  IEEE  sobre,  vol.,  no.,  pp.214,219,  19­21  de  octubre  de  1998

Ejercicios

1.  OpenCV  viene  con  una  muestra  de  Python  en  una  demostración  interactiva  de  camshift.  Úsalo,  hackéalo,  entiéndelo.

Flujo  óptico

Meta

En  este  capítulo,

•  Comprenderemos  los  conceptos  de  flujo  óptico  y  su  estimación  mediante  el  método  de  Lucas­Kanade.

•  Usaremos  funciones  como  cv2.calcOpticalFlowPyrLK()  para  rastrear  puntos  característicos  en  un  video.

Flujo  óptico

El  flujo  óptico  es  el  patrón  de  movimiento  aparente  de  los  objetos  de  la  imagen  entre  dos  fotogramas  consecutivos  causados  por  el  
movimiento  del  objeto  o  la  cámara.  Es  un  campo  vectorial  2D  donde  cada  vector  es  un  vector  de  desplazamiento  que  muestra  el  movimiento  
de  los  puntos  desde  el  primer  cuadro  al  segundo.  Considere  la  imagen  a  continuación  (Imagen  cortesía:  artículo  de  Wikipedia  sobre  flujo  óptico).

Muestra  una  pelota  moviéndose  en  5  fotogramas  consecutivos.  La  flecha  muestra  su  vector  de  desplazamiento.  El  flujo  óptico  tiene  muchas  
aplicaciones  en  áreas  como:

•  Estructura  de  movimiento

•  Compresión  de  video

•  Estabilización  de  vídeo ...

El  flujo  óptico  funciona  en  varios  supuestos:

1.  Las  intensidades  de  píxeles  de  un  objeto  no  cambian  entre  fotogramas  consecutivos.

1.6.  Análisis  de  vídeo 197
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

2.  Los  píxeles  vecinos  tienen  un  movimiento  similar.

Considere  un  píxel  ( , , )  en  el  primer  cuadro  (compruebe  que  aquí  se  agrega  una  nueva  dimensión,  el  tiempo.  Anteriormente  trabajábamos  solo  con  
, el  siguiente  cuadro  tomado  después  del  tiempo.  Entonces,  dado  que  esos  
imágenes,  por  lo  que  no  necesitamos  tiempo).  Se  mueve  por  distancia  ( )  en  
píxeles  son  los  mismos  y  la  intensidad  no  cambia,  podemos  decir:

( , , )  =  ( + , + , + )

Luego  tome  la  aproximación  de  la  serie  de  Taylor  del  lado  derecho,  elimine  los  términos  comunes  y  divida  entre  para  obtener  la  siguiente  
ecuación:

+  +  =  0

dónde:

∂ ∂
= ;  =
∂ ∂

= ;  =

La  ecuación  anterior  se  llama  ecuación  de  flujo  óptico.  En  él  podemos  encontrar  y ,  son  degradados  de  imagen.  De  manera  similar  es  
el  gradiente  a  lo  largo  del  tiempo.  Pero  ( , )  es  desconocido.  No  podemos  resolver  esta  ecuación  con  dos  variables  desconocidas.  Así  que  
se  proporcionan  varios  métodos  para  resolver  este  problema  y  uno  de  ellos  es  Lucas­Kanade.

Método  Lucas­Kanade

Hemos  visto  una  suposición  antes,  que  todos  los  píxeles  vecinos  tendrán  un  movimiento  similar.  El  método  de  Lucas­Kanade  toma  un  parche  de  
, Así  que  ahora  
3x3  alrededor  del  punto.  Entonces  todos  los  9  puntos  tienen  el  mismo  movimiento.  Podemos  encontrar  ( , )  para  estos  9  puntos.  
nuestro  problema  se  convierte  en  resolver  9  ecuaciones  con  dos  variables  desconocidas  que  están  sobredeterminadas.  Se  obtiene  una  mejor  
solución  con  el  método  de  ajuste  de  mínimos  cuadrados.  A  continuación  se  muestra  la  solución  final,  que  es  un  problema  desconocido  de  dos  
ecuaciones  y  dos,  y  se  resuelve  para  obtener  la  solución.

2
2 ]−1  [  −  ∑
[  ]   =  [ ∑ ∑ ∑   ∑ −  ∑ ]

(Verifique  la  similitud  de  la  matriz  inversa  con  el  detector  de  esquinas  de  Harris.  Denota  que  las  esquinas  son  mejores  puntos  para  rastrear).

Entonces,  desde  el  punto  de  vista  del  usuario,  la  idea  es  simple,  damos  algunos  puntos  para  rastrear,  recibimos  los  vectores  de  flujo  óptico  de  
esos  puntos.  Pero  de  nuevo  hay  algunos  problemas.  Hasta  ahora,  tratábamos  de  pequeños  movimientos.  Entonces  falla  cuando  hay  un  gran  
movimiento.  Así  que  de  nuevo  vamos  por  las  pirámides.  Cuando  subimos  en  la  pirámide,  los  pequeños  movimientos  se  eliminan  y  los  grandes  
movimientos  se  convierten  en  pequeños  movimientos.  Entonces,  aplicando  Lucas­Kanade  allí,  obtenemos  flujo  óptico  junto  con  la  escala.

Flujo  óptico  de  Lucas­Kanade  en  OpenCV

OpenCV  proporciona  todo  esto  en  una  sola  función,  cv2.calcOpticalFlowPyrLK().  Aquí,  creamos  una  aplicación  simple  que  
rastrea  algunos  puntos  en  un  video.  Para  decidir  los  puntos,  usamos  cv2.goodFeaturesToTrack().  Tomamos  el  primer  cuadro,  
detectamos  algunos  puntos  de  esquina  de  Shi­Tomasi  en  él,  luego  rastreamos  iterativamente  esos  puntos  usando  el  flujo  óptico  
de  Lucas­Kanade.  Para  la  función  cv2.calcOpticalFlowPyrLK()  pasamos  el  cuadro  anterior,  los  puntos  anteriores  y  el  cuadro  siguiente.
Devuelve  los  siguientes  puntos  junto  con  algunos  números  de  estado  que  tienen  un  valor  de  1  si  se  encuentra  el  siguiente  punto,  de  lo  contrario,  cero.  Pasamos  
iterativamente  estos  puntos  siguientes  como  puntos  anteriores  en  el  paso  siguiente.  Vea  el  código  a  continuación:

importar  numpy  como  np  
importar  cv2

cap  =  cv2.VideoCapture('lento.flv')

198 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

#  parámetros  para  la  detección  de  esquinas  de  ShiTomasi  
feature_params  =  dict( maxCorners  =  100,
nivel  de  calidad  =  0.3,  distancia  
mínima  =  7,  tamaño  de  
bloque  =  7 )

#  Parámetros  para  el  flujo  óptico  de  lucas  kanade  lk_params  =  dict( winSize  
=  (15,15),  maxLevel  =  2,

criterio  =  (cv2.TERM_CRITERIA_EPS  |  cv2.TERM_CRITERIA_COUNT,  10,  0.
→03))

#  Crea  algunos  colores  aleatorios  color  =  
np.random.randint(0,255,(100,3))

#  Toma  el  primer  cuadro  y  encuentra  las  esquinas  en  él
ret,  old_frame  =  cap.read()  old_gray  =  
cv2.cvtColor(old_frame,  cv2.COLOR_BGR2GRAY)  p0  =  cv2.goodFeaturesToTrack(old_gray,  
mask  =  None,  **feature_params)

#  Crear  una  imagen  de  máscara  para  fines  de  dibujo  mask  =  
np.zeros_like(old_frame)

while(1):  
ret,frame  =  cap.read()  frame_gray  =  
cv2.cvtColor(frame,  cv2.COLOR_BGR2GRAY)

#  calcula  el  flujo  óptico  p1,  st,  err  =  
cv2.calcOpticalFlowPyrLK(old_gray,  frame_gray,  p0,  None,  **lk_   →params)

#  Seleccionar  buenos  puntos  
good_new  =  p1[st==1]  good_old  =  
p0[st==1]

#  dibujar  las  pistas  para  i,
(nuevo,viejo)  en  enumerate(zip(bueno_nuevo,bueno_viejo)):
a,b  =  nuevo.ravel()
c,d  =  old.ravel()  máscara  =  
cv2.line(máscara,  (a,b),(c,d),  color[i].tolist(),  2)  marco  =  cv2.circle(marco,(a ,b),5,color[i].tolist(),­1)

img  =  cv2.add(marco,máscara)

cv2.imshow('marco',img)  k  =  
cv2.waitKey(30)  &  0xff  si  k  ==  27:

romper

#  Ahora  actualice  el  marco  anterior  y  los  puntos  anteriores  old_gray  =  frame_gray.copy()  p0  
=  good_new.reshape(­1,1,2)

cv2.destroyAllWindows()  cap.release()

(Este  código  no  verifica  qué  tan  correctos  son  los  siguientes  puntos  clave.  Por  lo  tanto,  incluso  si  algún  punto  característico  desaparece  en  la  imagen,  existe  
la  posibilidad  de  que  el  flujo  óptico  encuentre  el  siguiente  punto  que  puede  parecer  cercano  a  él.  Entonces,  en  realidad  para  un  seguimiento  sólido,  esquina

1.6.  Análisis  de  vídeo 199
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

los  puntos  deben  ser  detectados  en  intervalos  particulares.  Las  muestras  de  OpenCV  presentan  una  muestra  de  este  tipo  que  encuentra  los  puntos  
característicos  en  cada  5  fotogramas.  También  ejecuta  una  verificación  hacia  atrás  de  los  puntos  de  flujo  óptico  para  seleccionar  solo  los  buenos.
Compruebe  samples/python2/lk_track.py).

Vea  los  resultados  que  obtuvimos:

Flujo  óptico  denso  en  OpenCV

El  método  de  Lucas­Kanade  calcula  el  flujo  óptico  para  un  conjunto  de  características  dispersas  (en  nuestro  ejemplo,  las  esquinas  se  detectaron  
con  el  algoritmo  de  Shi  Tomasi).  OpenCV  proporciona  otro  algoritmo  para  encontrar  el  flujo  óptico  denso.  Calcula  el  flujo  óptico  para  todos  los  
puntos  en  el  cuadro.  Se  basa  en  el  algoritmo  de  Gunner  Farneback  que  se  explica  en  "Estimación  de  movimiento  de  dos  fotogramas  basada  en  
expansión  polinomial"  por  Gunner  Farneback  en  2003.

El  siguiente  ejemplo  muestra  cómo  encontrar  el  flujo  óptico  denso  utilizando  el  algoritmo  anterior.  Obtenemos  una  matriz  de  2  canales  con  vectores  
de  flujo  óptico,  ( , ).  Encontramos  su  magnitud  y  dirección.  Codificamos  con  colores  el  resultado  para  una  mejor  visualización.  La  dirección  
corresponde  al  valor  Hue  de  la  imagen.  La  magnitud  corresponde  al  plano  de  valor.  Vea  el  código  a  continuación:

importar  cv2  
importar  numpy  como  np  
cap  =  cv2.VideoCapture("vtest.avi")

ret,  frame1  =  cap.read()  prvs  =  
cv2.cvtColor(frame1,cv2.COLOR_BGR2GRAY)  hsv  =  np.zeros_like(frame1)  
hsv[...,1]  =  255

while(1):  ret,  
frame2  =  cap.read()  next  =  
cv2.cvtColor(frame2,cv2.COLOR_BGR2GRAY)

flujo  =  cv2.calcOpticalFlowFarneback(prvs,siguiente,  Ninguno,  0.5,  3,  15,  3,  5,  1.2,  0)

mag,  ang  =  cv2.cartToPolar(flujo[...,0],  flujo[...,1])

200 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

hsv[...,0]  =  ang*180/np.pi/2  hsv[...,2]  =  
cv2.normalize(mag,Ninguno,0,255,cv2.NORM_MINMAX)  rgb  =  cv2.cvtColor(hsv,cv2 .COLOR_HSV2BGR)

cv2.imshow('frame2',rgb)  k  =  
cv2.waitKey(30)  &  0xff  si  k  ==  27:

romper
elif  k  ==  palabra('s'):
cv2.imwrite('opticalfb.png',frame2)  
cv2.imwrite('opticalhsv.png',rgb)
prvs  =  siguiente

cap.release()  
cv2.destroyAllWindows()

Vea  el  resultado  a  continuación:

1.6.  Análisis  de  vídeo 201
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

OpenCV  viene  con  una  muestra  más  avanzada  sobre  flujo  óptico  denso,  consulte  samples/python2/opt_flow.
pi.

202 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

Ejercicios

1.  Verifique  el  código  en  samples/python2/lk_track.py.  Trate  de  entender  el  código.

2.  Verifique  el  código  en  samples/python2/opt_flow.py.  Trate  de  entender  el  código.

Resta  de  fondo
Meta

En  este  capítulo,

•  Nos  familiarizaremos  con  los  métodos  de  sustracción  de  fondo  disponibles  en  OpenCV.

Lo  esencial

La  sustracción  de  fondo  es  uno  de  los  principales  pasos  de  preprocesamiento  en  muchas  aplicaciones  basadas  en  visión.  Por  ejemplo,  
considere  los  casos  como  el  contador  de  visitantes  donde  una  cámara  estática  registra  el  número  de  visitantes  que  ingresan  o  salen  de  la  
habitación,  o  una  cámara  de  tráfico  que  extrae  información  sobre  los  vehículos,  etc.  En  todos  estos  casos,  primero  debe  extraer  solo  a  la  
persona  o  los  vehículos. .  Técnicamente,  debe  extraer  el  primer  plano  en  movimiento  del  fondo  estático.

Si  tiene  una  imagen  de  fondo  sola,  como  la  imagen  de  la  habitación  sin  visitantes,  la  imagen  de  la  carretera  sin  vehículos,  etc.,  es  un  
trabajo  fácil.  Simplemente  reste  la  nueva  imagen  del  fondo.  Obtienes  los  objetos  de  primer  plano  solos.  Pero  en  la  mayoría  de  los  casos,  
es  posible  que  no  tenga  esa  imagen,  por  lo  que  debemos  extraer  el  fondo  de  cualquier  imagen  que  tengamos.  Se  vuelve  más  complicado  
cuando  hay  sombra  de  los  vehículos.  Dado  que  la  sombra  también  se  está  moviendo,  la  simple  resta  marcará  eso  también  como  primer  
plano.  Complica  las  cosas.

Se  introdujeron  varios  algoritmos  para  este  propósito.  OpenCV  ha  implementado  tres  algoritmos  de  este  tipo  que  son  muy  fáciles  de  usar.  
Los  veremos  uno  por  uno.

FondoSubtractorMOG

Es  un  algoritmo  de  segmentación  de  fondo/primer  plano  basado  en  una  mezcla  gaussiana.  Fue  presentado  en  el  documento  "Un  modelo  
de  mezcla  de  fondo  adaptativo  mejorado  para  seguimiento  en  tiempo  real  con  detección  de  sombras"  por  P.  KadewTraKuPong  y  R.  
Bowden  en  2001.  Utiliza  un  método  para  modelar  cada  píxel  de  fondo  mediante  una  mezcla  de  distribuciones  K  Gaussianas  ( K  =  3  a  5).  
Los  pesos  de  la  mezcla  representan  las  proporciones  de  tiempo  que  esos  colores  permanecen  en  la  escena.  Los  colores  de  fondo  
probables  son  los  que  permanecen  más  tiempo  y  más  estáticos.

Mientras  codificamos,  necesitamos  crear  un  objeto  de  fondo  usando  la  función,  cv2.createBackgroundSubtractorMOG().
Tiene  algunos  parámetros  opcionales  como  la  duración  del  historial,  el  número  de  mezclas  gaussianas,  el  umbral,  etc.  Todo  está  configurado  con  
algunos  valores  predeterminados.  Luego,  dentro  del  bucle  de  video,  use  el  método  backgroundsubtractor.apply()  para  obtener  la  máscara  de  
primer  plano.

Vea  un  ejemplo  simple  a  continuación:

importar  numpy  como  np  
importar  cv2

tapa  =  cv2.VideoCapture('vtest.avi')

fgbg  =  cv2.createBackgroundSubtractorMOG()

mientras(1):

1.6.  Análisis  de  vídeo 203
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

derecha,  cuadro  =  cap.read()

fgmask  =  fgbg.apply(marco)

cv2.imshow('marco',fgmask)  k  =  
cv2.waitKey(30)  &  0xff  si  k  ==  27:

romper

cap.release()  
cv2.destroyAllWindows()

(Todos  los  resultados  se  muestran  al  final  para  comparar).

FondoSubtractorMOG2

También  es  un  algoritmo  de  segmentación  de  fondo/primer  plano  basado  en  una  mezcla  gaussiana.  Se  basa  en  dos  artículos  
de  Z.Zivkovic,  "Modelo  de  mezcla  gausiana  adaptable  mejorado  para  la  sustracción  de  fondo"  en  2004  y  "Estimación  de  densidad  
adaptativa  eficiente  por  píxel  de  imagen  para  la  tarea  de  sustracción  de  fondo"  en  2006.  Una  característica  importante  de  este  
algoritmo  es  que  selecciona  el  número  apropiado  de  distribución  gaussiana  para  cada  píxel.  (Recuerde,  en  el  último  caso,  
tomamos  una  K  distribuciones  gaussianas  a  lo  largo  del  algoritmo).  Proporciona  una  mejor  adaptabilidad  a  diferentes  escenas  
debido  a  cambios  de  iluminación,  etc.

Como  en  el  caso  anterior,  tenemos  que  crear  un  objeto  sustractor  de  fondo.  Aquí,  tiene  la  opción  de  seleccionar  si  la  sombra  se  
detectará  o  no.  Si  detectShadows  =  True  (que  es  así  por  defecto),  detecta  y  marca  sombras,  pero  disminuye  la  velocidad.  Las  
sombras  se  marcarán  en  color  gris.

importar  numpy  como  np  
importar  cv2

tapa  =  cv2.VideoCapture('vtest.avi')

fgbg  =  cv2.createBackgroundSubtractorMOG2()

while(1):  ret,  
cuadro  =  cap.read()

fgmask  =  fgbg.apply(marco)

cv2.imshow('marco',fgmask)  k  =  
cv2.waitKey(30)  &  0xff  si  k  ==  27:

romper

cap.release()  
cv2.destroyAllWindows()

(Resultados  dados  al  final)

FondoSubtractorGMG

Este  algoritmo  combina  la  estimación  estadística  de  la  imagen  de  fondo  y  la  segmentación  bayesiana  por  píxel.  Fue  presentado  
por  Andrew  B.  Godbehere,  Akihiro  Matsukawa,  Ken  Goldberg  en  su  artículo  "Seguimiento  visual  de  visitantes  humanos  bajo  
condiciones  de  iluminación  variable  para  una  instalación  de  arte  de  audio  sensible"  en  2012.  Según  el  artículo,  el

204 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

El  sistema  ejecutó  una  exitosa  instalación  de  arte  de  audio  interactivo  llamada  "¿Ya  llegamos?"  del  31  de  marzo  al  31  de  julio  de  2011  en  el  Museo  
Judío  Contemporáneo  de  San  Francisco,  California.

Utiliza  los  primeros  fotogramas  (120  por  defecto)  para  el  modelado  de  fondo.  Emplea  un  algoritmo  de  segmentación  de  primer  plano  probabilístico  
que  identifica  posibles  objetos  de  primer  plano  mediante  la  inferencia  bayesiana.  Las  estimaciones  son  adaptativas;  las  observaciones  más  nuevas  
tienen  un  mayor  peso  que  las  observaciones  antiguas  para  adaptarse  a  la  iluminación  variable.  Se  realizan  varias  operaciones  de  filtrado  
morfológico,  como  el  cierre  y  la  apertura,  para  eliminar  el  ruido  no  deseado.  Obtendrá  una  ventana  negra  durante  los  primeros  cuadros.

Sería  mejor  aplicar  apertura  morfológica  al  resultado  para  eliminar  los  ruidos.

importar  numpy  como  np  
importar  cv2

tapa  =  cv2.VideoCapture('vtest.avi')

kernel  =  cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))  fgbg  =  
cv2.createBackgroundSubtractorGMG()

while(1):  ret,  
cuadro  =  cap.read()

fgmask  =  fgbg.apply(marco)  fgmask  =  
cv2.morphologyEx(fgmask,  cv2.MORPH_OPEN,  kernel)

cv2.imshow('marco',fgmask)  k  =  
cv2.waitKey(30)  &  0xff  si  k  ==  27:

romper

cap.release()  
cv2.destroyAllWindows()

Resultados

marco  originales

La  imagen  de  abajo  muestra  el  cuadro  200  de  un  video

Resultado  de  BackgroundSubtractorMOG

1.6.  Análisis  de  vídeo 205
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Resultado  de  BackgroundSubtractorMOG2

La  región  de  color  gris  muestra  la  región  de  la  sombra.

Resultado  de  BackgroundSubtractorGMG

El  ruido  se  elimina  con  la  apertura  morfológica.

206 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

Ejercicios

Calibración  de  cámara  y  reconstrucción  3D

•  Calibración  de  la  cámara

Averigüemos  qué  tan  buena  es  nuestra  cámara.  ¿Hay  alguna  distorsión  en  las  imágenes  
tomadas  con  él?  Si  es  así,  ¿cómo  corregirlo?

•  Estimación  de  poses

Esta  es  una  pequeña  sección  que  lo  ayudará  a  crear  algunos  efectos  3D  geniales  con  el  
módulo  de  calibre.

•  Geometría  Epipolar

Comprendamos  la  geometría  epipolar  y  la  restricción  epipolar.

•  Mapa  de  profundidad  de  imágenes  estéreo

Extraiga  información  de  profundidad  de  imágenes  2D.

1.7.  Calibración  de  cámara  y  reconstrucción  3D 207
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Calibración  de  la  cámara

Meta

En  esta  sección,

•  Aprenderemos  sobre  distorsiones  en  la  cámara,  parámetros  intrínsecos  y  extrínsecos  de  la  cámara,  etc.

•  Aprenderemos  a  encontrar  estos  parámetros,  no  distorsionar  imágenes,  etc.

Lo  esencial

Las  cámaras  estenopeicas  baratas  de  hoy  introducen  mucha  distorsión  en  las  imágenes.  Dos  distorsiones  principales  son  la  distorsión  radial  y  la  
distorsión  tangencial.

Debido  a  la  distorsión  radial,  las  líneas  rectas  aparecerán  curvas.  Su  efecto  es  mayor  a  medida  que  nos  alejamos  del  centro  de  la  imagen.
Por  ejemplo,  a  continuación  se  muestra  una  imagen,  donde  dos  bordes  de  un  tablero  de  ajedrez  están  marcados  con  líneas  rojas.  Pero  puedes  ver  
que  el  borde  no  es  una  línea  recta  y  no  coincide  con  la  línea  roja.  Todas  las  líneas  rectas  esperadas  están  abultadas.
Visite  Distorsión  (óptica)  para  más  detalles.

208 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Esta  distorsión  se  resuelve  de  la  siguiente  manera:

2 +  2 4 6
=  (1  +  1  =   +  3 )
2 +  2 4 6
(1  +  1 +  3 )

De  forma  similar,  otra  distorsión  es  la  distorsión  tangencial  que  se  produce  porque  la  lente  de  toma  de  imágenes  no  está  alineada  perfectamente  paralela  al  
plano  de  formación  de  imágenes.  Por  lo  tanto,  algunas  áreas  de  la  imagen  pueden  verse  más  cerca  de  lo  esperado.  Se  resuelve  de  la  siguiente  manera:

2 +  2 2
=  +  [2  1  +  2(
2 +  2 2
=  +  [ 1( )  +  2 2 )] ]

En  resumen,  necesitamos  encontrar  cinco  parámetros,  conocidos  como  coeficientes  de  distorsión  dados  por:

=  ( 1 2 1  2 3)

Además  de  esto,  necesitamos  encontrar  un  poco  más  de  información,  como  los  parámetros  intrínsecos  y  extrínsecos  de  una  cámara.  Los  
, ( ),  centros  ópticos  ( )  etc.  E,s
parámetros  intrínsecos  son  específicos  de  una  cámara.  Incluye  información  como  distancia  focal  

1.7.  Calibración  de  cámara  y  reconstrucción  3D 209
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

también  llamada  matriz  de  cámara.  Depende  únicamente  de  la  cámara,  por  lo  que  una  vez  calculada,  se  puede  almacenar  para  fines  futuros.  Se  expresa  
como  una  matriz  de  3x3:

0
= 0
0  0  1
     

Los  parámetros  extrínsecos  corresponden  a  los  vectores  de  rotación  y  traslación  que  traducen  las  coordenadas  de  un  punto  3D  a  un  sistema  de  coordenadas.

Para  aplicaciones  estéreo,  estas  distorsiones  deben  corregirse  primero.  Para  encontrar  todos  estos  parámetros,  lo  que  tenemos  que  hacer  es  proporcionar  
algunas  imágenes  de  muestra  de  un  patrón  bien  definido  (por  ejemplo,  un  tablero  de  ajedrez).  Encontramos  algunos  puntos  específicos  en  él  (esquinas  
cuadradas  en  tablero  de  ajedrez).  Conocemos  sus  coordenadas  en  el  espacio  del  mundo  real  y  conocemos  sus  coordenadas  en  la  imagen.  Con  estos  datos  
se  resuelve  en  segundo  plano  algún  problema  matemático  para  obtener  los  coeficientes  de  distorsión.  Ese  es  el  resumen  de  toda  la  historia.  Para  obtener  
mejores  resultados,  necesitamos  al  menos  10  patrones  de  prueba.

Código

Como  se  mencionó  anteriormente,  necesitamos  al  menos  10  patrones  de  prueba  para  la  calibración  de  la  cámara.  OpenCV  viene  con  algunas  imágenes  del  
tablero  de  ajedrez  (ver  samples/cpp/left01.jpg  ­­  left14.jpg),  así  que  lo  utilizaremos.  En  aras  de  la  comprensión,  considere  solo  una  imagen  de  un  tablero  de  
ajedrez.  Los  datos  de  entrada  importantes  necesarios  para  la  calibración  de  la  cámara  son  un  conjunto  de  puntos  del  mundo  real  en  3D  y  sus  correspondientes  
puntos  de  imagen  en  2D.  Los  puntos  de  imagen  2D  están  bien  y  podemos  encontrarlos  fácilmente  en  la  imagen.  (Estos  puntos  de  imagen  son  ubicaciones  
donde  dos  cuadrados  negros  se  tocan  en  tableros  de  ajedrez)

¿Qué  pasa  con  los  puntos  3D  del  espacio  del  mundo  real?  Esas  imágenes  se  toman  de  una  cámara  estática  y  los  tableros  de  ajedrez  se  colocan  en  
diferentes  ubicaciones  y  orientaciones.  Entonces  necesitamos  saber  los  valores  ( , ).  Pero  para  ,simplificar,  podemos  decir  que  el  tablero  de  ajedrez  se  
mantuvo  estacionario  en  el  plano  XY  (por  lo  que  siempre  Z  =  0)  y  la  cámara  se  movió  en  consecuencia.  Esta  consideración  nos  ayuda  a  encontrar  solo  
valores  X,Y.  Ahora,  para  los  valores  X,Y,  simplemente  podemos  pasar  los  puntos  como  (0,0),  (1,0),  (2,0), ...  lo  que  denota  la  ubicación  de  los  puntos.  En  
este  caso,  los  resultados  que  obtendremos  estarán  en  la  escala  del  tamaño  del  tablero  de  ajedrez.  Pero  si  conocemos  el  tamaño  del  cuadrado,  (digamos  30  
mm),  y  podemos  pasar  los  valores  como  (0,0),(30,0),(60,0),...,  obtenemos  los  resultados  en  mm.
(En  este  caso,  no  sabemos  el  tamaño  del  cuadrado  ya  que  no  tomamos  esas  imágenes,  así  que  pasamos  en  términos  de  tamaño  del  cuadrado).

Los  puntos  3D  se  denominan  puntos  de  objeto  y  los  puntos  de  imagen  2D  se  denominan  puntos  de  imagen.

Configuración

Entonces,  para  encontrar  un  patrón  en  el  tablero  de  ajedrez,  usamos  la  función  cv2.findChessboardCorners().  También  necesitamos  pasar  qué  tipo  de  
patrón  estamos  buscando,  como  una  cuadrícula  de  8x8,  una  cuadrícula  de  5x5,  etc.  En  este  ejemplo,  usamos  una  cuadrícula  de  7x6.  (Normalmente,  un  
tablero  de  ajedrez  tiene  cuadrados  de  8x8  y  esquinas  internas  de  7x7).  Devuelve  los  puntos  de  las  esquinas  y  el  retval,  que  será  Verdadero  si  se  obtiene  el  patrón.
Estas  esquinas  se  colocarán  en  un  orden  (de  izquierda  a  derecha,  de  arriba  a  abajo)

Ver  también:

Es  posible  que  esta  función  no  pueda  encontrar  el  patrón  requerido  en  todas  las  imágenes.  Entonces,  una  buena  opción  es  escribir  el  código  de  tal  manera  
que  inicie  la  cámara  y  verifique  cada  cuadro  para  el  patrón  requerido.  Una  vez  obtenido  el  patrón,  busque  las  esquinas  y  guárdelo  en  una  lista.  También  
proporciona  un  intervalo  antes  de  leer  el  siguiente  cuadro  para  que  podamos  ajustar  nuestro  tablero  de  ajedrez  en  una  dirección  diferente.  Continúe  este  
proceso  hasta  obtener  el  número  requerido  de  buenos  patrones.  Incluso  en  el  ejemplo  proporcionado  aquí,  no  estamos  seguros  de  las  14  imágenes  dadas,  
cuántas  son  buenas.  Así  que  leemos  todas  las  imágenes  y  tomamos  las  buenas.

Ver  también:

En  lugar  de  un  tablero  de  ajedrez,  podemos  usar  una  cuadrícula  circular,  pero  luego  usamos  la  función  cv2.findCirclesGrid()  para  encontrar  el  patrón.  Se  
dice  que  una  menor  cantidad  de  imágenes  es  suficiente  cuando  se  usa  una  cuadrícula  circular.

Una  vez  que  encontramos  las  esquinas,  podemos  aumentar  su  precisión  usando  cv2.cornerSubPix().  También  podemos  dibujar  el  patrón  usando  
cv2.drawChessboardCorners().  Todos  estos  pasos  están  incluidos  en  el  siguiente  código:

210 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

importar  numpy  como  np  
importar  cv2  
importar  glob

#  criterios  de  terminación
criterio  =  (cv2.TERM_CRITERIA_EPS  +  cv2.TERM_CRITERIA_MAX_ITER,  30,  0.001)

#  preparar  puntos  de  objeto,  como  (0,0,0),  (1,0,0),  (2,0,0) ....,(6,5,0)  objp  =  np.zeros((6*  7,3),  np.float32)  objp[:,:2]  
=  np.mgrid[0:7,0:6].T.reshape(­1,2)

#  Matrices  para  almacenar  puntos  de  objetos  y  puntos  de  imagen  de  todas  las  imágenes.  objpoints  =  []  #  Punto  3d  
en  el  espacio  del  mundo  real  imgpoints  =  []  #  Puntos  2d  en  el  plano  de  la  
imagen.

imágenes  =  globo.glob('*.jpg')

para  fname  en  imágenes:  img  =  
cv2.imread(fname)  gray  =  
cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#  Encuentra  las  esquinas  del  tablero  de  ajedrez
ret,  esquinas  =  cv2.findChessboardCorners(gris,  (7,6),Ninguno)

#  Si  lo  encuentra,  agregue  puntos  de  objeto,  puntos  de  imagen  (después  de  refinarlos)  if  ret  ==  True:

puntosobj.append(objp)

esquinas2  =  cv2.cornerSubPix(gris,esquinas,(11,11),(­1,­1),criterios)  imgpoints.append(esquinas2)

#  Dibujar  y  mostrar  las  esquinas  img  =  
cv2.drawChessboardCorners(img,  (7,6),  corners2,ret)  cv2.imshow('img',img)  cv2.waitKey(500)

cv2.destroyAllWindows()

A  continuación  se  muestra  una  imagen  con  un  patrón  dibujado:

1.7.  Calibración  de  cámara  y  reconstrucción  3D 211
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Calibración

Entonces,  ahora  que  tenemos  nuestros  puntos  de  objeto  y  puntos  de  imagen,  estamos  listos  para  la  calibración.  Para  eso  usamos  la  
función,  cv2.calibrateCamera().  Devuelve  la  matriz  de  la  cámara,  los  coeficientes  de  distorsión,  los  vectores  de  rotación  y  traslación,  etc.

ret,  mtx,  dist,  rvecs,  tvecs  =  cv2.calibrateCamera(objpoints,  imgpoints,  gray.   →shape[::­1],Ninguno,Ninguno)

Sin  distorsión

Tenemos  lo  que  estábamos  intentando.  Ahora  podemos  tomar  una  imagen  y  no  distorsionarla.  OpenCV  viene  con  dos  métodos,  veremos  
ambos.  Pero  antes  de  eso,  podemos  refinar  la  matriz  de  la  cámara  en  función  de  un  parámetro  de  escalado  libre  usando

212 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

cv2.getOptimalNewCameraMatrix().  Si  el  parámetro  de  escala  alfa  =  0,  devuelve  una  imagen  sin  distorsiones  con  un  mínimo  de  píxeles  no  deseados.  Por  
lo  tanto,  incluso  puede  eliminar  algunos  píxeles  en  las  esquinas  de  la  imagen.  Si  alfa  =  1,  todos  los  píxeles  se  conservan  con  algunas  imágenes  negras  
adicionales.  También  devuelve  un  ROI  de  imagen  que  se  puede  usar  para  recortar  el  resultado.

Entonces  tomamos  una  nueva  imagen  (left12.jpg  en  este  caso.  Esa  es  la  primera  imagen  en  este  capítulo)

img  =  cv2.imread('left12.jpg')  h,  w  =  
img.shape[:2]  newcameramtx,  
roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))

1.  Usando  cv2.undistort()

Este  es  el  camino  más  corto.  Simplemente  llame  a  la  función  y  use  el  ROI  obtenido  anteriormente  para  recortar  el  resultado.

#  desdistorsionar
dst  =  cv2.undistort(img,  mtx,  dist,  None,  newcameramtx)

#  recortar  la  imagen  
x,y,w,h  =  roi  dst  =  
dst[y:y+h,  x:x+w]  
cv2.imwrite('calibresult.png',dst)

2.  Usando  la  reasignación

Este  es  un  camino  curvo.  Primero  encuentre  una  función  de  mapeo  de  imagen  distorsionada  a  imagen  no  distorsionada.  A  continuación,  utilice  la  función  de  
reasignación.

#  desdistorsionar
mapx,mapy  =  cv2.initUndistortRectifyMap(mtx,dist,None,newcameramtx,(w,h),5)  dst  =  
cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)

#  recortar  la  imagen  
x,y,w,h  =  roi  dst  =  
dst[y:y+h,  x:x+w]  
cv2.imwrite('calibresult.png',dst)

Ambos  métodos  dan  el  mismo  resultado.  Vea  el  resultado  a  continuación:

1.7.  Calibración  de  cámara  y  reconstrucción  3D 213
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Puedes  ver  en  el  resultado  que  todos  los  bordes  son  rectos.

Ahora  puede  almacenar  la  matriz  de  la  cámara  y  los  coeficientes  de  distorsión  usando  funciones  de  escritura  en  Numpy  (np.savez,  np.savetxt,  
etc.)  para  usos  futuros.

Error  de  reproyección

El  error  de  reproyección  da  una  buena  estimación  de  cuán  exactos  son  los  parámetros  encontrados.  Este  debe  ser  lo  más  cercano  a  cero  
posible.  Dadas  las  matrices  intrínseca,  distorsión,  rotación  y  traslación,  primero  transformamos  el  punto  del  objeto  en  el  punto  de  la  imagen  
usando  cv2.projectPoints().  Luego  calculamos  la  norma  absoluta  entre  lo  que  obtuvimos  con  nuestra  transformación  y  el  algoritmo  de  búsqueda  
de  esquinas.  Para  encontrar  el  error  promedio,  calculamos  la  media  aritmética  de  los  errores  calculados  para  todas  las  imágenes  de  calibración.

error_medio  =  0  para  
i  en  xrange(len(objpoints)):  imgpoints2,  _  error  =  
=  cv2.projectPoints(objpoints[i],  rvecs[i],  tvecs[i],  mtx,  dist)
cv2.norm(imgpoints[i],imgpoints2,  cv2.NORM_L2)/len(imgpoints2)  tot_error  +=  error

imprimir  "error  total:  ",  mean_error/len(objpoints)

Recursos  adicionales

Ejercicios

1.  Pruebe  la  calibración  de  la  cámara  con  cuadrícula  circular.

214 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Estimación  de  poses

Meta

En  esta  sección,

•  Aprenderemos  a  explotar  el  módulo  calib3d  para  crear  algunos  efectos  3D  en  las  imágenes.

Lo  esencial

Esta  va  a  ser  una  pequeña  sección.  Durante  la  última  sesión  de  calibración  de  la  cámara,  encontró  la  matriz  de  la  cámara,  los  coeficientes  de  
distorsión,  etc.  Dada  una  imagen  de  patrón,  podemos  utilizar  la  información  anterior  para  calcular  su  pose,  o  cómo  se  sitúa  el  objeto  en  el  espacio,  
por  ejemplo,  cómo  gira,  cómo  se  desplaza,  etc.  Para  un  objeto  plano,  podemos  asumir  Z  =  0,  de  modo  que  el  problema  ahora  es  cómo  se  coloca  
la  cámara  en  el  espacio  para  ver  nuestra  imagen  de  patrón.  Entonces,  si  sabemos  cómo  se  encuentra  el  objeto  en  el  espacio,  podemos  dibujar  
algunos  diagramas  2D  para  simular  el  efecto  3D.  Veamos  cómo  hacerlo.

Nuestro  problema  es  que  queremos  dibujar  nuestro  eje  de  coordenadas  3D  (ejes  X,  Y,  Z)  en  la  primera  esquina  de  nuestro  tablero  de  ajedrez.  Eje  
X  en  color  azul,  eje  Y  en  color  verde  y  eje  Z  en  color  rojo.  Entonces,  en  efecto,  el  eje  Z  debería  sentirse  como  si  fuera  perpendicular  a  nuestro  plano  
de  tablero  de  ajedrez.

Primero,  carguemos  la  matriz  de  la  cámara  y  los  coeficientes  de  distorsión  del  resultado  de  la  calibración  anterior.

importar  cv2  
importar  numpy  como  np  
importar  glob

#  Cargue  datos  previamente  guardados  con  
np.load('B.npz')  como  X:  =  [X[i]  for  i  in  
mtx,  distancia,  _,  _ ('mtx','dist','rvecs','tvecs')]

Ahora  vamos  a  crear  una  función,  draw,  que  toma  las  esquinas  del  tablero  de  ajedrez  (obtenidas  usando  cv2.findChessboardCorners())  y  los  puntos  
del  eje  para  dibujar  un  eje  3D.

def  dibujar  (img,  esquinas,  imgpts):
esquina  =  tupla(esquinas[0].ravel())  img  =  cv2.line(img,  
esquina,  tupla(imgpts[0].ravel()),  (255,0,0),  5)  img  =  cv2.line  (img,  esquina,  tupla(imgpts[1].ravel()),  (0,255,0),  
5)  img  =  cv2.line(img,  esquina,  tupla(imgpts[2].ravel()),  (0,  0,255),  5)  devolver  img

Luego,  como  en  el  caso  anterior,  creamos  criterios  de  terminación,  puntos  de  objeto  (puntos  3D  de  esquinas  en  tablero  de  ajedrez)  y  puntos  de  
eje.  Los  puntos  del  eje  son  puntos  en  el  espacio  3D  para  dibujar  el  eje.  Dibujamos  un  eje  de  longitud  3  (las  unidades  serán  en  términos  del  tamaño  
del  cuadrado  de  ajedrez  ya  que  calibramos  en  función  de  ese  tamaño).  Entonces,  nuestro  eje  X  se  dibuja  de  (0,0,0)  a  (3,0,0),  así  que  para  el  eje  Y.
Para  el  eje  Z,  se  dibuja  de  (0,0,0)  a  (0,0,­3).  Negativo  denota  que  se  dibuja  hacia  la  cámara.

criterio  =  (cv2.TERM_CRITERIA_EPS  +  cv2.TERM_CRITERIA_MAX_ITER,  30,  0.001)  objp  =  np.zeros((6*7,3),  
np.float32)  objp[:,:2]  =  np.mgrid[0:7,0  :6].T.reformar(­1,2)

eje  =  np.float32([[3,0,0],  [0,3,0],  [0,0,­3]]).remodelar(­1,3)

Ahora,  como  de  costumbre,  cargamos  cada  imagen.  Busque  la  cuadrícula  de  7x6.  Si  se  encuentra,  lo  refinamos  con  píxeles  de  subesquina.  Luego,  
para  calcular  la  rotación  y  la  traslación,  usamos  la  función  cv2.solvePnPRansac().  Una  vez  que  tenemos  esas  matrices  de  transformación,  las  
usamos  para  proyectar  nuestros  puntos  de  eje  al  plano  de  la  imagen.  En  palabras  simples,  encontramos  los  puntos  en  el  plano  de  la  imagen  
correspondientes  a  cada  uno  de  (3,0,0),  (0,3,0),  (0,0,3)  en  el  espacio  3D.  Una  vez  que  los  conseguimos,  dibujamos  líneas  desde  la  primera  esquina  
hasta  cada  uno  de  estos  puntos  usando  nuestra  función  dibujar().  Hecho !!!

1.7.  Calibración  de  cámara  y  reconstrucción  3D 215
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

for  fname  in  glob.glob('left*.jpg'):  img  =  cv2.imread(fname)  
gray  =  
cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)  ret,  corners  =  
cv2.findChessboardCorners(gray,  (7,6) ,Ninguno)

si  ret  ==  Verdadero:
esquinas2  =  cv2.cornerSubPix(gris,esquinas,(11,11),(­1,­1),criterios)

#  Encuentra  los  vectores  de  rotación  y  traslación.  rvecs,  tvecs,  inliers  
=  cv2.solvePnPRansac(objp,  corners2,  mtx,  dist)

#  proyectar  puntos  3D  en  el  plano  de  la  imagen  
imgpts,  jac  =  cv2.projectPoints(axis,  rvecs,  tvecs,  mtx,  dist)

img  =  dibujar(img,esquinas2,imgpts)  
cv2.imshow('img',img)  k  =  
cv2.waitKey(0)  &  0xff  si  k  ==  's':

cv2.imwrite(fname[:6]+'.png',  img)

cv2.destroyAllWindows()

Vea  algunos  resultados  a  continuación.  Observe  que  cada  eje  tiene  3  cuadrados  de  largo.:

216 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Renderizar  un  cubo

Si  desea  dibujar  un  cubo,  modifique  la  función  dibujar()  y  los  puntos  del  eje  de  la  siguiente  manera.

Función  draw()  modificada:

def  dibujar(img,  esquinas,  imgpts):  imgpts  =  
np.int32(imgpts).reshape(­1,2)

#  dibujar  la  planta  baja  en  verde  img  =  
cv2.drawContours(img,  [imgpts[:4]],­1,(0,255,0),­3)

#  dibujar  pilares  en  color  azul  para  i,j  en  
zip(rango(4),rango(4,8)):  img  =  cv2.line(img,  
tuple(imgpts[i]),  tuple(imgpts[j]),  (255),3)

#  dibujar  la  capa  superior  en  color  rojo  img  =  
cv2.drawContours(img,  [imgpts[4:]],­1,(0,0,255),3)

1.7.  Calibración  de  cámara  y  reconstrucción  3D 217
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

devolver  imagen

Puntos  de  eje  modificados.  Son  las  8  esquinas  de  un  cubo  en  el  espacio  3D:

eje  =  np.float32([[0,0,0],  [0,3,0],  [3,3,0],  [3,0,0],
[0,0,­3],[0,3,­3],[3,3,­3],[3,0,­3] ] )

Y  mira  el  resultado  a  continuación:

Si  está  interesado  en  gráficos,  realidad  aumentada,  etc.,  puede  usar  OpenGL  para  representar  figuras  más  complicadas.

Recursos  adicionales

Ejercicios

Geometría  Epipolar

Meta

En  esta  sección,

•  Aprenderemos  sobre  los  conceptos  básicos  de  la  geometría  multivista.

•  Veremos  qué  es  el  epipolo,  las  líneas  epipolares,  la  restricción  epipolar,  etc.

Conceptos  básicos

Cuando  tomamos  una  imagen  con  una  cámara  estenopeica,  perdemos  una  información  importante,  es  decir,  la  profundidad  de  la  imagen.  
O  qué  tan  lejos  está  cada  punto  de  la  imagen  de  la  cámara  porque  es  una  conversión  de  3D  a  2D.  Entonces,  es  una  pregunta  importante  si  
podemos  encontrar  la  información  de  profundidad  usando  estas  cámaras.  Y  la  respuesta  es  usar  más  de  una  cámara.  Nuestros  ojos  
funcionan  de  manera  similar  cuando  usamos  dos  cámaras  (dos  ojos),  lo  que  se  denomina  visión  estéreo.  Entonces,  veamos  qué  ofrece  
OpenCV  en  este  campo.

(Learning  OpenCV  de  Gary  Bradsky  tiene  mucha  información  en  este  campo).

218 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Antes  de  profundizar  en  las  imágenes,  comprendamos  primero  algunos  conceptos  básicos  de  la  geometría  multivista.  En  esta  sección  nos  
ocuparemos  de  la  geometría  epipolar.  Vea  la  imagen  a  continuación  que  muestra  una  configuración  básica  con  dos  cámaras  tomando  la  imagen  
de  la  misma  escena.

Si  usamos  solo  la  cámara  izquierda,  no  podemos  encontrar  el  punto  3D  correspondiente  al  punto  en  la  imagen  porque  cada  punto  
en  la  línea  se  proyecta  al  mismo  punto  en  el  plano  de  la  imagen.  Pero  considere  también  la  imagen  correcta.  Ahora  diferentes  puntos  

en  la  línea  se  proyectan  a  diferentes  puntos  ( )  en  el  plano  recto.  Entonces,  con  estas  dos  imágenes,  podemos  triangular  el  punto  
3D  correcto.  Esta  es  toda  la  idea.

La  proyección  de  los  diferentes  puntos  sobre ).  Lo  llamamos   elpilina  
forman  una   ceorrespondiente  
ínea  en   ′ al  punto.
l  plano  derecho  (línea
Significa,  para  encontrar  el  punto  en  la  imagen  de  la  derecha,  buscar  a  lo  largo  de  esta  epilínea.  Debería  estar  en  algún  
lugar  de  esta  línea  (Piénselo  de  esta  manera,  para  encontrar  el  punto  de  coincidencia  en  otra  imagen,  no  necesita  buscar  en  toda  la  
imagen,  solo  busque  a  lo  largo  de  la  epilínea.  Por  lo  tanto,  proporciona  un  mejor  rendimiento  y  precisión).  Esto  se  llama  Restricción  

Epipolar.  De  igual  forma  todos  los  puntos  tendrán  sus  correspondientes  epilíneas  en  la  otra  imagen.  El  plano  se  llama  Plano  Epipolar.

y ′ son  los  centros  de  cámara.  A  partir  de  la  configuración  anterior,  puede  ver  que  la  proyección  de  la  cámara  derecha  se  v′e  en  la  
imagen  de  la  izquierda  en  el  punto . Se  llama  epipolo.  El  epipolo  es  el  punto  de  intersección  de  la  línea  a  través  de  los  centros  de  

la  cámara  y  los  planos  de  la  imagen.  Del  mismo  modo  es  el  epipolo  de  la  cámara  izquierda.  En  algunos  casos,  no  podrá  ubicar  el  
epipolo  en  la  imagen,  es  posible  que  estén  fuera  de  la  imagen  (lo  que  significa  que  una  cámara  no  ve  a  la  otra).

Todas  las  epilinas  pasan  por  su  epipolo.  Entonces,  para  encontrar  la  ubicación  del  epipolo,  podemos  encontrar  muchas  epilíneas  y  encontrar  su  
punto  de  intersección.

Entonces,  en  esta  sesión,  nos  enfocamos  en  encontrar  líneas  epipolares  y  epipolos.  Pero  para  encontrarlos,  necesitamos  dos  
ingredientes  más,  la  Matriz  Fundamental  (F)  y  la  Matriz  Esencial  (E).  Essential  Matrix  contiene  información  sobre  traslación  y  
rotación,  que  describen  la  ubicación  de  la  segunda  cámara  en  relación  con  la  primera  en  coordenadas  globales.  Vea  la  imagen  a  
continuación  (Imagen  cortesía:  Learning  OpenCV  por  Gary  Bradsky):

1.7.  Calibración  de  cámara  y  reconstrucción  3D 219
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Pero  preferimos  que  las  mediciones  se  realicen  en  coordenadas  de  píxeles,  ¿verdad?  Fundamental  Matrix  contiene  la  misma  información  que  
Essential  Matrix  además  de  la  información  sobre  los  elementos  intrínsecos  de  ambas  cámaras  para  que  podamos  relacionar  las  dos  cámaras  en  
coordenadas  de  píxeles.  (Si  estamos  usando  imágenes  rectificadas  y  normalizamos  el  punto  dividiendo  por  las  distancias  focales,  = ).  En  palabras  
simples,  la  Matriz  fundamental  F,  asigna  un  punto  en  una  imagen  a  una  línea  (epilina)  en  la  otra  imagen.
Esto  se  calcula  a  partir  de  los  puntos  coincidentes  de  ambas  imágenes.  Se  requiere  un  mínimo  de  8  puntos  de  este  tipo  para  encontrar  la  matriz  
fundamental  (mientras  se  utiliza  el  algoritmo  de  8  puntos).  Se  prefieren  más  puntos  y  se  usa  RANSAC  para  obtener  un  resultado  más  sólido.

Código

Entonces,  primero  debemos  encontrar  tantas  coincidencias  posibles  entre  dos  imágenes  para  encontrar  la  matriz  fundamental.  Para  esto,  usamos  
descriptores  SIFT  con  emparejador  basado  en  FLANN  y  prueba  de  proporción.

importar  cv2  
importar  numpy  como  np  
desde  matplotlib  importar  pyplot  como  plt

img1  =  cv2.imread('myleft.jpg',0)  #queryimage  #  imagen  izquierda  img2  =  
cv2.imread('myright.jpg',0)  #trainimage  #  imagen  derecha

tamizar  =  cv2.TAMINAR()

#  encuentre  los  puntos  clave  y  descriptores  con  SIFT  kp1,  des1  =  
sift.detectAndCompute(img1,None)  kp2,  des2  =  
sift.detectAndCompute(img2,None)

#  Parámetros  FLANN
FLANN_INDEX_KDTREE  =  0  
index_params  =  dict(algoritmo  =  FLANN_INDEX_KDTREE,  árboles  =  5)  search_params  =  
dict(checks=50)

flann  =  cv2.FlannBasedMatcher(index_params,search_params)  coincidencias  =  
flann.knnMatch(des1,des2,k=2)

bueno  =  []  
pts1  =  []

220 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

ptos2  =  []

#  prueba  de  proporción  según  el  artículo  de  Lowe  
para  i,(m,n)  en  enumerar(coincidencias):
si  distancia  m  <  0.8*distancia  n:
good.append(m)  
pts2.append(kp2[m.trainIdx].pt)  
pts1.append(kp1[m.queryIdx].pt)

Ahora  tenemos  la  lista  de  las  mejores  coincidencias  de  ambas  imágenes.  Encontremos  la  Matriz  Fundamental.

pts1  =  np.int32(pts1)  pts2  =  
np.int32(pts2)
F,  máscara  =  cv2.findFundamentalMat(pts1,pts2,cv2.FM_LMEDS)

#  Seleccionamos  solo  puntos  interiores  pts1  =  
pts1[mask.ravel()==1]  pts2  =  
pts2[mask.ravel()==1]

A  continuación  encontramos  las  epilinas.  Las  epilinas  correspondientes  a  los  puntos  de  la  primera  imagen  se  dibujan  en  la  segunda  imagen.  Por  lo  tanto,  
mencionar  las  imágenes  correctas  es  importante  aquí.  Obtenemos  una  matriz  de  líneas.  Entonces  definimos  una  nueva  función  para  dibujar  estas  líneas  en  
las  imágenes.

def  dibuja  líneas  (img1,  img2,  líneas,  pts1,  pts2):
'''  img1  ­  imagen  en  la  que  dibujamos  las  epilíneas  de  los  puntos  en  img2
líneas  ­  epilíneas  correspondientes  '''  r,c  =  img1.shape  
img1  =  
cv2.cvtColor(img1,cv2.COLOR_GRAY2BGR)  img2  =  
cv2.cvtColor(img2,cv2.COLOR_GRAY2BGR)  for  r,pt1,pt2  in  
zip(lines,pts1 ,pts2):  color  =  
tupla(np.random.randint(0,255,3).tolist())  x0,y0  =  map(int,  [0,  ­r[2]/r[1] ])  x1,y1  
=  map(int,  [c,  ­(r[2]+r[0]*c)/r[1] ])  img1  =  cv2.line(img1,  
(x0,y0),  (x1,y1),  color,  1)  img1  =  cv2.circle(img1,tupla(pt1),5,color,­1)  
img2  =  cv2.circle(img2,tupla(pt2),5,color,­1)  return  img1,img2

Ahora  encontramos  las  epilinas  en  ambas  imágenes  y  las  dibujamos.

#  Encuentra  las  epilíneas  correspondientes  a  los  puntos  en  la  imagen  de  la  derecha  (segunda  imagen)  y  #  dibujando  
sus  líneas  en  la  imagen  de  la  izquierda  líneas1  =  
cv2.computeCorrespondEpilines(pts2.reshape(­1,1,2),  2,F)  líneas1  =  líneas1.reforma(­  1,3)  img5,img6  
=  líneas  dibujadas  (img1,img2,líneas1,pts1,pts2)

#  Encuentra  las  epilíneas  correspondientes  a  los  puntos  en  la  imagen  de  la  izquierda  (primera  imagen)  y  #  
dibujando  sus  líneas  en  la  imagen  de  la  derecha  
líneas2  =  cv2.computeCorrespondEpilines(pts1.reshape(­1,1,2),  1,F)  líneas2  =  líneas2.reforma(­  1,3)  
img3,img4  =  líneas  dibujadas  
(img2,img1,líneas2,pts2,pts1)

plt.subtrama(121),plt.imshow(img5)  
plt.subtrama(122),plt.imshow(img3)  plt.show()

A  continuación  se  muestra  el  resultado  que  obtenemos:

1.7.  Calibración  de  cámara  y  reconstrucción  3D 221
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Puede  ver  en  la  imagen  de  la  izquierda  que  todas  las  epilíneas  convergen  en  un  punto  fuera  de  la  imagen  del  lado  derecho.  esa  reunión

222 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

punto  es  el  epipolo.

Para  obtener  mejores  resultados,  se  deben  utilizar  imágenes  con  buena  resolución  y  muchos  puntos  no  planos.

Recursos  adicionales

Ejercicios

1.  Un  tema  importante  es  el  movimiento  de  avance  de  la  cámara.  Luego  se  verán  epipolos  en  los  mismos  lugares  en
ambos  con  epilinas  emergiendo  de  un  punto  fijo.  Ver  esta  discusión.

2.  La  estimación  de  la  matriz  fundamental  es  sensible  a  la  calidad  de  las  coincidencias,  valores  atípicos,  etc.  Empeora  cuando  todos
las  coincidencias  seleccionadas  se  encuentran  en  el  mismo  plano.  Revisa  esta  discusión.

Mapa  de  profundidad  a  partir  de  imágenes  estéreo

Meta

En  esta  sesión,

•  Aprenderemos  a  crear  mapas  de  profundidad  a  partir  de  imágenes  estéreo.

Lo  esencial

En  la  última  sesión,  vimos  conceptos  básicos  como  restricciones  epipolares  y  otros  términos  relacionados.  También  vimos  que  si  tenemos  dos  
imágenes  de  la  misma  escena,  podemos  obtener  información  de  profundidad  de  una  manera  intuitiva.  A  continuación  se  muestra  una  imagen  
y  algunas  fórmulas  matemáticas  simples  que  prueban  esa  intuición.  (Imagen  de  cortesía :

1.7.  Calibración  de  cámara  y  reconstrucción  3D 223
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

El  diagrama  anterior  contiene  triángulos  equivalentes.  Escribir  sus  ecuaciones  equivalentes  nos  dará  el  siguiente  resultado:

=  −
′=

y  son  la  distancia  entre  los  puntos  en  el  plano  de  la  imagen  correspondientes  al  punto  de  escena  3D  y  su  centro  de  cámara.  es  la  
distancia  entre  dos  cámaras  (que  conocemos)  y  es  la  distancia  focal  de  la  cámara  (ya  conocida).  En  resumen,  la  ecuación  anterior  
dice  que  la  profundidad  de  un  punto  en  una  escena  es  inversamente  proporcional  a  la  diferencia  en  la  distancia  de  los  puntos  de  
imagen  correspondientes  y  sus  centros  de  cámara.  Entonces,  con  esta  información,  podemos  derivar  la  profundidad  de  todos  los  
píxeles  en  una  imagen.

Entonces  encuentra  coincidencias  correspondientes  entre  dos  imágenes.  Ya  hemos  visto  cómo  la  restricción  epilina  hace  que  esta  operación  
sea  más  rápida  y  precisa.  Una  vez  que  encuentra  coincidencias,  encuentra  la  disparidad.  Veamos  cómo  podemos  hacerlo  con  OpenCV.

Código

El  siguiente  fragmento  de  código  muestra  un  procedimiento  simple  para  crear  un  mapa  de  disparidad.

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

imgL  =  cv2.imread('tsukuba_l.png',0)  imgR  =  
cv2.imread('tsukuba_r.png',0)

224 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

stereo  =  cv2.createStereoBM(numDisparities=16,  blockSize=15)  disparity  =  
stereo.compute(imgL,imgR)  plt.imshow(disparity,'gray')  
plt.show()

La  imagen  de  abajo  contiene  la  imagen  original  (izquierda)  y  su  mapa  de  disparidad  (derecha).  Como  puede  ver,  el  resultado  está  contaminado  
con  un  alto  grado  de  ruido.  Al  ajustar  los  valores  de  numDisparities  y  blockSize,  puede  obtener  mejores  resultados.

Nota:  Se  agregarán  más  detalles

Recursos  adicionales

Ejercicios

1.  Las  muestras  de  OpenCV  contienen  un  ejemplo  de  cómo  generar  un  mapa  de  disparidad  y  su  reconstrucción  en  3D.  Compruebe  
stereo_match.py  en  las  muestras  de  OpenCV­Python.

Aprendizaje  automático

•  K­vecino  más  cercano

Aprenda  a  usar  kNN  para  la  clasificación  Además,  aprenda  sobre  el  reconocimiento  de  dígitos  
escritos  a  mano  usando  kNN

•  Máquinas  de  vectores  de  soporte  (SVM)

1.8.  Aprendizaje  automático 225
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Comprender  los  conceptos  de  SVM

•  Agrupación  de  K­Means

Aprenda  a  usar  la  agrupación  en  clústeres  de  K­Means  para  agrupar  datos  en  una  cantidad  de  clústeres.  
Además,  aprenda  a  hacer  la  cuantificación  del  color  usando  K­Means  Clustering

226 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

K­vecino  más  cercano
•  Comprender  k­Vecino  más  cercano

Obtenga  una  comprensión  básica  de  lo  que  es  kNN

•  OCR  de  datos  escritos  a  mano  usando  kNN

Ahora  usemos  kNN  en  OpenCV  para  reconocimiento  de  dígitos  OCR

1.8.  Aprendizaje  automático 227
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Entendiendo  k­vecino  más  cercano

Meta

En  este  capítulo,  comprenderemos  los  conceptos  del  algoritmo  k­vecino  más  cercano  (kNN).

Teoría

kNN  es  uno  de  los  algoritmos  de  clasificación  más  simples  disponibles  para  el  aprendizaje  supervisado.  La  idea  es  buscar  la  coincidencia  más  
cercana  de  los  datos  de  prueba  en  el  espacio  de  características.  Lo  examinaremos  con  la  imagen  de  abajo.

En  la  imagen,  hay  dos  familias,  Blue  Squares  y  Red  Triangles.  Llamamos  a  cada  familia  como  Clase.  Sus  casas  se  muestran  en  su  mapa  de  la  
ciudad  que  llamamos  espacio  de  características.  (Puede  considerar  un  espacio  de  características  como  un  espacio  donde  se  proyectan  todos  los  
datos.  Por  ejemplo,  considere  un  espacio  de  coordenadas  2D.  Cada  dato  tiene  dos  características,  coordenadas  x  e  y.  Puede  representar  estos  
datos  en  su  espacio  de  coordenadas  2D,  ¿verdad?  Ahora  imagina  si  hay  tres  características,  necesitas  espacio  3D.
Ahora  considere  N  características,  donde  necesita  un  espacio  N­dimensional,  ¿verdad?  Este  espacio  N­dimensional  es  su  espacio  característico.
En  nuestra  imagen,  puede  considerarlo  como  un  caso  2D  con  dos  características).

Ahora,  un  nuevo  miembro  llega  a  la  ciudad  y  crea  un  nuevo  hogar,  que  se  muestra  como  un  círculo  verde.  Debería  ser  agregado  a  una  de  estas  
familias  Azul/Roja.  Llamamos  a  ese  proceso,  Clasificación.  ¿Qué  hacemos?  Ya  que  estamos  tratando  con  kNN,  apliquemos  este  algoritmo.

Un  método  es  verificar  quién  es  su  vecino  más  cercano.  De  la  imagen,  está  claro  que  es  la  familia  Red  Triangle.  Entonces  él  también  se  agrega  al  
Triángulo  Rojo.  Este  método  se  llama  simplemente  vecino  más  cercano,  porque  la  clasificación  depende  únicamente  del  vecino  más  cercano.

Pero  hay  un  problema  con  eso.  El  Triángulo  Rojo  puede  ser  el  más  cercano.  Pero,  ¿y  si  hay  muchos  cuadrados  azules  cerca  de  él?  Entonces  los  
Cuadrados  Azules  tienen  más  fuerza  en  esa  localidad  que  el  Triángulo  Rojo.  Por  lo  tanto,  solo  verificar  el  más  cercano  no  es  suficiente.  En  su  
lugar,  comprobamos  algunas  k  familias  más  cercanas.  Entonces  quien  sea  mayoritario  en  ellos,  el  nuevo  pertenece  a  esa  familia.  En  nuestra  
imagen,  tomemos  k=3,  es  decir,  3  familias  más  cercanas.  Tiene  dos  Rojos  y  un  Azul  (hay  dos  Azules  equidistantes,  pero  como  k=3,  tomamos  solo  
uno  de  ellos),  por  lo  que  nuevamente  debe  agregarse  a  la  familia  Roja.  Pero,  ¿y  si  tomamos  k=7?  Luego  tiene  5  familias  Azules  y  2  familias  Rojas.  
¡¡Excelente!!  Ahora  debería  ser  agregado  a  la  familia  Blue.  Entonces  todo  cambia  con  el  valor  de  k.  Lo  más  gracioso  es,  ¿y  si  k  =  4?  Tiene  2  
vecinos  rojos  y  2  azules.  es  un  empate!!!
Así  que  mejor  toma  k  como  un  número  impar.  Entonces,  este  método  se  llama  k­Vecino  más  cercano  ya  que  la  clasificación  depende  de  los  k  
vecinos  más  cercanos.

Nuevamente,  en  kNN,  es  cierto  que  estamos  considerando  k  vecinos,  pero  le  estamos  dando  la  misma  importancia  a  todos,  ¿no?  ¿Es  justicia?
Por  ejemplo,  tome  el  caso  de  k=4.  Dijimos  que  es  un  empate.  Pero  mira,  las  2  familias  Rojas  están  más  cerca  de  él  que  los

228 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

otras  2  familias  azules.  Por  lo  tanto,  es  más  elegible  para  ser  agregado  a  Red.  Entonces,  ¿cómo  explicamos  matemáticamente  eso?  Damos  
algunos  pesos  a  cada  familia  dependiendo  de  su  distancia  al  recién  llegado.  Para  aquellos  que  están  cerca  de  él,  obtienen  pesos  más  altos,  
mientras  que  aquellos  que  están  lejos  obtienen  pesos  más  bajos.  Luego  sumamos  los  pesos  totales  de  cada  familia  por  separado.  Quien  
obtenga  los  pesos  totales  más  altos,  el  recién  llegado  pasa  a  esa  familia.  Esto  se  llama  kNN  modificado.

Entonces,  ¿cuáles  son  algunas  de  las  cosas  importantes  que  ves  aquí?

•  Necesitas  tener  información  sobre  todas  las  casas  de  la  ciudad,  ¿verdad?  Porque  tenemos  que  verificar  la  distancia  desde  el  recién  
llegado  a  todas  las  casas  existentes  para  encontrar  al  vecino  más  cercano.  Si  hay  muchas  casas  y  familias,  se  necesita  mucha  
memoria  y  también  más  tiempo  para  el  cálculo.

•  Casi  no  hay  tiempo  para  ningún  tipo  de  entrenamiento  o  preparación.

Ahora  veámoslo  en  OpenCV.

kNN  en  OpenCV

Haremos  un  ejemplo  simple  aquí,  con  dos  familias  (clases),  como  arriba.  Luego,  en  el  próximo  capítulo,  haremos  mucho  más  mejor  ejemplo.

Así  que  aquí,  etiquetamos  a  la  familia  Roja  como  Clase­0  (indicada  por  0)  y  a  la  familia  Azul  como  Clase­1  (indicada  por  1).  Creamos  25  
familias  o  25  datos  de  entrenamiento  y  los  etiquetamos  como  Clase­0  o  Clase­1.  Hacemos  todo  esto  con  la  ayuda  del  generador  de  números  
aleatorios  en  Numpy.

Luego  lo  trazamos  con  la  ayuda  de  Matplotlib.  Las  familias  rojas  se  muestran  como  triángulos  rojos  y  las  familias  azules  se  muestran  como  
cuadrados  azules.

importar  cv2  
importar  numpy  como  np  
importar  matplotlib.pyplot  como  plt

#  Conjunto  de  funciones  que  contiene  valores  (x,y)  de  25  datos  conocidos/de  entrenamiento  trainData  
=  np.random.randint(0,100,(25,2)).astype(np.float32)

#  Etiqueta  cada  uno  de  ellos  rojo  o  azul  con  los  números  0  y  1  respuestas  =  
np.random.randint(0,2,(25,1)).astype(np.float32)

#  Tomar  familias  rojas  y  trazarlas  red  =  
trainData[responses.ravel()==0]  
plt.scatter(red[:,0],red[:,1],80,'r','^')

#  Tomar  familias  azules  y  trazarlas  blue  =  
trainData[responses.ravel()==1]  
plt.scatter(blue[:,0],blue[:,1],80,'b','s')

plt.mostrar()

Obtendrá  algo  similar  a  nuestra  primera  imagen.  Dado  que  está  utilizando  un  generador  de  números  aleatorios,  obtendrá  datos  diferentes  
cada  vez  que  ejecute  el  código.

A  continuación,  inicie  el  algoritmo  kNN  y  pase  los  datos  del  tren  y  las  respuestas  para  entrenar  el  kNN  (construye  un  árbol  de  búsqueda).

Luego  traeremos  a  un  recién  llegado  y  lo  clasificaremos  en  una  familia  con  la  ayuda  de  kNN  en  OpenCV.  Antes  de  ir  a  kNN,  necesitamos  
saber  algo  sobre  nuestros  datos  de  prueba  (datos  de  los  recién  llegados).  Nuestros  datos  deben  ser  una  matriz  de  punto  flotante  con  tamaño.  
×
Luego  encontramos  los  vecinos  más  cercanos   .
del  recién  llegado.  Podemos   especificar  cuántos  vecinos  queremos.  Vuelve:

1.  La  etiqueta  dada  al  recién  llegado  según  la  teoría  kNN  que  vimos  anteriormente.  Si  quieres  Vecino  más  cercano
algoritmo,  simplemente  especifique  k=1  donde  k  es  el  número  de  vecinos.

1.8.  Aprendizaje  automático 229
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

2.  Las  etiquetas  de  k­vecinos  más  cercanos.

3.  Distancias  correspondientes  del  recién  llegado  a  cada  vecino  más  cercano.

Entonces,  veamos  cómo  funciona.  El  recién  llegado  está  marcado  en  color  verde.

recién  llegado  =  np.random.randint(0,100,(1,2)).astype(np.float32)  plt.scatter(recién  llegado[:,0],recién  
llegado[:,1],80,'g','o' )

knn  =  cv2.KNearest()
knn.train(trainData,responses)  ret,  resultados,  
vecinos ,dist  =  knn.find_nearest(recién  llegado,  3)

print  "resultado:  ",  resultados,"\n"  print  "vecinos:  ",  
vecinos,"\n"  print  "distancia:  ",  dist

plt.mostrar()

Obtuve  el  resultado  de  la  siguiente  manera:

resultado:  [[ 1.]]  vecinos:  
[[ 1.  1.  1.]]  distancia:  [[ 53.  58.  61.]]

Dice  que  nuestro  recién  llegado  tiene  3  vecinos,  todos  de  la  familia  Blue.  Por  lo  tanto,  está  etiquetado  como  familia  azul.  Es  obvio  de  la  siguiente  trama:

Si  tiene  una  gran  cantidad  de  datos,  puede  simplemente  pasarlos  como  una  matriz.  Los  resultados  correspondientes  también  se  obtienen  como  matrices.

230 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

#10  recién  llegados
recién  llegados  =  np.random.randint(0,100,(10,2)).astype(np.float32)  ret,  resultados,vecinos,dist  =  
knn.find_nearest(recién  llegado,  3)
#  Los  resultados  también  contendrán  10  etiquetas.

Recursos  adicionales

1.  Notas  de  NPTEL  sobre  reconocimiento  de  patrones,  Capítulo  11

Ejercicios

OCR  de  datos  escritos  a  mano  usando  kNN

Meta

En  este  capítulo

•  Usaremos  nuestro  conocimiento  sobre  kNN  para  construir  una  aplicación  básica  de  OCR.

•  Probaremos  con  los  datos  de  dígitos  y  alfabetos  disponibles  que  vienen  con  OpenCV.

OCR  de  dígitos  escritos  a  mano

Nuestro  objetivo  es  construir  una  aplicación  que  pueda  leer  los  dígitos  escritos  a  mano.  Para  esto  necesitamos  algunos  train_data  y  test_data.  
OpenCV  viene  con  una  imagen  digits.png  (en  la  carpeta  opencv/samples/python2/data/)  que  tiene  5000  dígitos  escritos  a  mano  (500  por  
cada  dígito).  Cada  dígito  es  una  imagen  de  20x20.  Así  que  nuestro  primer  paso  es  dividir  esta  imagen  en  5000  dígitos  diferentes.  Para  cada  
dígito,  lo  aplanamos  en  una  sola  fila  con  400  píxeles.  Ese  es  nuestro  conjunto  de  características,  es  decir,  los  valores  de  intensidad  de  todos  
los  píxeles.  Es  el  conjunto  de  características  más  simple  que  podemos  crear.  Usamos  las  primeras  250  muestras  de  cada  dígito  como  
train_data  y  las  siguientes  250  muestras  como  test_data.  Así  que  vamos  a  prepararlos  primero.

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('dígitos.png')  gris  =  
cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#  Ahora  dividimos  la  imagen  en  5000  celdas,  cada  celda  de  tamaño  20x20  =  [np.hsplit(row,100)  for  
row  in  np.vsplit(gray,50)]

#  Conviértalo  en  una  matriz  Numpy.  Su  tamaño  será  (50,100,20,20)  x  =  np.array(cells)

#  Ahora  preparamos  train_data  y  test_data.  tren  =  
x[:,:50].reshape(­1,400).astype(np.float32)  #  Tamaño  =  (2500,400)  prueba  =  x[:,50:100].reshape(­1,400).astype(np .float32)  #  
Tamaño  =  (2500,400)

#  Crear  etiquetas  para  entrenar  y  probar  datos  k  =  np.arange(10)  
train_labels  =  np.repeat(k,250)
[:,np.newaxis]  test_labels  =  train_labels.copy()

#  Iniciar  kNN,  entrenar  los  datos,  luego  probarlos  con  datos  de  prueba  para  k=1

1.8.  Aprendizaje  automático 231
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

knn  =  cv2.KNearest()  
knn.train(train,train_labels)  ret,resultado,vecinos,dist  
=  knn.find_nearest(test,k=5)

#  Ahora  comprobamos  la  precisión  de  la  clasificación
#  Para  eso,  compare  el  resultado  con  test_labels  y  verifique  cuáles  son  las  coincidencias  incorrectas  =  result==test_labels

correcto  =  np.count_nonzero(coincidencias)  precisión  =  
correcto*100.0/resultado.tamaño  precisión  de  impresión

Así  que  nuestra  aplicación  OCR  básica  está  lista.  Este  ejemplo  en  particular  me  dio  una  precisión  del  91%.  Una  opción  para  mejorar  la  precisión  es  
agregar  más  datos  para  el  entrenamiento,  especialmente  los  incorrectos.  Entonces,  en  lugar  de  encontrar  estos  datos  de  entrenamiento  cada  vez  
que  inicio  la  aplicación,  es  mejor  que  los  guarde,  para  que  la  próxima  vez,  lea  directamente  estos  datos  de  un  archivo  y  comience  la  clasificación.  
Puede  hacerlo  con  la  ayuda  de  algunas  funciones  de  Numpy  como  np.savetxt,  np.savez,  np.load,  etc.  Consulte  sus  documentos  para  obtener  más  detalles.

#  guardar  los  datos
np.savez('knn_data.npz',tren=tren,  tren_etiquetas=tren_etiquetas)

#  Ahora  carga  los  datos
con  np.load('knn_data.npz')  como  datos:
imprimir  datos.archivos  tren  
=  datos['tren']  tren_etiquetas  =  
datos['tren_etiquetas']

En  mi  sistema,  ocupa  alrededor  de  4,4  MB  de  memoria.  Dado  que  estamos  utilizando  valores  de  intensidad  (datos  uint8)  como  características,  sería  
mejor  convertir  los  datos  a  np.uint8  primero  y  luego  guardarlos.  En  este  caso,  solo  ocupa  1,1  MB.  Luego,  mientras  carga,  puede  volver  a  convertirlo  
en  float32.

OCR  de  alfabetos  ingleses

A  continuación,  haremos  lo  mismo  con  los  alfabetos  ingleses,  pero  hay  un  ligero  cambio  en  el  conjunto  de  datos  y  características.  Aquí,  en  lugar  de  
imágenes,  OpenCV  viene  con  un  archivo  de  datos,  letter­recognition.data  en  la  carpeta  opencv/samples/cpp/.  Si  lo  abre,  verá  20000  líneas  que,  a  
primera  vista,  pueden  parecer  basura.  En  realidad,  en  cada  fila,  la  primera  columna  es  un  alfabeto  que  es  nuestra  etiqueta.  Los  siguientes  16  
números  que  le  siguen  son  sus  diferentes  características.  Estas  funciones  se  obtienen  del  repositorio  de  aprendizaje  automático  de  UCI.  Puede  
encontrar  los  detalles  de  estas  características  en  esta  página.

Hay  20000  muestras  disponibles,  por  lo  que  tomamos  los  primeros  10000  datos  como  muestras  de  entrenamiento  y  los  10000  restantes  como  
muestras  de  prueba.  Deberíamos  cambiar  los  alfabetos  a  caracteres  ascii  porque  no  podemos  trabajar  con  alfabetos  directamente.

importar  cv2  
importar  numpy  como  np  
importar  matplotlib.pyplot  como  plt

#  Cargue  los  datos,  los  convertidores  convierten  la  letra  en  un  número  data=  np.loadtxt('letter­
recognition.data',  dtype=  'float32',  delimiter  =  ',',
convertidores  =  {0:  lambda  ch:  ord(ch)­ord('A')})

#  dividir  los  datos  en  dos,  10000  cada  uno  para  tren  y  tren  de  prueba,  test  =  np.vsplit(data,2)

#  divide  trainData  y  testData  en  características  y  respuestas ,  trainData  =  np.hsplit(train,[1])  etiquetas,  
testData  =  np.hsplit(test,[1])

#  Iniciar  el  kNN,  clasificar,  medir  la  precisión.

232 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

knn  =  cv2.KNearest()  
knn.train(trainData,  respuestas)  ret,  resultado,  
vecinos,  dist  =  knn.find_nearest(testData,  k=5)

correcto  =  np.count_nonzero(resultado  ==  etiquetas)  precisión  =  
correcto*100.0/10000  precisión  de  impresión

Me  da  una  precisión  del  93,22%.  Nuevamente,  si  desea  aumentar  la  precisión,  puede  agregar  iterativamente  datos  de  error  en  cada  nivel.

Recursos  adicionales

Ejercicios

Máquinas  de  vectores  de  soporte  (SVM)

•  Comprender  la  SVM

Obtenga  una  comprensión  básica  de  lo  que  es  SVM

•  OCR  de  datos  escritos  a  mano  usando  SVM

Usemos  las  funcionalidades  de  SVM  en  OpenCV

1.8.  Aprendizaje  automático 233
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Comprender  la  SVM

Meta

En  este  capítulo

•  Veremos  una  comprensión  intuitiva  de  SVM

Teoría

Datos  linealmente  separables

Considere  la  imagen  a  continuación  que  tiene  dos  tipos  de  datos,  rojo  y  azul.  En  kNN,  para  un  dato  de  prueba,  solíamos  medir  su  distancia  a  
todas  las  muestras  de  entrenamiento  y  tomar  la  que  tenía  la  distancia  mínima.  Se  necesita  mucho  tiempo  para  medir  todas  las  distancias  y  
mucha  memoria  para  almacenar  todas  las  muestras  de  entrenamiento.  Pero  teniendo  en  cuenta  los  datos  proporcionados  en  la  imagen,  
¿deberíamos  necesitar  tanto?

Considere  otra  idea.  Encontramos  una  línea,  ( )  =  1  +  2  +  que  divide  ambos  datos  en  dos  regiones.  Cuando  nosotros ,  simplemente  
test_data  Podemos   sustituyámoslo  en  ( ).  Si  ( )  >  0,  pertenece  al  grupo  azul,  de  lo  contrario  pertenece  al  grupo  rojo.  obtener  un  nuevo  
llamar  a  esta  línea  Límite  de  decisión.  Es  muy  simple  y  eficiente  en  memoria.  Estos  datos  que  se  pueden  dividir  en  dos  con  una  línea  recta  (o  
hiperplanos  en  dimensiones  superiores)  se  denominan  separables  lineales.

Entonces,  en  la  imagen  de  arriba,  puede  ver  que  muchas  de  esas  líneas  son  posibles.  ¿Cuál  tomaremos?  Muy  intuitivamente  podemos  decir  
que  la  línea  debe  pasar  lo  más  lejos  posible  de  todos  los  puntos.  ¿Por  qué?  Porque  puede  haber  ruido  en  los  datos  entrantes.  Estos  datos  
no  deberían  afectar  la  precisión  de  la  clasificación.  Por  lo  tanto,  tomar  la  línea  más  lejana  proporcionará  más  inmunidad  contra  el  ruido.  
Entonces,  lo  que  hace  SVM  es  encontrar  una  línea  recta  (o  hiperplano)  con  la  distancia  mínima  más  grande  a  las  muestras  de  entrenamiento.  
Vea  la  línea  en  negrita  en  la  imagen  de  abajo  que  pasa  por  el  centro.

Entonces,  para  encontrar  este  límite  de  decisión,  necesita  datos  de  entrenamiento.  ¿Necesitas  todo?  NO.  Solo  los  que  están  cerca  del  grupo  
opuesto  son  suficientes.  En  nuestra  imagen,  son  un  círculo  relleno  de  azul  y  dos  cuadrados  rellenos  de  rojo.  Podemos  llamarlos  Vectores  de  
Soporte  y  las  rectas  que  los  atraviesan  se  llaman  Planos  de  Soporte.  Son  adecuados  para  encontrar  nuestro  límite  de  decisión.  No  tenemos  
que  preocuparnos  por  todos  los  datos.  Ayuda  en  la  reducción  de  datos.

Lo  que  sucedió  es  que  se  encuentran  los  primeros  dos  hiperplanos  que  representan  mejor  los  datos.  Por  ejemplo,  los  datos  azules  están  
representados  por  +  0  >  1  mientras  que  los  datos  rojos  están  representados  por  +  0  <  −1  donde  es  el  vector  de  peso  ( =  [ 1,  2, ..., ])  y  
es  el  vector  de  características  ( =  [ 1,  2, ..., ]).  0  es  el  sesgo.  El  vector  de  peso  decide  la  orientación  del  límite  de  decisión,  mientras  que  el  
punto  de  polarización  decide  su  ubicación.  Ahora,  el  límite  de  decisión  se  define  como  el  punto  medio  entre  estos  hiperplanos,  por  lo  que  se  
expresa  como  +  0  =  0.  La  distancia  mínima  desde  el  vector  de  soporte  hasta  el  límite  de  decisión  viene  dada  por,
=
1  || || .  El  margen  es  el  doble  de  esta  distancia,  y  necesitamos  maximizar  este  margen.  es  decir,  tenemos  que

234 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

minimizar  una  nueva  función  ( ,  0)  con  algunas  limitaciones  que  se  pueden  expresar  a  continuación:

1
min ( ,  0)  = ||  ||2  sujeto  a  ( +  0)  ≥  1  
,  0
2

donde  es  la  etiqueta  de  cada  clase,     [−1,  1].

Datos  separables  no  lineales

Considere  algunos  datos  que  no  se  pueden  dividir  en  dos  con  una  línea  recta.  Por  ejemplo,  considere  datos  unidimensionales  donde  'X'  
está  en  ­3  y  +3  y  'O'  está  en  ­1  y  +1.  Claramente  no  es  linealmente  separable.  Pero  existen  métodos  para  resolver  este  tipo  de  problemas.  
2
Si  podemos  mapear  este  conjunto  de  datos  con  una  función,  ( )  =  obtenemos  'X'  en  9  y  'O'  en  1,,  que  son  separables  linealmente.

2
De  lo  contrario,  podemos  convertir  estos  datos  unidimensionales  en  bidimensionales.  Podemos  usar  la  función  ( )  =  ( , )  para  mapear  
estos  datos.  Entonces  'X'  se  convierte  en  (­3,9)  y  (3,9)  mientras  que  'O'  se  convierte  en  (­1,1)  y  (1,1).  Esto  también  es  separable  lineal.
En  resumen,  es  más  probable  que  los  datos  separables  no  lineales  en  el  espacio  de  menor  dimensión  se  conviertan  en  separables  lineales  en  
el  espacio  de  mayor  dimensión.

En  general,  es  posible  mapear  puntos  en  un  espacio  d­dimensional  a  algún  espacio  D­dimensional  ( > )  para  verificar  la  posibilidad  de  
separabilidad  lineal.  Hay  una  idea  que  ayuda  a  calcular  el  producto  escalar  en  el  espacio  de  alta  dimensión  (núcleo)  realizando  cálculos  
en  el  espacio  de  entrada  (característica)  de  baja  dimensión.  Podemos  ilustrar  con  el  siguiente  ejemplo.

Considere  dos  puntos  en  un  espacio  bidimensional,  =  ( 1,  2)  y  =  ( 1,  2).  Sea  una  función  de  mapeo  que  mapea  un  punto  bidimensional  a  
un  espacio  tridimensional  de  la  siguiente  manera:

( )  =  ( 2  1 , 2  2 ,


√  2  1  2)  ( )  =  ( 2  1 , 2  2 ,
√  2  1  2)

Definamos  una  función  kernel  ( , )  que  hace  un  producto  escalar  entre  dos  puntos,  como  se  muestra  a  continuación:

( , )  =  ( ).  ( )  =  ( ) ,  ( )  √  2

=  ( 2  1 , 2  2 , 1  2).( 2  1 , 2  2 ,


√  2  1  2)
= 2   2   2  
+  2
1 2  +  1 2 2 1  1  2  2

2
=  ( 1  1  +  2  2)
2
( ).  ( )  =  ( . )

Significa  que  se  puede  lograr  un  producto  escalar  en  un  espacio  tridimensional  utilizando  un  producto  escalar  al  cuadrado  en  un  espacio  
bidimensional.  Esto  se  puede  aplicar  al  espacio  dimensional  superior.  Entonces  podemos  calcular  características  de  dimensiones  más  altas  a  partir  
de  dimensiones  más  bajas.  Una  vez  que  los  mapeamos,  obtenemos  un  espacio  dimensional  superior.

Además  de  todos  estos  conceptos,  viene  el  problema  de  la  clasificación  errónea.  Por  lo  tanto,  solo  encontrar  el  límite  de  decisión  con  el  
margen  máximo  no  es  suficiente.  Necesitamos  considerar  también  el  problema  de  los  errores  de  clasificación.  A  veces,  puede  ser  posible  
encontrar  un  límite  de  decisión  con  menos  margen,  pero  con  errores  de  clasificación  reducidos.  De  todos  modos,  necesitamos  modificar  
nuestro  modelo  para  que  encuentre  el  límite  de  decisión  con  el  máximo  margen,  pero  con  menos  errores  de  clasificación.
El  criterio  de  minimización  se  modifica  como:

|| ||2  +  ( )

La  siguiente  imagen  muestra  este  concepto.  Para  cada  muestra  de  los  datos  de  entrenamiento  se  define  un  nuevo  parámetro.  Es  la  
distancia  desde  su  muestra  de  entrenamiento  correspondiente  a  su  región  de  decisión  correcta.  Para  los  que  no  están  mal  clasificados,  
caen  en  sus  correspondientes  planos  de  apoyo,  por  lo  que  su  distancia  es  cero.

1.8.  Aprendizaje  automático 235
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Entonces  el  nuevo  problema  de  optimización  es:

min ( ,  0)  =  ||  ||2  +  ∑   sujeto  a  ( +  0)  ≥  1  −  y  ≥  0  


,  0

¿Cómo  se  debe  elegir  el  parámetro  C?  Es  obvio  que  la  respuesta  a  esta  pregunta  depende  de  cómo  se  distribuyan  los  datos  de  
entrenamiento.  Aunque  no  hay  una  respuesta  general,  es  útil  tener  en  cuenta  estas  reglas:

•  Los  valores  grandes  de  C  dan  soluciones  con  menos  errores  de  clasificación  pero  con  un  margen  más  pequeño.  Considere  
que  en  este  caso  es  costoso  cometer  errores  de  clasificación.  Dado  que  el  objetivo  de  la  optimización  es  minimizar  el  
argumento,  se  permiten  pocos  errores  de  clasificación.

•  Valores  pequeños  de  C  dan  soluciones  con  mayor  margen  y  más  errores  de  clasificación.  En  este  caso  la  minimización  no  
considera  tanto  el  término  de  la  suma  por  lo  que  se  enfoca  más  en  encontrar  un  hiperplano  con  gran  margen.

Recursos  adicionales

1.  Notas  de  NPTEL  sobre  Reconocimiento  de  Patrones  Estadísticos,  Capítulos  25­29.

Ejercicios

OCR  de  datos  escritos  a  mano  usando  SVM

Meta

En  este  capítulo

•  Revisaremos  el  OCR  de  datos  escritos  a  mano,  pero  con  SVM  en  lugar  de  kNN.

OCR  de  dígitos  escritos  a  mano

En  kNN,  usamos  directamente  la  intensidad  de  píxel  como  vector  de  características.  Esta  vez  usaremos  Histograma  de  Gradientes  Orientados  (HOG)  
como  vectores  de  características.

236 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Aquí,  antes  de  encontrar  el  HOG,  desviamos  la  imagen  usando  sus  momentos  de  segundo  orden.  Así  que  primero  definimos  una  función  alinear()  que  
toma  una  imagen  de  dígito  y  la  alinea.  A  continuación  se  muestra  la  función  de  desfase():

def  enderezar(img):  m  =  
cv2.momentos(img)  if  
abs(m['mu02'])  <  1e­2:  return  img.copy()  
skew  =  m['mu11']/m['mu02']

M  =  np.float32([[1,  sesgo,  ­0.5*SZ*sesgo],  [0,  1,  0]])  img  =  cv2.warpAffine(img,M,
(SZ,  SZ),flags=affine_flags)  return  imagen

La  imagen  de  abajo  muestra  la  función  de  alineamiento  de  arriba  aplicada  a  una  imagen  de  cero.  La  imagen  de  la  izquierda  es  la  imagen  original  y  la  
imagen  de  la  derecha  es  la  imagen  sesgada.

A  continuación  tenemos  que  encontrar  el  Descriptor  HOG  de  cada  celda.  Para  eso,  encontramos  las  derivadas  de  Sobel  de  cada  celda  en  la  dirección  X  e  
Y.  Luego  encuentre  su  magnitud  y  dirección  de  gradiente  en  cada  píxel.  Este  gradiente  se  cuantifica  en  16  valores  enteros.  Divide  esta  imagen  en  cuatro  
subcuadrados.  Para  cada  subcuadrado,  calcule  el  histograma  de  dirección  (16  contenedores)  ponderado  con  su  magnitud.  Entonces,  cada  subcuadrado  
te  da  un  vector  que  contiene  16  valores.  Cuatro  de  estos  vectores  (de  cuatro  subcuadrados)  juntos  nos  dan  un  vector  de  características  que  contiene  64  
valores.  Este  es  el  vector  de  características  que  usamos  para  entrenar  nuestros  datos.

def  cerdo(img):  gx  
=  cv2.Sobel(img,  cv2.CV_32F,  1,  0)  gy  =  cv2.Sobel(img,  
cv2.CV_32F,  0,  1)  mag,  ang  =  cv2.cartToPolar(gx,  gy)

#  cuantificación  de  binvalues  en  (0...16)  bins  =  
np.int32(bin_n*ang/(2*np.pi))

#  Divide  en  4  subcuadrados  bin_cells  
=  bins[:10,:10],  bins[10:,:10],  bins[:10,10:],  bins[10:,10:]
mag_cells  =  mag[:10,:10],  mag[10:,:10],  mag[:10,10:],  mag[10:,10:]  hists  =  [np.bincount(b.ravel(),  
m.ravel(),  bin_n)  para  b,  m  en  zip(bin_cells,  mag_
→células)]
hist  =  np.hstack(hists)  devuelve  hist

1.8.  Aprendizaje  automático 237
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Finalmente,  como  en  el  caso  anterior,  comenzamos  por  dividir  nuestro  gran  conjunto  de  datos  en  celdas  individuales.  Por  cada  dígito,  se  reservan  250  celdas  
para  datos  de  entrenamiento  y  los  250  datos  restantes  se  reservan  para  pruebas.  El  código  completo  se  proporciona  a  continuación:

importar  cv2  
importar  numpy  como  np

SZ=20
bin_n  =  16  #  Número  de  contenedores

svm_params  =  dict( kernel_type  =  cv2.SVM_LINEAR,
tipo_svm  =  cv2.SVM_C_SVC,  C=2.67,  
gamma=5.383 )

affine_flags  =  cv2.WARP_INVERSE_MAP|cv2.INTER_LINEAR

def  enderezar(img):  m  =  
cv2.momentos(img)  if  
abs(m['mu02'])  <  1e­2:  return  img.copy()  
skew  =  m['mu11']/m['mu02']

M  =  np.float32([[1,  sesgo,  ­0.5*SZ*sesgo],  [0,  1,  0]])  img  =  cv2.warpAffine(img,M,(SZ,  
SZ),flags=affine_flags)  return  imagen

def  cerdo(img):  gx  =  
cv2.Sobel(img,  cv2.CV_32F,  1,  0)  gy  =  cv2.Sobel(img,  
cv2.CV_32F,  0,  1)  mag,  ang  =  cv2.cartToPolar(gx,  gy)  
contenedores  =  np.int32(bin_n*ang/(2*np.pi))  bin_cells  
=  contenedores[:10,:10],  contenedores[10:,:10],   #  cuantificación  de  binvalues  en  (0...16)
contenedores[:10,10:],  contenedores[10 :,10:]  mag_cells  =  mag[:10,:10],  mag[10:,:10],  mag[:10,10:],  mag[10:,10:]  
hists  =  [np.bincount(b .ravel(),  m.ravel(),  bin_n)  for  b,  m  in  zip(bin_cells,  mag_   →cells)]  hist  =  
np.hstack(hists)  return  hist

#  hist  es  un  vector  de  64  bits

img  =  cv2.imread('dígitos.png',0)

celdas  =  [np.hsplit(fila,100)  para  fila  en  np.vsplit(img,50)]

#  La  primera  mitad  es  trainData,  el  resto  es  testData  train_cells  =  [ i[:50]  para  i  
en  celdas]  test_cells  =  [ i[50:]  para  i  en  celdas]

###### ahora  entrenando #######################

enderezado  =  [mapa(enderezado,fila)  para  fila  en  train_cells]  hogdata  =  
[mapa(hog,fila)  para  fila  en  enderezado]  trainData  =  
np.float32(hogdata).reshape(­1,64)  respuestas  =  
np.float32( np.repeat(np.arange(10),250)[:,np.nuevoeje])

svm  =  cv2.SVM()  
svm.train(trainData,responses,  params=svm_params)  svm.save('svm_data.dat')

###### Ahora  probando #######################

238 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

enderezado  =  [mapa(enderezar,  fila)  para  fila  en  test_cells]  hogdata  =  
[mapa(hog,  fila)  para  fila  en  enderezar]  testData  =  
np.float32(hogdata).reshape(­1,bin_n*4)  resultado  =  svm.  predecir_todos(datos  
de  prueba)

#######  Comprobar  precisión  #######################  máscara  =  
resultado==respuestas  correctas  =  
np.count_nonzero(máscara)  imprimir  correcto*  
100.0/resultado.tamaño

Esta  técnica  en  particular  me  dio  casi  un  94%  de  precisión.  Puede  probar  diferentes  valores  para  varios  parámetros  de  SVM  para  verificar  
si  es  posible  una  mayor  precisión.  O  puede  leer  documentos  técnicos  sobre  esta  área  e  intentar  implementarlos.

Recursos  adicionales

1.  Video  de  histogramas  de  gradientes  orientados

Ejercicios

1.  Las  muestras  de  OpenCV  contienen  digits.py  que  aplica  una  ligera  mejora  del  método  anterior  para  mejorar
resultado.  También  contiene  la  referencia.  Compruébalo  y  entiéndelo.

Agrupación  de  K­Means

•  Comprensión  de  la  agrupación  en  clústeres  de  K­Means

Lea  para  obtener  una  comprensión  intuitiva  de  K­Means  Clustering

•  Agrupación  de  K­Means  en  OpenCV

Ahora  probemos  las  funciones  K­Means  en  OpenCV

1.8.  Aprendizaje  automático 239
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Comprensión  de  la  agrupación  en  clústeres  de  K­Means

Meta

En  este  capítulo,  comprenderemos  los  conceptos  de  K­Means  Clustering,  cómo  funciona,  etc.

Teoría

Trataremos  esto  con  un  ejemplo  que  se  usa  comúnmente.

Problema  con  la  talla  de  la  camiseta

Considere  una  empresa  que  va  a  lanzar  un  nuevo  modelo  de  camiseta  al  mercado.  Obviamente  tendrán  que  fabricar  modelos  en  diferentes  
tamaños  para  satisfacer  a  personas  de  todos  los  tamaños.  Entonces,  la  compañía  crea  datos  de  la  altura  y  el  peso  de  las  personas,  y  los  
representa  en  un  gráfico,  como  se  muestra  a  continuación:

La  empresa  no  puede  crear  camisetas  con  todos  los  tamaños.  En  su  lugar,  dividen  a  las  personas  en  pequeñas,  medianas  y  grandes,  y  fabrican  
solo  estos  3  modelos  que  encajarán  en  todas  las  personas.  Esta  agrupación  de  personas  en  tres  grupos  se  puede  hacer  mediante  la  agrupación  
de  k­means,  y  el  algoritmo  nos  proporciona  los  mejores  3  tamaños,  que  satisfarán  a  todas  las  personas.  Y  si  no  es  así,  la  empresa  puede  dividir  
a  las  personas  en  más  grupos,  pueden  ser  cinco,  y  así  sucesivamente.  Compruebe  la  imagen  a  continuación:

240 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Como  funciona ?

Este  algoritmo  es  un  proceso  iterativo.  Te  lo  explicamos  paso  a  paso  con  ayuda  de  imágenes.

Considere  un  conjunto  de  datos  como  se  muestra  a  continuación  (puede  considerarlo  como  un  problema  de  camiseta).  Necesitamos  agrupar  estos  datos  en  dos  grupos.

Paso:  1 :  el  algoritmo  elige  aleatoriamente  dos  centroides,  1  y  2  (a  veces,  dos  datos  cualesquiera  se  toman  como  centroides).

1.8.  Aprendizaje  automático 241
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Paso :  2  ­  Calcula  la  distancia  de  cada  punto  a  ambos  centroides.  Si  los  datos  de  una  prueba  están  más  cerca  de  1,  entonces  esos  datos  se  etiquetan  con  '0'.  Si  
está  más  cerca  de  2,  entonces  etiquételo  como  '1' (si  hay  más  centroides,  etiquételos  como  '2',  '3',  etc.).

En  nuestro  caso,  colorearemos  todos  los  '0'  etiquetados  con  rojo  y  los  '1'  etiquetados  con  azul.  Entonces  obtenemos  la  siguiente  imagen  después  de  las  
operaciones  anteriores.

Paso :  3  ­  Luego  calculamos  el  promedio  de  todos  los  puntos  azules  y  rojos  por  separado  y  esos  serán  nuestros  nuevos  centroides.
Es  decir,  1  y  2  se  desplazan  a  los  centroides  recién  calculados.  (Recuerde,  las  imágenes  que  se  muestran  no  son  valores  reales  y  no  están  a  escala  real,  es  solo  
para  demostración).

Y  nuevamente,  realice  el  paso  2  con  nuevos  centroides  y  etiquete  los  datos  en  '0'  y  '1'.

Entonces  obtenemos  el  resultado  de  la  siguiente  manera:

242 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Ahora  el  Paso  ­  2  y  el  Paso  ­  3  se  repiten  hasta  que  ambos  centroides  converjan  en  puntos  fijos.  (O  puede  detenerse  
según  los  criterios  que  proporcionamos,  como  el  número  máximo  de  iteraciones,  o  se  alcanza  una  precisión  específica,  etc.)
Estos  puntos  son  tales  que  la  suma  de  las  distancias  entre  los  datos  de  prueba  y  sus  centroides  correspondientes  son  mínimas.
O  simplemente,  la  suma  de  distancias  entre  1  ↔  _y  2  ↔  es  mínima. _

(1, _ )  +  ∑ (2, _


[  =  ∑ _
) ]

El  resultado  final  casi  se  ve  a  continuación:

1.8.  Aprendizaje  automático 243
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Así  que  esto  es  solo  una  comprensión  intuitiva  de  K­Means  Clustering.  Para  obtener  más  detalles  y  una  explicación  matemática,  lea  
cualquier  libro  de  texto  de  aprendizaje  automático  estándar  o  consulte  los  enlaces  en  recursos  adicionales.  Es  solo  una  capa  superior  del  
agrupamiento  de  K­Means.  Hay  muchas  modificaciones  a  este  algoritmo,  como  elegir  los  centroides  iniciales,  acelerar  el  proceso  de  
iteración,  etc.

Recursos  adicionales

1.  Curso  de  aprendizaje  automático,  Video  conferencias  del  Prof.  Andrew  Ng  (Algunas  de  las  imágenes  están  tomadas  de  esto)

Ejercicios

Agrupación  de  K­Means  en  OpenCV

Meta

•  Aprenda  a  usar  la  función  cv2.kmeans()  en  OpenCV  para  la  agrupación  de  datos

Comprender  los  parámetros

Parámetros  de  entrada

1.  muestras :  debe  ser  del  tipo  de  datos  np.float32 ,  y  cada  característica  debe  colocarse  en  una  sola  columna.

244 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

2.  nclusters(K) :  número  de  clústeres  requeridos  al  final

3.  criterio  [Es  el  criterio  de  terminación  de  la  iteración.  Cuando  se  cumple  este  criterio,  la  iteración  del  algoritmo  se  detiene.  De  hecho,
debe  ser  una  tupla  de  3  parámetros.  Ellos  son  (tipo,  max_iter,  epsilon):]

•  3.a  ­  tipo  de  criterio  de  terminación  [Tiene  3  banderas  como  se  muestra  a  continuación:]  cv2.TERM_CRITERIA_EPS  ­  detiene  la  
iteración  del  algoritmo  si  se  alcanza  la  precisión  especificada,  épsilon.  cv2.TERM_CRITERIA_MAX_ITER :  
detiene  el  
algoritmo  después  del  número  especificado  de  iteraciones,  max_iter.  cv2.TERM_CRITERIA_EPS  +  
cv2.TERM_CRITERIA_MAX_ITER :  detiene  la  iteración  cuando  se  cumple  alguna  de  las  condiciones  anteriores.

•  3.b  ­  max_iter:  un  número  entero  que  especifica  el  número  máximo  de  iteraciones.

•  3.c  ­  epsilon  ­  Precisión  requerida

4.  intentos :  Bandera  para  especificar  el  número  de  veces  que  se  ejecuta  el  algoritmo  usando  diferentes  etiquetas  iniciales.  El  algoritmo  devuelve  
las  etiquetas  que  producen  la  mejor  compacidad.  Esta  compacidad  se  devuelve  como  salida.

5.  banderas :  esta  bandera  se  utiliza  para  especificar  cómo  se  toman  los  centros  iniciales.  Normalmente  se  utilizan  dos  banderas  para  esto:
cv2.KMEANS_PP_CENTERS  y  cv2.KMEANS_RANDOM_CENTERS.

Parámetros  de  salida

1.  Compacidad :  Es  la  suma  de  las  distancias  al  cuadrado  de  cada  punto  a  sus  centros  correspondientes.

2.  etiquetas :  esta  es  la  matriz  de  etiquetas  (igual  que  'código'  en  el  artículo  anterior)  donde  cada  elemento  marcado  '0',  '1'...

3.  centros :  Esta  es  una  matriz  de  centros  de  grupos.

Ahora  veremos  cómo  aplicar  el  algoritmo  K­Means  con  tres  ejemplos.

1.  Datos  con  una  sola  función

Considere  que  tiene  un  conjunto  de  datos  con  una  sola  característica,  es  decir,  unidimensional.  Por  ejemplo,  podemos  tomar  nuestro  problema  de  la  
camiseta  donde  usas  solo  la  altura  de  las  personas  para  decidir  el  tamaño  de  la  camiseta.

Así  que  empezamos  por  crear  datos  y  trazarlos  en  Matplotlib

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

x  =  np.aleatorio.randint(25,100,25)  y  =  
np.aleatorio.randint(175,255,25)  z  =  np.hstack((x,y))  
z  =  z.reformar((50,1))  z  =  
np.float32(z)  plt.hist(z,256,
[0,256]),plt.show()

Así  que  tenemos  'z',  que  es  una  matriz  de  tamaño  50  y  valores  que  van  de  0  a  255.  He  reformado  'z'  en  un  vector  de  columna.
Será  más  útil  cuando  haya  más  de  una  característica  presente.  Luego  hice  datos  de  tipo  np.float32.

Obtenemos  la  siguiente  imagen:

1.8.  Aprendizaje  automático 245
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Ahora  aplicamos  la  función  KMeans.  Antes  de  eso  necesitamos  especificar  los  criterios.  Mi  criterio  es  tal  que,  cada  vez  que  
se  ejecutan  10  iteraciones  del  algoritmo,  o  se  alcanza  una  precisión  de  épsilon  =  1.0,  se  detiene  el  algoritmo  y  se  devuelve  el
respuesta.

#  Definir  criterio  =  ( tipo,  max_iter  =  10  criterio  =   ,  épsilon  =  1.0 )
(cv2.TERM_CRITERIA_EPS  +  cv2.TERM_CRITERIA_MAX_ITER,  10,  1.0)

#  Establecer  banderas  (solo  para  evitar  saltos  de  línea  en  el  código)  
banderas  =  cv2.KMEANS_RANDOM_CENTERS

#  Aplicar  KMeans  
compacidad,etiquetas,centros  =  cv2.kmeans(z,2,Ninguno,criterios,10,banderas)

Esto  nos  da  la  compacidad,  las  etiquetas  y  los  centros.  En  este  caso,  obtuve  centros  como  60  y  207.  Las  etiquetas  tendrán  el  
mismo  tamaño  que  los  datos  de  prueba,  donde  cada  dato  se  etiquetará  como  '0',  '1',  '2',  etc.,  según  sus  centroides.  Ahora  
dividimos  los  datos  en  diferentes  grupos  según  sus  etiquetas.

A  =  z[etiquetas==0]
B  =  z[etiquetas==1]

Ahora  trazamos  A  en  color  rojo  y  B  en  color  azul  y  sus  centroides  en  color  amarillo.

#  Ahora  trace  'A'  en  rojo,  'B'  en  azul,  'centros'  en  amarillo  plt.hist(A,256,[0,256],color  =  'r')  
plt.hist(B,256,[0,256],  color  =  'b')  plt.hist(centros,32,
[0,256],color  =  'y')  plt.show()

246 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

A  continuación  se  muestra  la  salida  que  obtuvimos:

2.  Datos  con  múltiples  características

En  el  ejemplo  anterior,  tomamos  solo  la  altura  para  el  problema  de  la  camiseta.  Aquí,  tomaremos  tanto  la  altura  como  el  peso,  es  decir,  dos  
características.

Recuerde,  en  el  caso  anterior,  convertimos  nuestros  datos  en  un  solo  vector  de  columna.  Cada  función  se  organiza  en  una  columna,  mientras  que  
cada  fila  corresponde  a  una  muestra  de  prueba  de  entrada.

Por  ejemplo,  en  este  caso,  configuramos  unos  datos  de  prueba  de  tamaño  50x2,  que  son  alturas  y  pesos  de  50  personas.  La  primera  columna  
corresponde  a  la  altura  de  las  50  personas  y  la  segunda  columna  corresponde  a  sus  pesos.  La  primera  fila  contiene  dos  elementos  donde  el  primero  
es  la  altura  de  la  primera  persona  y  el  segundo  su  peso.  Del  mismo  modo,  las  filas  restantes  corresponden  a  las  alturas  y  pesos  de  otras  personas.  
Compruebe  la  imagen  a  continuación:

1.8.  Aprendizaje  automático 247
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Ahora  me  muevo  directamente  al  código:

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

X  =  np.aleatorio.randint(25,50,(25,2))
Y  =  np.random.randint(60,85,(25,2))  
Z  =  np.vstack((X,Y))

#  convertir  a  np.float32  Z  =  np.float32(Z)

#  definir  criterios  y  aplicar  criterios  kmeans()  =  
(cv2.TERM_CRITERIA_EPS  +  cv2.TERM_CRITERIA_MAX_ITER,  10,  1.0)  
ret,label,center=cv2.kmeans(Z,2,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)

#  Ahora  separe  los  datos,  tenga  en  cuenta  el  flatten()
A  =  Z[etiqueta.ravel()==0]
B  =  Z[etiqueta.ravel()==1]

#  Graficar  los  datos
plt.dispersión(A[:,0],A[:,1])  
plt.dispersión(B[:,0],B[:,1],c  =  'r')  plt.dispersión(centro[:,  
0],centro[:,1],s  =  80,c  =  'y',  marcador  =  's')  plt.xlabel('Altura'),plt.ylabel('Peso')

248 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

plt.mostrar()

A  continuación  se  muestra  la  salida  que  obtenemos:

3.  Cuantificación  de  color

La  cuantificación  de  color  es  el  proceso  de  reducir  el  número  de  colores  en  una  imagen.  Una  razón  para  hacerlo  es  reducir  la  memoria.  A  
veces,  algunos  dispositivos  pueden  tener  limitaciones  tales  que  solo  pueden  producir  una  cantidad  limitada  de  colores.  En  esos  casos  
también,  se  realiza  la  cuantificación  del  color.  Aquí  usamos  el  agrupamiento  de  k­medias  para  la  cuantificación  del  color.

No  hay  nada  nuevo  que  explicar  aquí.  Hay  3  características,  digamos,  R,  G,  B.  Entonces,  necesitamos  remodelar  la  imagen  a  una  matriz  de  
tamaño  Mx3  (M  es  el  número  de  píxeles  en  la  imagen).  Y  después  de  la  agrupación,  aplicamos  valores  de  centroide  (también  es  R,  G,  B)  a  
todos  los  píxeles,  de  modo  que  la  imagen  resultante  tenga  una  cantidad  específica  de  colores.  Y  de  nuevo  tenemos  que  volver  a  darle  forma  
a  la  forma  de  la  imagen  original.  A  continuación  se  muestra  el  código:

importar  numpy  como  np  
importar  cv2

img  =  cv2.imread('inicio.jpg')
Z  =  imagen.reformar((­1,3))

#  convertir  a  np.float32  Z  =  
np.float32(Z)

#  definir  criterios,  número  de  clústeres  (K)  y  aplicar  criterios  kmeans()  =  
(cv2.TERM_CRITERIA_EPS  +  cv2.TERM_CRITERIA_MAX_ITER,  10,  1.0)
K  =  8

1.8.  Aprendizaje  automático 249
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

ret,etiqueta,centro=cv2.kmeans(Z,K,Ninguno,criterios,10,cv2.KMEANS_RANDOM_CENTERS)

#  Ahora  vuelva  a  convertir  a  uint8  y  haga  que  la  imagen  original  sea  center  =  
np.uint8(center)  res  =  center[label.flatten()]

res2  =  res.reforma((img.forma))

cv2.imshow('res2',res2)  cv2.waitKey(0)  
cv2.destroyAllWindows()

Vea  el  resultado  a  continuación  para  K  =  8:

Recursos  adicionales

Ejercicios

Fotografía  Computacional

Aquí  aprenderá  diferentes  funcionalidades  de  OpenCV  relacionadas  con  la  fotografía  computacional,  como  la  eliminación  de  ruido  de  imágenes,  etc.

•  Eliminación  de  ruido  de  imagen

250 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Vea  una  buena  técnica  para  eliminar  ruidos  en  imágenes  llamada  Medios  no  locales
eliminación  de  ruido

•  Repintado  de  imágenes

¿Tienes  una  foto  antigua  degradada  con  muchos  puntos  negros  y  trazos?
Tómalo.  Intentemos  restaurarlos  con  una  técnica  llamada  imagen  en  pintura.

1.9.  Fotografía  Computacional 251
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Eliminación  de  ruido  de  imagen

Meta

En  este  capítulo,

•  Aprenderá  sobre  el  algoritmo  de  eliminación  de  ruido  de  medios  no  locales  para  eliminar  el  ruido  en  la  imagen.

•  Verá  diferentes  funciones  como  cv2.fastNlMeansDenoising(),  cv2.fastNlMeansDenoisingColored()  etc.

Teoría

En  capítulos  anteriores,  hemos  visto  muchas  técnicas  de  suavizado  de  imágenes  como  Gaussian  Blurring,  Median  Blurring,  etc.  y  fueron  buenas  
hasta  cierto  punto  para  eliminar  pequeñas  cantidades  de  ruido.  En  esas  técnicas,  tomamos  un  pequeño  vecindario  alrededor  de  un  píxel  e  hicimos  
algunas  operaciones  como  el  promedio  ponderado  gaussiano,  la  mediana  de  los  valores,  etc.  para  reemplazar  el  elemento  central.  En  resumen,  
la  eliminación  de  ruido  en  un  píxel  era  local  para  su  vecindario.

Hay  una  propiedad  del  ruido.  Generalmente  se  considera  que  el  ruido  es  una  variable  aleatoria  con  media  cero.  Considere  un  píxel  con  ruido,  =  0  
+  donde  es  el  valor  real  del  píxel  y0  el  ruido  en  ese  píxel.  Puede  tomar  una  gran  cantidad  de  píxeles  iguales  (digamos)  de  diferentes  imágenes  y  
calcular  su  promedio.  Idealmente,  debería  obtener  =  ya  que  la  media  de  0  ruido  es  cero.

Puede  verificarlo  usted  mismo  mediante  una  configuración  simple.  Sostenga  una  cámara  estática  en  un  lugar  determinado  durante  un  par  de  
segundos.  Esto  le  dará  muchos  marcos  o  muchas  imágenes  de  la  misma  escena.  Luego,  escriba  un  fragmento  de  código  para  encontrar  el  
promedio  de  todos  los  cuadros  en  el  video  (Esto  debería  ser  demasiado  simple  para  usted  ahora).  Compara  el  resultado  final  y  el  primer  cuadro.  
Puede  ver  la  reducción  del  ruido.  Desafortunadamente,  este  método  simple  no  es  robusto  para  los  movimientos  de  la  cámara  y  la  escena.  
Además,  a  menudo  solo  hay  una  imagen  ruidosa  disponible.

Entonces,  la  idea  es  simple,  necesitamos  un  conjunto  de  imágenes  similares  para  promediar  el  ruido.  Considere  una  ventana  pequeña  (digamos  
una  ventana  de  5x5)  en  la  imagen.  Es  muy  probable  que  el  mismo  parche  esté  en  otro  lugar  de  la  imagen.  A  veces  en  un  pequeño  barrio  a  su  
alrededor.  ¿Qué  hay  de  usar  estos  parches  similares  juntos  y  encontrar  su  promedio?  Para  esa  ventana  en  particular,  está  bien.  Vea  una  imagen  
de  ejemplo  a  continuación:

252 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Los  parches  azules  en  la  imagen  se  ven  similares.  Los  parches  verdes  se  ven  similares.  Así  que  tomamos  un  píxel,  tomamos  una  ventana  pequeña  a  su  
alrededor,  buscamos  ventanas  similares  en  la  imagen,  promediamos  todas  las  ventanas  y  reemplazamos  el  píxel  con  el  resultado  que  obtuvimos.  Este  método  
es  Eliminación  de  ruido  de  medios  no  locales.  Lleva  más  tiempo  en  comparación  con  las  técnicas  de  desenfoque  que  vimos  anteriormente,  pero  su  resultado  es  
muy  bueno.  Se  pueden  encontrar  más  detalles  y  una  demostración  en  línea  en  el  primer  enlace  en  recursos  adicionales.

Para  imágenes  en  color,  la  imagen  se  convierte  al  espacio  de  color  CIELAB  y  luego  elimina  por  separado  los  componentes  L  y  AB.

Eliminación  de  ruido  de  imagen  en  OpenCV

OpenCV  proporciona  cuatro  variaciones  de  esta  técnica.

1.  cv2.fastNlMeansDenoising()  ­  funciona  con  una  sola  imagen  en  escala  de  grises

2.  cv2.fastNlMeansDenoisingColored()  ­  funciona  con  una  imagen  en  color.

3.  cv2.fastNlMeansDenoisingMulti()  ­  funciona  con  secuencias  de  imágenes  capturadas  en  un  corto  período  de  tiempo  (escala  de  grises
imágenes)

4.  cv2.fastNlMeansDenoisingColoredMulti()  ­  igual  que  arriba,  pero  para  imágenes  en  color.

Los  argumentos  comunes  son:

•  h :  parámetro  que  decide  la  intensidad  del  filtro.  Un  valor  h  más  alto  elimina  mejor  el  ruido,  pero  elimina  los  detalles  de  la  imagen
también.  (10  está  bien)

•  hForColorComponents:  igual  que  h,  pero  solo  para  imágenes  en  color.  (normalmente  igual  que  h)

•  templateWindowSize :  debe  ser  impar.  (recomendado  7)

•  searchWindowSize:  debe  ser  impar.  (recomendado  21)

Visite  el  primer  enlace  en  recursos  adicionales  para  obtener  más  detalles  sobre  estos  parámetros.

Demostraremos  2  y  3  aquí.  Te  queda  descanso.

1.  cv2.fastNlMeansDenoisingColored()

Como  se  mencionó  anteriormente,  se  utiliza  para  eliminar  el  ruido  de  las  imágenes  en  color.  (Se  espera  que  el  ruido  sea  gaussiano).  Vea  el  ejemplo  a  
continuación:

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

img  =  cv2.imread('morir.png')

dst  =  cv2.fastNlMeansDenoisingColored(img,Ninguno,10,10,7,21)

plt.subplot(121),plt.imshow(img)  
plt.subplot(122),plt.imshow(dst)  plt.show()

A  continuación  se  muestra  una  versión  ampliada  del  resultado.  Mi  imagen  de  entrada  tiene  un  ruido  gaussiano  de  =  25.  Vea  el  resultado:

1.9.  Fotografía  Computacional 253
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

2.  cv2.fastNlMeansDenoisingMulti()

Ahora  aplicaremos  el  mismo  método  a  un  video.  El  primer  argumento  es  la  lista  de  fotogramas  ruidosos.  El  segundo  argumento,  
imgToDenoiseIndex,  especifica  qué  cuadro  necesitamos  eliminar  el  ruido,  para  eso  pasamos  el  índice  del  cuadro  en  nuestra  lista  de  entrada.
El  tercero  es  el  tamaño  de  la  ventana  temporal,  que  especifica  el  número  de  fotogramas  cercanos  que  se  utilizarán  para  eliminar  el  ruido.  
Debería  ser  extraño.  En  ese  caso,  se  utiliza  un  total  de  tramas  de  tamaño  de  ventana  temporal  donde  la  trama  central  es  la  trama  que  se  va  a  eliminar.
Por  ejemplo,  pasó  una  lista  de  5  marcos  como  entrada.  Sea  imgToDenoiseIndex  =  2  y  temporalWindowSize  =  3.  Luego,  el  marco  1,  el  marco  2  
y  el  marco  3  se  usan  para  eliminar  el  ruido  del  marco  2.  Veamos  un  ejemplo.

importar  numpy  como  np  
importar  cv2  
desde  matplotlib  importar  pyplot  como  plt

tapa  =  cv2.VideoCapture('vtest.avi')

#  crear  una  lista  de  los  primeros  5  fotogramas
img  =  [cap.read()[1]  para  i  en  xrange(5)]

#  convertir  todo  a  gris  en  escala  de  grises  =  
[cv2.cvtColor(i,  cv2.COLOR_BGR2GRAY)  for  i  in  img]

254 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

#  convertir  todo  a  float64
gris  =  [np.float64(i)  para  i  en  gris]

#  crear  un  ruido  de  variación  25
ruido  =  np.random.randn(*gray[1].shape)*10

#  Agregue  este  ruido  a  las  imágenes  
ruidoso  =  [i+ruido  para  i  en  gris]

#  Convertir  de  nuevo  a  uint8  ruidoso  
=  [np.uint8(np.clip(i,0,255))  para  i  en  ruidoso]

#  Eliminación  de  ruido  en  el  tercer  cuadro  considerando  los  5  cuadros  dst  =  
cv2.fastNlMeansDenoisingMulti(noisy,  2,  5,  None,  4,  7,  35)

plt.subplot(131),plt.imshow(gris[2],'gris')  
plt.subplot(132),plt.imshow(ruidoso[2],'gris')  plt.subplot(133),plt.imshow  
(dst,'gris')  plt.mostrar()

La  imagen  de  abajo  muestra  una  versión  ampliada  del  resultado  que  obtuvimos:

1.9.  Fotografía  Computacional 255
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

256 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Se  necesita  una  cantidad  considerable  de  tiempo  para  el  cálculo.  Como  resultado,  la  primera  imagen  es  el  marco  original,  la  segunda  es  la  
ruidosa  y  la  tercera  es  la  imagen  sin  ruido.

Recursos  adicionales

1.  http://www.ipol.im/pub/art/2011/bcm_nlm/  (Tiene  los  detalles,  demostración  en  línea,  etc.  Muy  recomendable  para  visitar.
Nuestra  imagen  de  prueba  se  genera  a  partir  de  este  enlace)

2.  Curso  en  línea  en  Coursera  (Primera  imagen  tomada  de  aquí)

Ejercicios

Imagen  en  pintura

Meta

En  este  capítulo,

•  Aprenderemos  a  eliminar  pequeños  ruidos,  trazos,  etc.  en  fotografías  antiguas  mediante  un  método  llamado  inpainting.

•  Veremos  funcionalidades  de  pintura  en  OpenCV.

Lo  esencial

La  mayoría  de  ustedes  tendrá  algunas  fotos  antiguas  degradadas  en  su  casa  con  algunos  puntos  negros,  algunos  trazos,  etc.  ¿Alguna  vez  
has  pensado  en  restaurarlo?  No  podemos  simplemente  borrarlos  en  una  herramienta  de  pintura  porque  simplemente  reemplazará  las  
estructuras  negras  con  estructuras  blancas,  lo  cual  no  sirve  de  nada.  En  estos  casos,  se  utiliza  una  técnica  llamada  imagen  en  pintura.
La  idea  básica  es  simple:  reemplace  esas  malas  marcas  con  sus  píxeles  vecinos  para  que  se  vea  como  el  vecindario.
Considere  la  imagen  que  se  muestra  a  continuación  (tomada  de  Wikipedia):

Se  diseñaron  varios  algoritmos  para  este  propósito  y  OpenCV  proporciona  dos  de  ellos.  Se  puede  acceder  a  ambos  mediante  la  misma  
función,  cv2.inpaint()

El  primer  algoritmo  se  basa  en  el  artículo  "Una  técnica  de  pintura  de  imágenes  basada  en  el  método  de  marcha  rápida"  de  Alexandru  Telea  
en  2004.  Se  basa  en  el  método  de  marcha  rápida.  Considere  una  región  de  la  imagen  para  pintarla.  El  algoritmo  comienza  desde  el  límite  de  
esta  región  y  va  dentro  de  la  región  llenando  gradualmente  todo  lo  que  está  en  el  límite  primero.  Se  necesita  un  pequeño  vecindario  alrededor  
del  píxel  en  el  vecindario  para  pintarlo.  Este  píxel  se  reemplaza  por  la  suma  ponderada  normalizada  de  todos  los  píxeles  conocidos  en  el  
vecindario.  La  selección  de  los  pesos  es  un  asunto  importante.
Se  otorga  más  ponderación  a  los  píxeles  que  se  encuentran  cerca  del  punto,  cerca  de  la  normal  del  límite  y  los  que  se  encuentran  en  los  
contornos  del  límite.  Una  vez  que  se  vuelve  a  pintar  un  píxel,  se  mueve  al  siguiente  píxel  más  cercano  utilizando  el  método  de  marcha  rápida.  FMM

1.9.  Fotografía  Computacional 257
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

asegura  que  los  píxeles  cercanos  a  los  píxeles  conocidos  se  pinten  primero,  de  modo  que  funcione  como  una  operación  heurística  manual.
Este  algoritmo  se  habilita  mediante  el  uso  de  la  bandera,  cv2.INPAINT_TELEA.

El  segundo  algoritmo  se  basa  en  el  artículo  "Navier­Stokes,  Fluid  Dynamics,  and  Image  and  Video  Inpainting"  de  Bertalmio,  Marcelo,  Andrea  L.  Bertozzi  y  
Guillermo  Sapiro  en  2001.  Este  algoritmo  se  basa  en  la  dinámica  de  fluidos  y  utiliza  ecuaciones  diferenciales  parciales.  El  principio  básico  es  heurístico.  
Primero  viaja  a  lo  largo  de  los  bordes  desde  regiones  conocidas  a  regiones  desconocidas  (porque  los  bordes  deben  ser  continuos).  Continúa  isófotas  
(líneas  que  unen  puntos  con  la  misma  intensidad,  al  igual  que  los  contornos  unen  puntos  con  la  misma  elevación)  mientras  hace  coincidir  los  vectores  de  
gradiente  en  el  límite  de  la  región  de  pintura.  Para  ello  se  utilizan  algunos  métodos  de  la  dinámica  de  fluidos.  Una  vez  que  se  obtienen,  se  rellena  el  color  
para  reducir  la  varianza  mínima  en  esa  área.  Este  algoritmo  se  habilita  mediante  el  uso  de  la  bandera,  cv2.INPAINT_NS.

Código

Necesitamos  crear  una  máscara  del  mismo  tamaño  que  la  de  la  imagen  de  entrada,  donde  los  píxeles  distintos  de  cero  corresponden  al  área  que  se  va  a  
pintar.  Todo  lo  demás  es  simple.  Mi  imagen  está  degradada  con  algunos  trazos  negros  (agregué  manualmente).  Creé  los  trazos  correspondientes  con  la  
herramienta  Paint.

importar  numpy  como  np  
importar  cv2

img  =  cv2.imread('messi_2.jpg')  máscara  =  
cv2.imread('mask2.png',0)

dst  =  cv2.inpaint(img,máscara,3,cv2.INPAINT_TELEA)

cv2.imshow('dst',dst)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

Vea  el  resultado  a  continuación.  La  primera  imagen  muestra  una  entrada  degradada.  La  segunda  imagen  es  la  máscara.  La  tercera  imagen  es  el  resultado  
del  primer  algoritmo  y  la  última  imagen  es  el  resultado  del  segundo  algoritmo.

258 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

1.  Bertalmio,  Marcelo,  Andrea  L.  Bertozzi  y  Guillermo  Sapiro.  “Navier­stokes,  dinámica  de  fluidos  y  pintura  de  imágenes  y  videos”.  En  
Computer  Vision  and  Pattern  Recognition,  2001.  CVPR  2001.  Actas  de  la  Conferencia  de  la  IEEE  Computer  Society  de  2001  en,  
vol.  1,  págs.  I­355.  IEEE,  2001.

2.  Telea,  Alexandru.  “Una  técnica  de  pintura  de  imagen  basada  en  el  método  de  marcha  rápida”.  diario  de  gráficos
herramientas  9.1  (2004):  23­34.

Ejercicios

1.  OpenCV  viene  con  una  muestra  interactiva  sobre  pintura,  samples/python2/inpaint.py,  pruébalo.

2.  Hace  unos  meses,  vi  un  video  sobre  Content­Aware  Fill,  una  técnica  avanzada  de  pintura  utilizada  en  Adobe  Photoshop.  En  una  
búsqueda  posterior,  pude  encontrar  que  la  misma  técnica  ya  está  en  GIMP  con  un  nombre  diferente,  "Resintetizador" (Necesita  
instalar  un  complemento  por  separado).  Estoy  seguro  de  que  disfrutarás  de  la  técnica.

Detección  de  objetos

•  Detección  de  rostros  usando  Haar  Cascades

1.10.  Detección  de  objetos 259
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Detección  de  rostros  mediante  cascadas  haar

260 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Detección  de  rostros  usando  cascadas  Haar

Meta

En  esta  sesión,

•  Veremos  los  conceptos  básicos  de  la  detección  de  rostros  utilizando  los  clasificadores  en  cascada  basados  en  características  de  Haar.

•  Extenderemos  lo  mismo  para  la  detección  ocular,  etc.

Lo  esencial

La  detección  de  objetos  mediante  clasificadores  en  cascada  basados  en  funciones  de  Haar  es  un  método  eficaz  de  detección  de  objetos  
propuesto  por  Paul  Viola  y  Michael  Jones  en  su  artículo,  "Detección  rápida  de  objetos  mediante  una  cascada  potenciada  de  funciones  simples"  
en  2001.  Es  un  enfoque  basado  en  el  aprendizaje  automático  en  el  que  un  La  función  de  cascada  se  entrena  a  partir  de  muchas  imágenes  
positivas  y  negativas.  Luego  se  usa  para  detectar  objetos  en  otras  imágenes.

Aquí  trabajaremos  con  la  detección  de  rostros.  Inicialmente,  el  algoritmo  necesita  muchas  imágenes  positivas  (imágenes  de  rostros)  e  imágenes  
negativas  (imágenes  sin  rostros)  para  entrenar  al  clasificador.  Luego  necesitamos  extraer  características  de  él.  Para  esto,  se  utilizan  las  
características  de  haar  que  se  muestran  en  la  imagen  a  continuación.  Son  como  nuestro  kernel  convolucional.  Cada  característica  es  un  valor  
único  obtenido  al  restar  la  suma  de  píxeles  debajo  del  rectángulo  blanco  de  la  suma  de  píxeles  debajo  del  rectángulo  negro.

Ahora  todos  los  tamaños  y  ubicaciones  posibles  de  cada  kernel  se  utilizan  para  calcular  muchas  características.  (Imagínense  cuántos  cálculos  
necesita?  Incluso  una  ventana  de  24x24  da  como  resultado  más  de  160000  características).  Para  cada  cálculo  de  características,  necesitamos  
encontrar  la  suma  de  píxeles  debajo  de  los  rectángulos  blanco  y  negro.  Para  solucionar  esto,  introdujeron  las  imágenes  integrales.  Simplifica  
el  cálculo  de  la  suma  de  píxeles,  cuán  grande  puede  ser  el  número  de  píxeles,  a  una  operación  que  involucra  solo  cuatro  píxeles.  Bonito,  ¿no?  
Hace  las  cosas  súper  rápido.

Pero  entre  todas  estas  características  que  calculamos,  la  mayoría  de  ellas  son  irrelevantes.  Por  ejemplo,  considere  la  imagen  de  abajo.  La  fila  
superior  muestra  dos  buenas  características.  La  primera  característica  seleccionada  parece  centrarse  en  la  propiedad  de  que  la  región  de  los  
ojos  suele  ser  más  oscura  que  la  región  de  la  nariz  y  las  mejillas.  La  segunda  característica  seleccionada  se  basa  en  la  propiedad  de  que  los  ojos

1.10.  Detección  de  objetos 261
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

son  más  oscuros  que  el  puente  de  la  nariz.  Pero  las  mismas  ventanas  que  se  aplican  en  las  mejillas  o  en  cualquier  otro  lugar  son  irrelevantes.  Entonces,  
¿cómo  seleccionamos  las  mejores  funciones  entre  más  de  160  000  funciones?  Lo  consigue  Adaboost.

Para  ello,  aplicamos  todas  y  cada  una  de  las  funciones  en  todas  las  imágenes  de  entrenamiento.  Para  cada  característica,  encuentra  el  mejor  umbral  
que  clasificará  las  caras  en  positivas  y  negativas.  Pero  obviamente,  habrá  errores  o  clasificaciones  erróneas.  Seleccionamos  las  características  con  la  
tasa  de  error  mínima,  lo  que  significa  que  son  las  características  que  mejor  clasifican  las  imágenes  de  rostros  y  no  rostros.
(El  proceso  no  es  tan  simple  como  esto.  A  cada  imagen  se  le  da  el  mismo  peso  al  principio.  Después  de  cada  clasificación,  se  aumentan  los  pesos  de  
las  imágenes  clasificadas  incorrectamente.  Luego,  nuevamente  se  realiza  el  mismo  proceso.  Se  calculan  nuevas  tasas  de  error.  También  nuevos  pesos.  
El  el  proceso  continúa  hasta  que  se  logra  la  precisión  requerida  o  la  tasa  de  error  o  se  encuentra  el  número  requerido  de  características).

El  clasificador  final  es  una  suma  ponderada  de  estos  clasificadores  débiles.  Se  llama  débil  porque  por  sí  solo  no  puede  clasificar  la  imagen,  pero  junto  
con  otros  forma  un  clasificador  fuerte.  El  documento  dice  que  incluso  200  funciones  brindan  detección  con  una  precisión  del  95%.  Su  configuración  final  
tenía  alrededor  de  6000  funciones.  (Imagine  una  reducción  de  más  de  160 000  funciones  a  6000  funciones.
Eso  es  una  gran  ganancia).

Así  que  ahora  tomas  una  imagen.  Tome  cada  ventana  de  24x24.  Aplicarle  6000  características.  Comprueba  si  es  cara  o  no.  Guau..
Wow...  ¿No  es  un  poco  ineficiente  y  requiere  mucho  tiempo?  Sí,  lo  es.  Los  autores  tienen  una  buena  solución  para  eso.

En  una  imagen,  la  mayor  parte  de  la  región  de  la  imagen  es  una  región  sin  rostro.  Por  lo  tanto,  es  una  mejor  idea  tener  un  método  simple  para  verificar  
si  una  ventana  no  es  una  región  de  la  cara.  Si  no  es  así,  deséchalo  de  un  solo  tiro.  No  vuelvas  a  procesarlo.  En  su  lugar,  concéntrese  en  la  región  donde  
puede  haber  una  cara.  De  esta  manera,  podemos  encontrar  más  tiempo  para  comprobar  una  posible  región  de  la  cara.

Para  ello  introdujeron  el  concepto  de  Cascada  de  Clasificadores.  En  lugar  de  aplicar  todas  las  6000  funciones  en  una  ventana,  agrupe  las  funciones  en  
diferentes  etapas  de  clasificadores  y  aplíquelas  una  por  una.  (Normalmente,  las  primeras  etapas  contendrán  una  cantidad  muy  inferior  de  características).  
Si  una  ventana  falla  en  la  primera  etapa,  deséchela.  No  consideramos  las  funciones  restantes  en  él.
Si  pasa,  aplique  la  segunda  etapa  de  características  y  continúe  el  proceso.  La  ventana  que  pasa  por  todas  las  etapas  es  una  región  frontal.  Que  tal  el  
plan!!!

El  detector  de  autores  tenía  más  de  6000  funciones  con  38  etapas  con  1,  10,  25,  25  y  50  funciones  en  las  primeras  cinco  etapas.  (Dos  funciones  en  la  
imagen  de  arriba  se  obtienen  en  realidad  como  las  dos  mejores  funciones  de  Adaboost).  Según  los  autores,  en  promedio,  se  evalúan  10  características  
de  más  de  6000  por  subventana.

Así  que  esta  es  una  explicación  simple  e  intuitiva  de  cómo  funciona  la  detección  de  rostros  de  Viola­Jones.  Lea  el  documento  para  obtener  más  detalles  
o  consulte  las  referencias  en  la  sección  Recursos  adicionales.

262 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Detección  de  cascada  de  cabello  en  OpenCV

OpenCV  viene  con  un  entrenador  y  un  detector.  Si  desea  entrenar  su  propio  clasificador  para  cualquier  objeto  como  automóvil,  avión,  etc.,  puede  usar  
OpenCV  para  crear  uno.  Sus  detalles  completos  se  dan  aquí:  Entrenamiento  de  clasificador  en  cascada.

Aquí  nos  ocuparemos  de  la  detección.  OpenCV  ya  contiene  muchos  clasificadores  preentrenados  para  cara,  ojos,  sonrisa,  etc.
Esos  archivos  XML  se  almacenan  en  la  carpeta  opencv/data/haarcascades/.  Vamos  a  crear  un  detector  de  cara  y  ojos  con  OpenCV.

Primero  necesitamos  cargar  los  clasificadores  XML  requeridos.  Luego  cargue  nuestra  imagen  de  entrada  (o  video)  en  modo  de  escala  de  grises.

importar  numpy  como  np  
importar  cv2

face_cascade  =  cv2.CascadeClassifier('haarcascade_frontalface_default.xml')  eye_cascade  =  
cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

img  =  cv2.imread('sachin.jpg')  gris  =  
cv2.cvtColor(img,  cv2.COLOR_BGR2GRAY)

Ahora  encontramos  las  caras  en  la  imagen.  Si  se  encuentran  rostros,  devuelve  las  posiciones  de  los  rostros  detectados  como  Rect(x,y,w,h).  Una  vez  que  
obtengamos  estas  ubicaciones,  podemos  crear  un  ROI  para  la  cara  y  aplicar  la  detección  de  ojos  en  este  ROI  (¡ya  que  los  ojos  siempre  están  en  la  cara!).

caras  =  face_cascade.detectMultiScale(gris,  1.3,  5)  para  (x,y,w,h)  en  caras:  img  
=  cv2.rectangle(img,(x,y),(x+w,y+h),
( 255,0,0),2)  roi_gray  =  gris[y:y+h,  x:x+w]  roi_color  =  img[y:y+h,  x:x+w]  ojos  =  
eye_cascade.detectMultiScale(roi_gray)  para  
(ej,ey,ew,eh)  en  los  ojos:

cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

cv2.imshow('img',img)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

El  resultado  se  ve  a  continuación:

1.10.  Detección  de  objetos 263
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

Recursos  adicionales

1.  Conferencia  en  video  sobre  detección  y  seguimiento  de  rostros

2.  Una  interesante  entrevista  sobre  Detección  de  Rostros  por  Adam  Harvey

Ejercicios

Enlaces  OpenCV­Python

Aquí,  aprenderá  cómo  se  generan  los  enlaces  OpenCV­Python.

•  ¿ Cómo  funcionan  los  enlaces  OpenCV­Python?

Aprenda  cómo  se  generan  los  enlaces  OpenCV­Python.

264 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

¿Cómo  funcionan  los  enlaces  OpenCV­Python?

Meta

Aprender:

•  ¿Cómo  se  generan  los  enlaces  OpenCV­Python?

•  ¿Cómo  extender  nuevos  módulos  OpenCV  a  Python?

¿Cómo  se  generan  los  enlaces  OpenCV­Python?

En  OpenCV,  todos  los  algoritmos  se  implementan  en  C++.  Pero  estos  algoritmos  se  pueden  usar  desde  diferentes  lenguajes  como  Python,  Java,  etc.  
Esto  es  posible  gracias  a  los  generadores  de  enlaces.  Estos  generadores  crean  un  puente  entre  C++  y  Python  que  permite  a  los  usuarios  llamar  a  
funciones  de  C++  desde  Python.  Para  obtener  una  imagen  completa  de  lo  que  sucede  en  segundo  plano,  se  requiere  un  buen  conocimiento  de  la  API  
de  Python/C.  Puede  encontrar  un  ejemplo  simple  sobre  cómo  extender  las  funciones  de  C++  a  Python  en  la  documentación  oficial  de  Python[1].  Por  lo  
tanto,  extender  todas  las  funciones  de  OpenCV  a  Python  escribiendo  sus  funciones  de  contenedor  manualmente  es  una  tarea  que  requiere  mucho  
tiempo.  Entonces  OpenCV  lo  hace  de  una  manera  más  inteligente.  OpenCV  genera  estas  funciones  contenedoras  automáticamente  desde  los  
encabezados  de  C++  utilizando  algunos  scripts  de  Python  que  se  encuentran  en  módulos/python/src2.  Investigaremos  qué  hacen.

Primero,  modules/python/CMakeFiles.txt  es  un  script  de  CMake  que  verifica  los  módulos  que  se  extenderán  a  Python.  Verificará  automáticamente  todos  
los  módulos  que  se  extenderán  y  tomará  sus  archivos  de  encabezado.  Estos  archivos  de  encabezado  contienen  una  lista  de  todas  las  clases,  funciones,  
constantes,  etc.  para  esos  módulos  en  particular.

En  segundo  lugar,  estos  archivos  de  encabezado  se  pasan  a  un  script  de  Python,  módulos/python/src2/gen2.py.  Este  es  el  script  del  generador  de  
enlaces  de  Python.  Llama  a  otros  módulos  de  script  de  Python/python/src2/hdr_parser.py.  Esta  es  la  secuencia  de  comandos  del  analizador  de  
encabezado.  Este  analizador  de  encabezado  divide  el  archivo  de  encabezado  completo  en  pequeñas  listas  de  Python.  Por  lo  tanto,  estas  listas  contienen  
todos  los  detalles  sobre  una  función,  clase,  etc.  en  particular.  Por  ejemplo,  se  analizará  una  función  para  obtener  una  lista  que  contenga  el  nombre  de  la  
función,  el  tipo  de  retorno,  los  argumentos  de  entrada,  los  tipos  de  argumentos,  etc.  La  lista  final  contiene  detalles  de  todas  las  funciones,  estructuras ,  
clases,  etc.  en  ese  archivo  de  encabezado.

Pero  el  analizador  de  encabezado  no  analiza  todas  las  funciones/clases  en  el  archivo  de  encabezado.  El  desarrollador  debe  especificar  qué  funciones  
se  deben  exportar  a  Python.  Para  eso,  se  agregan  ciertas  macros  al  comienzo  de  estas  declaraciones  que  permiten  que  el  analizador  de  encabezado  
identifique  las  funciones  que  se  analizarán.  Estas  macros  son  agregadas  por  el  desarrollador  que  programa  la  función  particular.  En  resumen,  el  
desarrollador  decide  qué  funciones  se  deben  extender  a  Python  y  cuáles  no.  Los  detalles  de  esas  macros  se  darán  en  la  próxima  sesión.

Entonces,  el  analizador  de  encabezado  devuelve  una  gran  lista  final  de  funciones  analizadas.  Nuestro  script  generador  (gen2.py)  creará  funciones  
contenedoras  para  todas  las  funciones/clases/enumeraciones/estructuras  analizadas  por  el  analizador  de  encabezado  (puede  encontrar  estos  archivos  
de  encabezado  durante  la  compilación  en  la  carpeta  build/modules/python/  como  archivos  pyopencv_generated_*.h ).  Pero  puede  haber  algunos  tipos  
de  datos  básicos  de  OpenCV  como  Mat,  Vec4i,  Size.  Deben  extenderse  manualmente.  Por  ejemplo,  un  tipo  Mat  debe  extenderse  a  una  matriz  Numpy,  
Size  debe  extenderse  a  una  tupla  de  dos  enteros,  etc.  De  manera  similar,  puede  haber  algunas  estructuras/clases/funciones  complejas,  etc.  que  deben  
extenderse  manualmente.  Todas  estas  funciones  de  contenedor  manual  se  colocan  en  módulos/python/src2/pycv2.hpp.

Así  que  ahora  lo  único  que  queda  es  la  compilación  de  estos  archivos  de  contenedor  que  nos  da  el  módulo  cv2 .  Entonces,  cuando  llama  a  una  función,  
diga  res  =  equalizeHist  (img1,  img2)  en  Python,  pasa  dos  matrices  numpy  y  espera  otra  matriz  numpy  como  salida.  Entonces,  estas  matrices  numpy  se  
convierten  en  cv::Mat  y  luego  llaman  a  la  función  equalizeHist()  en  C++.  Resultado  final,  res  se  convertirá  nuevamente  en  una  matriz  Numpy.  En  
resumen,  casi  todas  las  operaciones  se  realizan  en  C  ++,  lo  que  nos  brinda  casi  la  misma  velocidad  que  la  de  C  ++.

Así  que  esta  es  la  versión  básica  de  cómo  se  generan  los  enlaces  OpenCV­Python.

1.11.  Enlaces  OpenCV­Python 265
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

¿Cómo  extender  nuevos  módulos  a  Python?

El  analizador  de  encabezado  analiza  los  archivos  de  encabezado  en  función  de  algunas  macros  contenedoras  agregadas  a  la  declaración  de  la  función.  
Las  constantes  de  enumeración  no  necesitan  ninguna  macro  contenedora.  Se  envuelven  automáticamente.  Pero  las  funciones,  clases,  etc.  restantes  
necesitan  macros  contenedoras.

Las  funciones  se  amplían  utilizando  la  macro  CV_EXPORTS_W.  A  continuación  se  muestra  un  ejemplo.

CV_EXPORTS_W  void  equalizeHist( InputArray  src,  OutputArray  dst );

El  analizador  de  encabezado  puede  comprender  los  argumentos  de  entrada  y  salida  de  palabras  clave  como  InputArray,  OutputArray,  etc.  Pero  a  veces,  
es  posible  que  necesitemos  codificar  entradas  y  salidas.  Para  ello,  se  utilizan  macros  como  CV_OUT,  CV_IN_OUT,  etc.

CV_EXPORTS_W  void  minEnclosingCircle( Puntos  InputArray,
CV_OUT  Point2f&  centro,  CV_OUT  float&  radio);

También  para  clases  grandes,  se  utiliza  CV_EXPORTS_W.  Para  ampliar  los  métodos  de  clase,  se  utiliza  CV_WRAP.  De  manera  similar,  CV_PROP  se  
usa  para  campos  de  clase.

clase  CV_EXPORTS_W  CLAHE :  Algoritmo  público  { público:

Aplicación  de  vacío  virtual  CV_WRAP  (InputArray  src,  OutputArray  dst)  =  0;

CV_WRAP  virtual  void  setClipLimit(doble  clipLimit)  =  0;
CV_WRAP  doble  virtual  getClipLimit()  const  =  0;
}

Las  funciones  sobrecargadas  se  pueden  ampliar  mediante  CV_EXPORTS_AS.  Pero  necesitamos  pasar  un  nuevo  nombre  para  que  cada  función  sea  
llamada  por  ese  nombre  en  Python.  Tome  el  caso  de  la  función  integral  a  continuación.  Hay  tres  funciones  disponibles,  por  lo  que  cada  una  se  nombra  
con  un  sufijo  en  Python.  De  manera  similar,  CV_WRAP_AS  se  puede  usar  para  envolver  métodos  sobrecargados.

//!  calcula  la  imagen  integral  CV_EXPORTS_W  void  
integral( InputArray  src,  OutputArray  sum,  int  s  depth  =  ­1 );

//!  calcula  la  imagen  integral  y  la  integral  para  la  imagen  cuadrada  CV_EXPORTS_AS(integral2)  void  
integral( InputArray  src,  OutputArray  sum,
OutputArray  sqsum,  int  s  depth  =  ­1,  int
→profundidad  cuadrada  =  ­1 );

//!  calcula  la  imagen  integral,  la  integral  para  la  imagen  al  cuadrado  y  la  imagen  integral  inclinada   →  CV_EXPORTS_AS(integral3)  
void  integral( InputArray  
src,  OutputArray  sum,
OutputArray  sqsum,  OutputArray  inclinado,  int  profundidad  =  ­1,  
int  profundidad  cuadrada  =  ­1 );

Las  clases/estructuras  pequeñas  se  amplían  mediante  CV_EXPORTS_W_SIMPLE.  Estas  estructuras  se  pasan  por  valor  a  las  funciones  de  C++.  Los  
ejemplos  son  KeyPoint,  Match,  etc.  Sus  métodos  se  amplían  con  CV_WRAP  y  los  campos  se  amplían  con  CV_PROP_RW.

clase  CV_EXPORTS_W_SIMPLE  DMatch

{ público:
CV_WRAP  DMatch();
CV_WRAP  DMatch(int  _queryIdx,  int  _trainIdx,  float  _distance);
CV_WRAP  DMatch(int  _queryIdx,  int  _trainIdx,  int  _imgIdx,  float  _distance);

266 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

CV_PROP_RW  int  consultaIdx; //  índice  del  descriptor  de  la  consulta
CV_PROP_RW  int  trenIdx; //  índice  del  descriptor  del  tren
CV_PROP_RW  int  imgIdx; //  índice  de  la  imagen  del  tren

CV_PROP_RW  distancia  flotante ;

Algunas  otras  clases/estructuras  pequeñas  se  pueden  exportar  usando  CV_EXPORTS_W_MAP  donde  se  exporta  a  un  diccionario  nativo  de  
Python.  Moments()  es  un  ejemplo  de  ello.

class  CV_EXPORTS_W_MAP  Momentos  { public: //!  

momentos  
espaciales  CV_PROP_RW  
doble  m00,  m10,  m01,  m20,  m11,  m02,  m30,  m21,  m12,  m03; //!  momentos  centrales

CV_PROP_RW  doble  mu20,  mu11,  mu02,  mu30,  mu21,  mu12,  mu03; //!  momentos  centrales  
normalizados
CV_PROP_RW  doble  nu20,  nu11,  nu02,  nu30,  nu21,  nu12,  nu03;

Estas  son  las  principales  macros  de  extensión  disponibles  en  OpenCV.  Por  lo  general,  un  desarrollador  tiene  que  colocar  las  macros  
adecuadas  en  sus  posiciones  correspondientes.  El  resto  lo  hacen  los  scripts  del  generador.  A  veces,  puede  haber  casos  excepcionales  en  
los  que  los  scripts  del  generador  no  puedan  crear  los  contenedores.  Tales  funciones  deben  manejarse  manualmente.  Pero  la  mayoría  de  las  
veces,  un  código  escrito  de  acuerdo  con  las  pautas  de  codificación  de  OpenCV  será  envuelto  automáticamente  por  scripts  generadores.

1.11.  Enlaces  OpenCV­Python 267
Machine Translated by Google

Documentación  de  tutoriales  de  OpenCV­Python,  versión  1

268 Capítulo  1.  Tutoriales  de  OpenCV­Python
Machine Translated by Google

CAPÍTULO  2

índices  y  tablas

•  volver  a  indexar

•  índice  de  modificación

•  buscar

269

También podría gustarte