IBCBiomech / insolesibc

Prototipo de aplicación para plantillas
0 stars 1 forks source link

Cámara a 60fps #31

Open ivanjimenez opened 1 year ago

ivanjimenez commented 1 year ago

He estado realizando algunas pruebas con registro de sensores de plantillas conjuntamente con una cámara ivCam a 60fps a 640x480 y el tiempo del video parece bastante sincronizado con el csv

Tengo una licencia de ivcam que también puedes probar: VP5RS-26Y9M-Z39Q7-IVY6E-P9VEN

Estimo que puede ser que hay alguna configuración que no está bien en la cámara. Revisamos mañana.

047.zip

bernatDiaz commented 1 year ago

Con la camara que me lleve del lab a 60 fps me graba a la mitad de tiempo He puesto un stopwatch y va demasiado lento en leer los frames. El bucle se ejecuta cada ~30 ms (30 fps), deberia ejecutarse cada ~15ms para 60 fps

private void DisplayCameraCallback()
        {
            Mat frame = new Mat();
            Stopwatch stopwatch = Stopwatch.StartNew();
            while (true)
            {
                if (cancellationTokenDisplay.IsCancellationRequested)
                {
                    videoCapture.Release();
                    videoCapture = null;
                    cameraService.InvokeFrameAvailable(index, GetBlackImage(resolution));
                    return;
                }
                Trace.WriteLine(stopwatch.Elapsed.TotalMilliseconds);
                if (videoCapture.Grab())
                {
                    videoCapture.Read(frame);
                    cameraService.InvokeFrameAvailable(index, frame);
                }
            }
        }
ivanjimenez commented 1 year ago

El stopwatch no funciona, prueba el ivcam con la licencia instalada en desktop para probar

ivanjimenez commented 1 year ago

También con la cámara que tienes cambia el tipo de cidec, a ver

bernatDiaz commented 1 year ago

El codec ya he probado varios y van todos lentos. El numero de serie me dice que ya ha sido usado.

bernatDiaz commented 1 year ago

Hay una version de opencvsharp con cuda https://www.nuget.org/packages/OpenCvSharp4.runtime.win.cuda/4.5.0.20201013 esto se puede usar o no funcionara en todos los pcs?

ivanjimenez commented 1 year ago

Prueba la de Cuda, voy a ver otro código

ivanjimenez commented 1 year ago

Bernat, prueba estas dos librerías:

En caso de que funcione y grabe a tiempo, usar otras resoluciones o fps

ivanjimenez commented 1 year ago

Sobre EmguCV:

using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.UI;
using System;
using System.IO;

class Program
{
    static void Main()
    {
        // Crear objeto de captura de video
        VideoCapture capture = new VideoCapture(0); // El índice 0 representa la cámara predeterminada

        // Configurar propiedades de la captura
        capture.SetCaptureProperty(CapProp.Fps, 60); // Configurar la frecuencia de cuadros (fps) a 60

        // Mostrar opciones de resolución y códec de video disponibles
        PrintAvailableResolutions(capture);
        PrintAvailableCodecs();

        // Elegir resolución y códec de video
        capture.SetCaptureProperty(CapProp.FrameWidth, 1920); // Configurar el ancho de la resolución (ejemplo: 1920)
        capture.SetCaptureProperty(CapProp.FrameHeight, 1080); // Configurar el alto de la resolución (ejemplo: 1080)
        capture.SetCaptureProperty(CapProp.FourCC, VideoWriter.Fourcc('H', '2', '6', '4')); // Configurar códec de video (ejemplo: H.264)

        // Crear objeto VideoWriter para grabar el video
        VideoWriter writer = new VideoWriter("output.mp4", capture.GetCaptureProperty(CapProp.FourCC), 
            capture.GetCaptureProperty(CapProp.Fps), new System.Drawing.Size((int)capture.GetCaptureProperty(CapProp.FrameWidth), 
            (int)capture.GetCaptureProperty(CapProp.FrameHeight)));

        // Iniciar el bucle de captura y escritura de video
        while (true)
        {
            Mat frame = capture.QueryFrame(); // Capturar un cuadro del video

            // Realizar operaciones con el cuadro (opcional)

            // Escribir el cuadro en el archivo de video
            writer.Write(frame);

            // Mostrar el cuadro en una ventana (opcional)
            CvInvoke.Imshow("Video", frame);

            // Salir del bucle al presionar la tecla 'Esc'
            if (CvInvoke.WaitKey(1) == 27)
                break;
        }

        // Liberar recursos
        capture.Dispose();
        writer.Dispose();
        CvInvoke.DestroyAllWindows();
    }

