jueves, 9 de febrero de 2017

Eclipse como me gusta

Novateando con Eclipse Neon

Ok, ya van varias veces que intento usar Eclipse, pero a la fecha no nos hemos llevado demasiado bien.  Parece que las cosas van a mejorar, pero he tenido que configurar varias cosillas.
  1. Descargar e instalar Eclipse localmente.
    https://www.eclipse.org/downloads/
  2. Agregar el lanzador al menú de Xubuntu.
  3. Instalar CMakeEditor.  No se logra conectar a SourceForge, reportando un "handshake failure". 
    1. Hay que descargar el .zip de sourceforge directamente.
    2. Help->Install new software...->Add...->Archive->CMakeEd-1.3.0.zip
    3. Aparecerá la opción para instalar CMakeEd, seguir las instrucciones.
  4. Configurar a Eclipse para trabajar con mis proyectos que usan CMake.
    https://cmake.org/Wiki/CMake:Eclipse_UNIX_Tutorial
  5. Cambiarle la consola para poder imprimir a colores:
    • Instalar TM Terminal
    • Window->Preferences->Terminal->Local terminal
    • Sólo logro arrancarla con Ctrl+Alt+Shift+T porque si no abre la terminal de xubuntu, pero funciona.  Tampoco

jueves, 1 de diciembre de 2016

Kinect v2 en Linux con CUDA 7.5


  • Descargar los fuentes

$ git clone https://github.com/OpenKinect/libfreenect2.git
$ cd libfreenect2


  • Herramientas para compilar

$ sudo apt-get install build-essential cmake pkg-config

Dependencias

$ sudo apt-get install libusb-1.0-0-dev
$ sudo apt-get install libturbojpeg libjpeg-turbo8-dev
$ sudo apt-get install libglfw3-dev

Problema: OpenCL con beignet-dev elimina opencl de nvidia-opencl-dev => no instalar, instalar el de nvidia

Para generar la documentación es necesario tener también:

$ sudo apt-get install doxygen

de lo contrario se marcará el error:
-- Could NOT find Doxygen (missing:  DOXYGEN_EXECUTABLE)
al configurar con cmake.

  • Habilitar driver de nvidia

$ sudo apt-get install nvidia-cuda-toolkit

  • Descargar el .deb para Ubuntu 15.04 de la página oficial y extraer el .deb con los ejemplos (samples), sale un data.tar.gz, extraerlos de ahí e instalar ejemplos

[No recuerdo para qué utilizé la linea siguiente, pero en instalaciones siguientes no la he necesitado]
$ grep -rl "CUDA_PATH ?= /usr/local/cuda" ./ | xargs sed -i 's:CUDA_PATH ?= /usr/local/cuda:CUDA_PATH ?= /usr:g'


$ sudo apt-get install libva-dev libjpeg-dev
$ sudo apt-get install libopenni2-dev

No logreé que funcionara el código para OpenNI.

Build


  • Modificar en CMakeLists:

CUDA_INCLUDE_DIRECTORIES(
      "${MY_DIR}/include/"
      "[path_to]/CudaSamples/NVIDIA_CUDA-7.5_Samples/common/inc"    #"${CUDA_TOOLKIT_ROOT_DIR}/samples/common/inc"
      "${NVCUDASAMPLES_ROOT}/common/inc"
    )

$ mkdir compile
$ cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/Programacion/libfreenect2/build/freenect2 -DCUDA_NVCC_FLAGS="-D_FORCE_INLINES"
$ make
$ make install
$ make doc

Copiar las reglas de udev:

sudo cp platform/linux/udev/90-kinect2.rules /etc/udev/rules.d/

Probar con los demos, como Protonect, sí funciona.

OpenCV

$ sudo apt install libav-tools

$ cmake -D PYTHON3_INCLUDE_DIR=/usr/include/python3.5m -DPYTHON3_INCLUDE_DIR2=/usr/include/x86_64-linux-gnu/python3.5m -D PYTHON3_NUMPY_INCLUDE_DIRS=/home/blackzafiro/.local/lib/python3.5/site-packages/numpy/core/include -DINSTALL_PYTHON_EXAMPLES=ON -DCMAKE_INSTALL_PREFIX=/home/blackzafiro/Descargas/Programacion/opencv/opencv-3.1.0/build ..

OpenCV 3.1.0

