Open ivanjimenez opened 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);
}
}
}
El stopwatch no funciona, prueba el ivcam con la licencia instalada en desktop para probar
También con la cámara que tienes cambia el tipo de cidec, a ver
El codec ya he probado varios y van todos lentos. El numero de serie me dice que ya ha sido usado.
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?
Prueba la de Cuda, voy a ver otro código
Bernat, prueba estas dos librerías:
[ ] Aforge: http://www.aforgenet.com/
[ ] EmguCV: https://emgu.com/wiki/index.php/Main_Page Te puedes bajar la release más abajo que creo que un nuget package.
[ ] Testear si funciona a una resolución baja 640x480 a 60fps
En caso de que funcione y grabe a tiempo, usar otras resoluciones o fps
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.
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.
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
Bernat, en cuanto a los fps:
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.
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.
Opcion 1: https://github.com/IBCBio/insolesibc/tree/fpsOpcion1 no graba bien los ficheros no estan vacios pero no los puedo abrir
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.
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!
Prueba además a conectar la cámara usb a un USB 3.0 y probar a 60 fps.
Diria que mis USB son todos 3.0 o 3.10 ademas de la captura de pantilla tienen el simbolo SS
Lo del bitrate con Emgu no me deja devuelve -1 siempre, (no se esta cambiando)
La resolucion si la cambio va muy mal y graba 2 segundos solo cuando tendria que grabar 16s
El auto focus no se esta cambiando si hago un get despues devuelve -1
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
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
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
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