    // Método para imprimir las resoluciones disponibles
    static void PrintAvailableResolutions(VideoCapture capture)
    {
        Console.WriteLine("Resoluciones disponibles:");

        foreach (var resolution in capture.GetCaptureProperty(CapProp.SupportedResolutions).ToString().Split(','))
        {
            Console.WriteLine(resolution);
        }
    }

    // Método para imprimir los códecs disponibles
    static void PrintAvailableCodecs()
    {
        Console.WriteLine("Códecs disponibles:");

        foreach (var codec in VideoWriter.GetCodecNames())
        {
            Console.WriteLine(codec);
        }
    }
}

En este código, hemos agregado dos métodos auxiliares: PrintAvailableResolutions y PrintAvailableCodecs, que muestran las resoluciones y códecs de video disponibles respectivamente. Puedes llamar a estos métodos para ver las opciones disponibles antes de elegir la resolución y el códec de video.

ivanjimenez commented 1 year ago

Con AForge:

using System;
using System.Drawing;
using AForge.Video;
using AForge.Video.DirectShow;
using AForge.Video.FFMPEG;

class Program
{
    static void Main()
    {
        // Buscar dispositivos de video disponibles
        FilterInfoCollection videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

        if (videoDevices.Count == 0)
        {
            Console.WriteLine("No se encontraron dispositivos de video.");
            return;
        }

        // Crear objeto de captura de video
        VideoCaptureDevice videoSource = new VideoCaptureDevice(videoDevices[0].MonikerString);

        // Mostrar opciones de resolución disponibles
        PrintAvailableResolutions(videoSource);

        // Elegir resolución y códec de video
        videoSource.VideoResolution = videoSource.VideoCapabilities[0];

        // Crear objeto VideoFileWriter para grabar el video
        VideoFileWriter writer = new VideoFileWriter();
        writer.Open("output.mp4", videoSource.VideoResolution.FrameSize.Width, 
            videoSource.VideoResolution.FrameSize.Height, 60, VideoCodec.MPEG4);

        // Iniciar el bucle de captura y escritura de video
        videoSource.NewFrame += (s, e) =>
        {
            Bitmap frame = (Bitmap)e.Frame.Clone(); // Capturar un cuadro del video

            // Realizar operaciones con el cuadro (opcional)

            // Escribir el cuadro en el archivo de video
            writer.WriteVideoFrame(frame);

            // Mostrar el cuadro en una ventana (opcional)
            // ...

            // Salir del bucle al presionar la tecla 'Esc'
            if (Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)
                videoSource.SignalToStop();
        };

        // Iniciar la captura de video
        videoSource.Start();

        // Esperar hasta que se presione la tecla 'Esc' para detener la grabación
        while (videoSource.IsRunning)
        {
            // Esperar
        }

        // Detener y liberar recursos
        videoSource.SignalToStop();
        videoSource.WaitForStop();
        writer.Close();
        writer.Dispose();
    }

    // Método para imprimir las resoluciones disponibles
    static void PrintAvailableResolutions(VideoCaptureDevice videoSource)
    {
        Console.WriteLine("Resoluciones disponibles:");

        foreach (var resolution in videoSource.VideoCapabilities)
        {
            Console.WriteLine(resolution.FrameSize);
        }
    }
}

En este ejemplo, hemos utilizado la clase VideoCaptureDevice de AForge.NET para acceder al dispositivo de video. Hemos agregado el método PrintAvailableResolutions para mostrar las resoluciones disponibles y elegir una de ellas. Luego, hemos creado un objeto VideoFileWriter para grabar el video con una resolución y un códec específicos.