Compilar versión estable

Cada vez que compilo OpenCV, configurarlo es todo un triunfo.  Pero uso muchas dependencias, por lo que mejor anoto aquí lo usual:

Aunque existe una página con el procedimiento y es útil pasar por ahí primero, aquí dejo mi acordeón.

Dependencias

libgtk-3-dev        ?
libgtk2.0-dev
libqt4-dev

libvtk6-dev
libopenni-dev

libav-tools
libavcodec-dev
libavformat-dev
libswscale-dev

libjpeg-dev
libpng-dev
libtiff-dev
libjasper-dev

libdc1394-22        # Caḿaras IEEE
libdc1394-22-dev

libtbb2             # Paralelismo
libtbb-dev

libgtkglext1-dev

python3-dev
python3-numpy
python-dev
python-numpy

nvidia-cuda-dev
nvidia-cuda-gdb
nvidia-cuda-toolkit

Configurar y compilar

Editar el archivo cmake/FindCUDA.cmake:

Cambiar la línea 711:

711 PATHS "/usr/lib/nvidia-current" "/usr/lib/nvidia-361"

de modo que la segunda dirección se la del driver de nvidia, donde se encuentra el archivo libnvcuvid.so.  Dara algunas advertencias, pero funciona como debe.

En la línea 799 insertar:

799 if(CUDA_VERSION VERSION_GREATER "7.0")

800   find_cuda_helper_libs(nvcuvid)

801 endif()
Otra opción es indicar el directorio de este archivo a cmake, como se indica a continuación.

$ mkdir compile
$ mkdir build
$ cd compile
$ cmake -DCMAKE_INSTALL_PREFIX=</home/...> -DWITH_OPENGL=ON -DWITH_QT=ON -DWITH_VTK=ON -DWITH_OPENNI=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCUDA_NVCC_FLAGS="-D_FORCE_INLINES" -D PYTHON3_INCLUDE_DIR=/usr/include/python3.5m -DINSTALL_PYTHON_EXAMPLES=ON -DCUDA_cublas_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libcublas.so -DWITH_CUBLAS=ON -DWITH_NVCUVID=ON -DCUDA_nvcuvid_LIBRARY:FILEPATH=/usr/lib/nvidia-367/libnvcuvid.so ..

ó

$ cmake -DCUDA_NVCC_FLAGS="-D_FORCE_INLINES" -DCMAKE_INSTALL_PREFIX:PATH= -DWITH_IPP=ON -DWITH_CUBLAS=1 -DWITH_OPENGL=ON -DWITH_NVCUVID=ON ..
$ make -j 3
$ make install

Aparecerá una advertencia por haber agregado '/usr/lib/nvidia-367'.

Ojo: Qt y Vtk no se llevan, aunque puse ambas opciones arriba, elegir sólo una.

Con ffmpeg local

Para utilizar ffmpeg compilado localmente, antes de  realizar los pasos siguientes:
$ export LD_LIBRARY_PATH=/home/.../ffmpeg.../build/lib
$ export PKG_CONFIG_PATH=/home/.../lib/pkgconfig:$PKG_CONFIG_PATH
$ export PKG_CONFIG_LIBDIR=$PKG_CONFIG_LIBDIR:/home/.../build/lib

jueves, 7 de julio de 2016

Mi acordeón de git

Inicialización

Iniciar un repositorio localmente

$ git init
$ git remote add origin https://github.com/<username>/<repo>.git
$ git remote -v                 // verificar la liga
$ git push -u origin --all      // envía todo lo agregado localmente
Más detalles en Adding an existing project to GitHub using the command line

Clonar una bifurcación (fork)

$ git clone https://github.com/<username<repo>.git

Manipular los archicos

Agregar

$ git add .     // all
$ git add -u    // update
$ git add -A    // both

Remover

$ git rm --cached somefile.ext   // no remueve el archivo original
$ git rm --cached -r somedirectory
$ git rm --cached *~             // remueve archivos de respaldo

Borrar

$ git clean -f -d                // borra todos los archivos que no siga git

Manipular los repositorios

Encomendar (commit)

Registra en el repositorio local:
$ git commit -a -m "mensaje"     // agregar todo & commit
$ git commit -m "mensaje"        // sólo encomendar
$ git commit -m "mensaje" path/to/file.ext // encomendar un archivo

Empujar (Push)