Dentro del bucle de captura de video, utilizamos el evento NewFrame para capturar cada cuadro del video y realizar las operaciones necesarias. Luego, escribimos el cuadro en el archivo de video utilizando el método WriteVideoFrame del VideoFileWriter.

Finalmente, detenemos y liberamos los recursos adecuadamente al finalizar la grabación.

AForge.NET es una biblioteca más antigua y no ha sido actualizada en mucho tiempo.

Priorizar la anterior librería, en caso de que no funcione está como segunda opción.

Espero que esto te pueda ayudar.

bernatDiaz commented 1 year ago

rama MVVMEmgu Va igual que el opencvsharp si cambio la resolucion sale 1 o 2 s y a 60 fps la mitad de tiempo. El codec he dejado el que viene por defecto porque me tiraba error supongo que mi pc no lo tiene instalado. Si quieres probar con el codec descomenta esta linea //videoCapture.Set(CapProp.FourCC, VideoWriter.Fourcc('H', '2', '6', '4')); // Con esto no funciona esta en el fichero Services/CameraStreamService.cs en el constructor

ivanjimenez commented 1 year ago

Bernat, en cuanto a los fps:

Opción 1:

Hay código provisto por alguien de opencvcsharp con el que hablé. Es un proyecto que está hecho en WinForms. Pero se ve la idea de la grabación que realiza y se podría trasladar a wpf. En teoría resolvería el problema de los fps que se requieran. Lee el código siguiente que es lo más importante:

https://github.com/kashiash/VLCSimpleWebCamViewer/blob/master/WinFormsOpenCvRecorder/Recorder.cs

E intenta hacer una simple prueba, ya sea con el proyecto MVVM o con uno simple proyecto.

Opción 2

using System;
using System.Drawing;
using OpenCvSharp;
using OpenCvSharp.Extensions;

public class WebcamRecorder
{
    private VideoCapture capture;
    private VideoWriter writer;
    private bool isRecording = false;
    private int frameCount = 0;
    private int targetFrameCount;

    public WebcamRecorder(string outputPath, int width, int height, int fps, int durationSeconds)
    {
        // Inicializa la cámara web
        capture = new VideoCapture(0);

        // Comprueba si la cámara web está abierta
        if (!capture.IsOpened())
        {
            Console.WriteLine("No se pudo abrir la cámara web.");
            return;
        }

        // Configura el tamaño del cuadro y la frecuencia de cuadros por segundo
        OpenCvSharp.Size frameSize = new OpenCvSharp.Size(width, height);
        writer = new VideoWriter(outputPath, FourCC.XVID, fps, frameSize);

        // Calcula el número total de cuadros objetivo basado en la duración
        targetFrameCount = fps * durationSeconds;
    }

    public void StartRecording()
    {
        if (isRecording)
        {
            Console.WriteLine("La grabación ya está en curso.");
            return;
        }

        isRecording = true;

        // Crea un bucle para capturar y escribir los cuadros del video
        while (isRecording && frameCount < targetFrameCount)
        {
            // Captura un cuadro de la cámara web
            Mat frame = new Mat();
            capture.Read(frame);

            // Verifica si el cuadro es válido
            if (frame.Empty())
                break;

            // Escribe el cuadro en el video
            writer.Write(frame);

            // Muestra el cuadro en una ventana (opcional)
            Cv2.ImShow("Webcam", frame);

            // Incrementa el contador de cuadros
            frameCount++;

            // Espera 1/fps segundos antes de capturar el siguiente cuadro
            int delay = (int)(1000 / writer.Fps);
            if (Cv2.WaitKey(delay) == 27) // Presiona la tecla Escape para detener la grabación
                break;
        }

        StopRecording();
    }

    public void StopRecording()
    {
        if (!isRecording)
        {
            Console.WriteLine("La grabación no está en curso.");
            return;
        }

        isRecording = false;

        // Libera los recursos
        writer.Release();
        Cv2.DestroyAllWindows();
    }
    static void Main(string[] args)
    {
        WebcamRecorder recorder = new WebcamRecorder("output.avi", 640, 480, 60, 10);
        recorder.StartRecording();

        Console.WriteLine("Grabación finalizada. Presiona cualquier tecla para salir.");
        Console.ReadKey();
    }
}