Envía los datos al repo remoto:
$ git push

Ramas (branches)

$ git checkout -b branchname     // crear
$ git branck                     // ¿en qué rama me encuentro?
$ git checkout master

Solicitud de atracción (pull request)

Es cuando se solicita la fusión de ramas en Github.

viernes, 31 de octubre de 2014

Diagramas de clases y secuencia de KinectFusionBasics-D2D y KinectFusionExplorer-D2D

Tratando de comprender los demos de Microsoft, comienzo por hacer los diagramas de clases. ¿Quién es responsable de qué en KinectFusionBasics-D2D?

Sin embargo, al hacer el diagrama del KinectFusionExplorer-D2D, no estoy muy segura de haber ganado mucha información. Tal vez es un asunto de eficiencia, pero la cantidad de atributos y métodos en cada clase me parece impresionante, mientras que el número de clases es muy pequeño.  O tal vez este programa es más un asunto de programación estructurada que de orientación a objetos. Inclusive eliminando información dentro de cada clase, este diagrama no ofrece mayor información.

El siguiente paso ha sido crear los diagramas de secuencia, para ver qué lógica sigue el programa.  Trato de eliminar la información referente a la GUI y enfocarme en el manejo del Kinect y la reconstrucción de la superficie.  Los diagramas se toman algunas libertades, por ejemplo, se escribe el nombre del archivo que contiene a funciones independientes, donde se hubiera requerido el nombre de un objeto.

Al seguir la secuencia de ejecución desde la función de entrada int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) pareciera que el verdadero trabajo inicia con LRESULT CALLBACK CKinectFusionExplorer::MessageRouter.


El diagrama siguiente muestra lo que sucede cuando se ejecuta MessageRouter() y se está inicializando la aplicación.  Aquí aparece la creación al segundo hilo de ejecución, que menciona la documentación del demo.  La clase encargada de su creación y manejo es KinectFusionProcessor

Otros dos casos relevantes dentro de DlgProc() son cuando los mensajes son WM_FRAMEREADY y WM_UPDATESENSORSTATUS.  Este último caso es el más sencillo, pero refiere una llama al objeto de tipo NuiSensorChooserUI para actualizar parámetros del sensor.
Cuando el cuadro se encuentra listo, se muestran las imágenes correspondientes en pantalla y se actualizan los elementos de la interfaz que así lo requieran.

Segundo hilo

Aquí es donde realmente se realiza el procesamiento de la información del Kinect y la reconstrucción de la superficie.  La función enviada como parámetro al crear este hilo DWORD WINAPI KinectFusionProcessor::ThreadProc(LPVOID lpParameter), devuelve una referencia al método MainLoop() de la misma clase.  Aquí también hay un ciclo atendiendo eventos: fin del procesamiento, cuadro (de profundidad) siguiente y cambio de estado del sensor.  El diagrama siguiente ilustra qué hace esta función cuando se tiene disponible el siguiente cuadro.

Cada vez que es necesario reiniciar la reconstrucción del volumen, se manda llamar a la función HRESULT KinectFusionProcessor::RecreateVolume().  El diagrama siguiente ilustra la secuencia principal de llamadas.

Por último, la parte más pesada del procesamiento se encuentra en la función void KinectFusionProcessor::ProcessDepth().  Me interesa especialmente la reconstrucción con captura de color, por lo que sigo esa línea de ejecución.

Como se puede ver, esta es la función encargada de llamar a todas las demás funciones que realizan alguna parte del procesamiento.  Una vez alcanzado este punto ya es mucho más natural saber qué función realiza qué tarea y en qué orden.

Sincronización de hilos

Existen regiones críticas en las que se modifica el valor de variables, que deben se bloqueadas antes de re-escribirlas (las solicitudes para realizar estos bloqueos fueron ilustradas en los diagramas de secuencia de arriba).  Para los bloqueos se definen tres candados: m_lockParams, m_lockFrame y m_lockVolume.

Varias funciones dentro de KinectFusionProcessor revisan si fueron llamadas desde el segundo hilo creado o desde otro hilo.  Para ello utilizan el valor del atributo m_threadId, cuyo valor es asignado al crear el hilo con la llamada a la función CreateThread.

Las funciones que solicitan ser llamadas desde su propio hilo (segundo hilo creado, (AssertOwnThread())), se encargan del manejo del Kinect y el procesamiento de la información recibida.  Estas son:
  • MainLoop()
  • ShutdownSensor()
  • CreateFirstConnected()
  • InitializeKinectFusion()
  • RecreateVolume()
  • CopyExtendedDepth(NUI_IMAGE_FRAME &imageFrame)
  • ProcessDepth()
  • UpdateCameraPoseFinder()
  • StoreImageToFrameBuffer(const NUI_FUSION_IMAGE_FRAME* imageFrame, BYTE* buffer)
  • InternalResetReconstruction()
  • SetStatusMessage(WCHAR * szMessage)
  • NotifyFrameReady()
  • NotifyEmptyFrame()
Las funciones que solicitan ser llamadas desde otro hilo (AssertOtherThread()), reciben información desde la interfaz de usuario y almacenan los valores correspondientes en los atributos que podrá revisar el hilo encargado del procesamiento.  Antes y después de asignar estos valores, deben solicitar la aplicación de los candados correspondiente.  Estas funciones son:
  • ~KinectFusionProcessor()
  • StartProcessing(): Crea el segundo hilo.
  • StopProcessing()
  • ResolveSensorConflict()
  • IsVolumeInitialized()
  • SetWindow(HWND hWnd, UINT msgFrameReady, UINT msgUpdateSensorStatus)
  • SetParams(const KinectFusionParams& params)
  • LockFrame(KinectFusionProcessorFrame const** ppFrame)
  • UnlockFrame()
  • ResetReconstruction(): Llamada cuando el usuario selecciona alguna opción en la interfaz que provoca que se reinicie la reconstrucción.
  • CalculateMesh(INuiFusionColorMesh** ppMesh)

martes, 28 de octubre de 2014

Hola mundo Kinect con wxWidgets

Como paso inicial para un proyecto de visión por computadora, fue necesario separar claramente el código que controla el Kinect en DepthBasics-D2D © Microsoft, del código de la interfaz gráfica, que utiliza las Microsoft Foundation Classes (MFC). Con este objetivo, creé un pequeño programa que utiliza wxWidgets, el Kinect Developer Toolkit y Kinect SDK con los drivers oficiales para controlar el Kinect, que pueden ser descargados gratuitamente del sitio de Microsoft. Este programa únicamente lee la información de profundidad y la muestra en pantalla, manteniendo al mínimo el código requerido. La conexión al Kinect y lectura de información se realizan dentro de la clase definida en el archivo KinectManager.h. Las otras clases se encargan de crear y manejar la interfaz gráfica. Como wxWidgets requiere, se utiliza un timer para generar eventos que obliguen al programa a leer la información del Kinect. El proyecto de Visual Studio 2012 (Express) puede ser descargado de aquí.

domingo, 6 de julio de 2014

Cómo crear TabControl en CEGUI sólo con el archivo .layout

CEGUI incluye un buen ejemplo de cómo utilizar el TabControl, sin embargo require código.  Si se desea crear todas las pestañas con un .layout no hay instrucciones a la vista.  El orden correcto para insertar los elementos es:
<Window type="TaharezLook/TabControl" name="TabControl" >
           <Property name="TooltipText" value="This is the tab control" />
           <Property name="TabHeight" value="{0,-1}" />
           <Property name="MaxSize" value="{{1,0},{1,0}}" />
           <Property name="TabPanePosition" value="Top" />
           <Property name="Area" value="{{0.5,0},{0.15,0},{0.95,0},{0.95,0}}" />
           <Window name="PageArmor" type="TaharezLook/TabButtonPane">
                <Property name="Area" value="{{0.05,0},{0.05,0},{0.95,0},{0.95,0}}" />
                <Property name="Text" value="Armadura" />
           </Window>
           <Window name="PageItems" type="TaharezLook/TabButtonPane">
                <Property name="Area" value="{{0.05,0},{0.05,0},{0.95,0},{0.95,0}}" />
                <Property name="Text" value="Artículos" />
           </Window>
           <Window name="PageSkills" type="TaharezLook/TabButtonPane">
                <Property name="Area" value="{{0.05,0},{0.05,0},{0.95,0},{0.95,0}}" />
                <Property name="Text" value="Habilidades" />
           </Window>
</Window>
Ahora sí, dentro del TabButtonPane se puede incluir cualquier elemento que se necesite en el panel de esa pestaña.