Dado el ejemplo de arriba yo he conseguido grabar a 60 fps con una webcam con el tiempo de grabación bien. Pero a doble velocidad. ¿Puedes probar con la cámara usb nueva que va a 60fps?

Si nada de lo anterior ayuda, dejamos por ahora que grabe a 30fps a una resolución más alta y ya probamos otras cosas. Pero mejor avanzar en la interface.

bernatDiaz commented 1 year ago

Opcion 1: https://github.com/IBCBio/insolesibc/tree/fpsOpcion1 no graba bien los ficheros no estan vacios pero no los puedo abrir

bernatDiaz commented 1 year ago

Opcion 2. Ha grabado a 60 fps y 10 segundos pero he usado un cronometro web y la grabacion ha tardado 20 segundos en realizarse. El video se ve mas rapido de lo que deberia.

ivanjimenez commented 1 year ago

Ok, perfecto. Continúa como te comentaba con la interface. Con la cámara wifi funciona perfectamente a 60 fps, también es bueno explorar ese tipo de productos. Voy a indagar yo un poco más con ese asunto. Lo único que necesitamos por ahora es:

//Ejemplo de configuración de resoución, autofocus.
VideoCapture Camera = new VideoCapture(0);
Camera.SetCaptureProperty(CapProp.FrameWidth, 1280);
Camera.SetCaptureProperty(CapProp.FrameHeight, 720);
Camera.SetCaptureProperty(CapProp.Autofocus, 39);
Camera.SetCaptureProperty(CapProp.Fps, 60); // 60Fps for USB 3.0, 30 Fps for USB 2.0!
ivanjimenez commented 1 year ago

Prueba además a conectar la cámara usb a un USB 3.0 y probar a 60 fps.

bernatDiaz commented 1 year ago

Captura de pantalla (27)

bernatDiaz commented 1 year ago

Diria que mis USB son todos 3.0 o 3.10 ademas de la captura de pantilla tienen el simbolo SS

bernatDiaz commented 1 year ago

Lo del bitrate con Emgu no me deja devuelve -1 siempre, (no se esta cambiando)

bernatDiaz commented 1 year ago

La resolucion si la cambio va muy mal y graba 2 segundos solo cuando tendria que grabar 16s

bernatDiaz commented 1 year ago

El auto focus no se esta cambiando si hago un get despues devuelve -1

bernatDiaz commented 1 year ago

Este codigo no me funciona

static void PrintAvailableResolutions(VideoCapture capture)
    {
        Console.WriteLine("Resoluciones disponibles:");

        foreach (var resolution in capture.GetCaptureProperty(CapProp.SupportedResolutions).ToString().Split(','))
        {
            Console.WriteLine(resolution);
        }
    }

La propiedad CapProp.SupportedResolutions no existe. La unica forma que he encontrado para buscar resoluciones y fps con emgu.CV es hacer un set para cada una que quieras probar y despues hacer un Get si lo ha cambiado es que existe pero esto ya lo probé con OpenCVsharp y era muy lento

ivanjimenez commented 1 year ago

Diria que mis USB son todos 3.0 o 3.10 ademas de la captura de pantilla tienen el simbolo SS

Si son ss son 3.0

ivanjimenez commented 1 year ago

I

Este codigo no me funciona

static void PrintAvailableResolutions(VideoCapture capture)
    {
        Console.WriteLine("Resoluciones disponibles:");

        foreach (var resolution in capture.GetCaptureProperty(CapProp.SupportedResolutions).ToString().Split(','))
        {
            Console.WriteLine(resolution);
        }
    }

La propiedad CapProp.SupportedResolutions no existe. La unica forma que he encontrado para buscar resoluciones y fps con emgu.CV es hacer un set para cada una que quieras probar y despues hacer un Get si lo ha cambiado es que existe pero esto ya lo probé con OpenCVsharp y era muy lento

Si va tan mal el Emgu no lo queremos, he visto que sí están actualizados los paquetes nuget de Aforge

https://www.nuget.org/packages?q=AForge.NET

Así que, te pediría probarlos y ver si el bitrate se puede cambiar.

Hablamos en unos minutos