OpenCvSharp VideoWriter writes an empty video - c#

I am trying to read a vide file, resize the frames and write them to an output file:
using System;
using System.Drawing;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.Extensions;
namespace VideoProcessing
{
public class Player
{
private VideoCapture capture;
private VideoWriter writer;
private Mat matInternal;
public Bitmap bmInternal;
private bool bIsPlaying = false;
public Timer MyTimer = new Timer();
const string outname = "output.avi";
OpenCvSharp.Size dsize = new OpenCvSharp.Size(640, 480);
public void InitPlayer(string videoName)
{
capture = new VideoCapture(videoName);
writer = new VideoWriter(outname, FourCC.MJPG, capture.Fps, dsize);
matInternal = Mat.Zeros(dsize, MatType.CV_8UC3);
bmInternal = matInternal.ToBitmap();
var delay = 1000 / (int)capture.Fps;
MyTimer.Interval = delay;
MyTimer.Tick += new EventHandler(mk_onTick());
MyTimer.Start();
}
private Action<object, EventArgs>
mk_onTick()
{
return (object sender, EventArgs e) =>
{
capture.Read(matInternal);
if (matInternal.Empty())
{
Console.WriteLine("Empty frame!");
}
else
{
matInternal.Resize(dsize);
bmInternal = matInternal.ToBitmap();
writer.Write(matInternal);
}
};
}
public void Dispose()
{
capture.Dispose();
writer.Dispose();
}
}
}
This is executed in my main function as follows:
using System;
using System.Drawing;
using OpenCvSharp;
using OpenCvSharp.Extensions;
namespace VideoProcessing
{
internal class Program
{
private static void Main(string[] args)
{
var videoName = "input.mp4";
var pl = new Player();
pl.InitPlayer(videoName);
// Some other code that executes in the meantime
pl.Dispose();
}
}
}
The writer can get disposed before the video finishes, which is fine because this will later be adapted for live camera video streams. However, the VideoWriter here produces an apparently empty, 0 second long video file. The codec setting does not produce any errors, and the video is only at 24 FPS so it should not be running into any speed issues. What could be causing this?

I think you have to delay your main thread.
By adding Thread.Sleep(2000) for instance.
I try your code with camera and it works well.

Related

How can i run Class Code in extra Thread? [duplicate]

This question already has answers here:
WebBrowser Control in a new thread
(4 answers)
Closed 2 years ago.
i wanna get the content of 100 links as fast as possible. My first thought was to create one thread, that creates 100 Webbrowser objects, let them navigate and collect all html strings in a list. But when i try to run my code i get the error "actual thread is no singlethread-apartment".
I have the following Code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
class ClassDriver
{
[STAThread]
public void StartDriver()
{
ClassTest t = new ClassTest();
Thread thread = new Thread(new ThreadStart(t.Collect));
thread.Start();
}
}
class ClassTest
{
private static List<WebBrowser> browsers;
private static List<string> htmls;
private static Stopwatch sw = new Stopwatch();
public void Collect()
{
string[] link = { "", "" };
sw.Start();
htmls = new List<string>();
browsers = new List<WebBrowser>();
for (int a = 0; a < 100; a++)
{
browsers.Add(new WebBrowser());
browsers.Last().DocumentCompleted += ClassGetRanking_DocumentCompleted;
browsers.Last().Navigate(link[0] + (a + 1) + link[1]);
}
}
private void ClassGetRanking_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser b = (sender as WebBrowser);
htmls.Add(b.DocumentText);
if (htmls.Count == browsers.Count)
{
sw.Stop();
}
}
}
}
The STAThread attribute you applied on StartDriver() method has no effect on the threads created by your own application.
You need to make them STA yourself by calling SetApartmentState() before calling Start()
Thread thread = new Thread(new ThreadStart(t.Collect));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
Ref:
https://learn.microsoft.com/en-us/dotnet/api/system.threading.thread.setapartmentstate

Form doesn't load in while loop

I have a class defined to get live capture from a camera, and a form button "END CAPTURE" that should halt the capture; and an typical Application.Exit() button.
However, for some reason the while loop as shown below doesn't load the form even when the condition is met. To debug this, I commented out the while loop to see if it snaps at least 1 image; and it does (as shown in fig). What makes the while loop not to load the form and show the output continuously ?
while (!terminated)
{
// CAMERA ACQUISITION CODE
}
Figure of single while loop run:
Full program for reference:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using mv.impact.acquire;
using mv.impact.acquire.examples.helper;
namespace mv_BlueFoxControl
{
public partial class Form1 : Form
{
private bool button1WasClicked = false;
public Bitmap SnappedBitmap = null;
public static Image PersistentImage = null;
public Form1()
{
InitializeComponent();
mv.impact.acquire.LibraryPath.init(); // this will add the folders containing unmanaged libraries to the PATH variable.
Device pDev = DeviceManager.getDevice(0);// Get a pointer to the first device found
if (pDev == null)
{
Console.WriteLine("Unable to continue! No device found! Press any key to end the program.");
//Console.Read();
Environment.Exit(1);
}
Console.WriteLine("Initialising the device. This might take some time...");
try
{
pDev.open();//start the sensor
Console.WriteLine("Device opened successfully...");
}
catch (ImpactAcquireException e)
{
// throw error code if the same device is already opened in another process...
Console.WriteLine("An error occurred while opening the device " + pDev.serial +
"(error code: " + e.Message + "). Press any key to end the application...");
//Console.ReadLine();
Environment.Exit(1);
}
bool terminated = false;// Bool terminated was here.
Console.WriteLine("Press CAPTURE to end the application");
// create thread for live capture
Thread thread = new Thread(delegate()//Start live acquisition
{
DeviceAccess.manuallyStartAcquisitionIfNeeded(pDev, fi);
Request pRequest = null;
// we always have to keep at least 2 images as the display module might want to repaint the image, thus we
// can free it unless we have a assigned the display to a new buffer.
Request pPreviousRequest = null;
int timeout_ms = 500;
int cnt = 0;
int requestNr = Device.INVALID_ID;
Console.WriteLine(terminated);
while (!terminated)
{
// CAMERA ACQUISITON CODE
}
DeviceAccess.manuallyStopAcquisitionIfNeeded(pDev, fi);
// free the last potential locked request
if (pRequest != null)
{
pRequest.unlock();
}
// clear the request queue
fi.imageRequestReset(0, 0);
// extract and unlock all requests that are now returned as 'aborted'
requestNr = Device.INVALID_ID;
while ((requestNr = fi.imageRequestWaitFor(0)) >= 0)
{
pRequest = fi.getRequest(requestNr);
Console.WriteLine("Request {0} did return with status {1}", requestNr, pRequest.requestResult.readS());
pRequest.unlock();
}
});//End of thread
Console.WriteLine(" End Thread");
thread.Start();
if (button1WasClicked)
{
terminated = true;
}
Console.WriteLine("Program termination");
Console.WriteLine(terminated);
thread.Join();
}
private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void button1_Click(object sender, EventArgs e)
{
button1WasClicked = true;
}
}
}
Because of thread.Join(); The application will wait that the thread ends (which will not end until you press the button) and so the constructor is never finished.
You have to initialize a Thread field and only close it when you press the button.
Try this:
public partial class Form1 : Form
{
//...
private Thread _cameraThread;
public Form1()
{
//... the previous code
_cameraThread = new Thread(delegate()//Start live acquisition
{
// thread logic
});
_cameraThread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void button1_Click(object sender, EventArgs e)
{
button1WasClicked = true;
//set the flag and wait for the thread to finish
_cameraThread.Join();
Console.WriteLine("Program termination");
}
}

Print preview performance

My question is pretty straightforward. I need to display a print preview dialog in a multi-user ERP environment. It speaks for itself that printing should be as fast as possible.
However, if I use the code below, it takes about 10! seconds before the preview is displayed and is fully generated. This is without database access or any other CPU intensive operations.
Is there any way or method to improve this performance? I'm also able to use WPF, should that be necessary.
I've noticed that if you generate the preview, close it, and then quickly generate it again, it responds much faster, about a second or two. If you then wait another 5 seconds or so, generate it again, it takes about 10 seconds again.
I'm guessing some type of caching is going on, but don't have a clue what's actually happening.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PrintPerformanceTests
{
public class PrintPreviewTest
{
private string printerName;
private PrintPreviewDialog printPreviewDialog1;
private PrintDocument printDocument1 = new PrintDocument();
private Random random = new Random();
public string PrinterName
{
get { return printerName; }
set { printerName = value; }
}
public PrintPreviewDialog PrintPreviewDialog
{
get { return printPreviewDialog1; }
set { printPreviewDialog1 = value; }
}
public PrintPreviewTest(string printerName, PrintPreviewDialog printPreviewDialog)
{
this.PrinterName = printerName;
this.PrintPreviewDialog = printPreviewDialog;
printDocument1.PrintPage += new PrintPageEventHandler(printDocument1_PrintPage);
}
public void GenerateRandomPrintPreview()
{
Cursor.Current = Cursors.WaitCursor;
try
{
PrintPreviewDialog.Document = printDocument1;
PrintPreviewDialog.ShowDialog();
}
catch (Exception exc)
{
Cursor.Current = Cursors.Default;
MessageBox.Show(exc.ToString());
}
finally
{
Cursor.Current = Cursors.Default;
}
}
void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
{
e.Graphics.PageUnit = GraphicsUnit.Millimeter;
using(Font f = new Font("Arial", 10f))
{
for (int i = 0; i < 20; i++)
{
string txt = "Random string " + i.ToString();
e.Graphics.DrawString(txt, f, Brushes.Black, new PointF(random.Next(10, 200), random.Next(10,280)));
}
}
e.HasMorePages = false;
}
}
}
usage:
PrintPreviewTest pt = new PrintPreviewTest(tbPrinter.Text, printPreviewDialog);
pt.GenerateRandomPrintPreview();
In my experience this startup delay is related to initialization of printer parameters. When you set printer name (especially network printer name) and create print preview dialog, it first connects to the specified printer and checks it's settings (paper size etc.). It takes a lot of time. The only way (IMHO) to overcome this issue is to create your own print preview dialog that initializes printer settings in separate thread.

Download multiple files in parallel using c#

I want to download files in parallel using C#. For this, I have written this code which is working perfectly but the problem is that UI is freezing.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace FileDownloader
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private static int count = 1;
private static string f= "lecture";
private string URL = "www.someexample.com";
public MainWindow()
{
InitializeComponent();
}
public static string GetDirectoryListingRegexForUrl(string url)
{
if (url.Equals(URL))
{
return "(?<name>.*)";
}
throw new NotSupportedException();
}
public void DownloadP(string[] urls)
{
Parallel.ForEach(urls.ToList(), new ParallelOptions { MaxDegreeOfParallelism = 10 }, DownloadFile);
}
private void DownloadFile(string url)
{
using(WebClient client=new WebClient())
{
if (url.EndsWith(".pdf"))
{
int nextIndex = Interlocked.Increment(ref count);
client.DownloadFile(url, f + nextIndex + ".pdf");
this.Dispatcher.Invoke(() => {
listbox.Items.Add(url);
});
}
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
DownloadP(listofFiles);
}
}
}
You can use async/await with conjunction with new WebClient method DownloadFileTaskAsync.
private async Task DownloadFile(string url)
{
if (!url.EndsWith(".pdf"))
{
return;
}
using (var client = new WebClient())
{
int nextIndex = Interlocked.Increment(ref count);
await client.DownloadFileTaskAsync(url, "lecture" + nextIndex + ".pdf");
listBox.Items.Add(url);
}
}
private async void Button_OnClick(object sender, RoutedEventArgs e)
{
button.IsEnabled = false;
await DownloadFiles(urlList);
button.IsEnabled = true;
}
private async Task DownloadFiles(IEnumerable<string> urlList)
{
foreach (var url in urlList)
{
await DownloadFile(url);
}
}
Relace your DownloadP function with this :
public async Task DownloadP(string[] urls)
{
await Task.Factory.StartNew(() => Parallel.ForEach(urls.ToList(), new ParallelOptions { MaxDegreeOfParallelism = 10 }, DownloadFile));
}
instead of using client.DownloadFile use client.DownloadFileAsync like this
var webClient=new WebClient();
webClient.DownloadFileCompleted += webClient_DownloadFileCompleted;
webClient.DownloadFileAsync("Your url","file_name");
the event
private void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("Download Completed.");
}
I know this Question is old, but WebClient is outdated and dedicated.
First of all, WPF uses MVVM pattern that you should try to follow, but except that you can use the HttpClient in using System.Net.Http;.
To download multiple files in a parallel you can create a parallel foreach that handles all the downloads that the HttpClient have to perform. You did tis right but the foreach will block the thread so start it in a new one Task.Run(()=>{// Your Code});
In the case you don’t want do write something like that yourself, you could use the Shard Download Library on NuGet. This NuGet Package is also on GitHub if you want to see how it does its job. It helped me often if I want do download a lot of files, because is does not block the UI thread and is easy to use. To use it you have to write something like this:
void Download()
{
string[] links = new string[]{
"https://google.com",
"https://speed.hetzner.de/100MB.bin",
"https://file-examples.com/storage/fe88dacf086398d1c98749c/2017/04/file_example_MP4_1920_18MG.mp4" };
foreach (var link in links)
{
_ = new LoadRequest(link);
}
Console.ReadLine();
}
But you can also set the MaxDegreeOfParalism and you can change it while it is downloading. You can set the Path for the output file and name it. The problem that the HttpClient has with download finished and progress report is also solved with this. The bad thing is that the documentation of this library is not very good. Here an example with few options as an example.
async Task DownloadAsync()
{
string[] links = new string[]{
"https://google.com",
"https://speed.hetzner.de/100MB.bin",
"https://file-examples.com/storage/fe88dacf086398d1c98749c/2017/04/file_example_MP4_1920_18MG.mp4" };
RequestHandler requestHandler = new()
{
MaxDegreeOfParallelism = 10
};
LoadRequestOptions option = new()
{
Progress = new Progress<float>(value => Console.WriteLine(value.ToString("0.0%"))),
DestinationPath = "C:\\Users\\[UserName]\\Desktop\\",
RequestCompleated = path => Console.WriteLine("Finished: " + path?.ToString()),
RequestHandler = requestHandler
};
LoadRequest last = null;
foreach (string link in links)
{
last = new LoadRequest(link, option);
}
await last.Task;
}
I hope that can help people that have the same problem and don’t want to use the dedicated WebClient.

How come I get no output from this piece of code?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Timer time = new Timer();
time.Elapsed += new ElapsedEventHandler(action);
time.Interval = 5000;
time.Enabled = true;
time.Start();
}
static void action(Object sender, ElapsedEventArgs args)
{
Console.WriteLine("haha\n");
}
}
}
This piece of code doesnt have any output. Could anyone tell me what the problem is? Thank you very much. I followed exact code on MSDN.. http://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.71).aspx
Timer goes out of scope immediately and thus is never called. The program exits before it has a chance to fire the action.
You can make your main method sleep by adding this after time.start():
TimeSpan interval = new TimeSpan(0, 0, 2);
Thread.Sleep(interval);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
class Program
{
static void Main(string[] args)
{
while(true)
{
Timer time = new Timer();
time.Elapsed += new ElapsedEventHandler(action);
time.Interval = 100;
time.Enabled = true;
time.Start();
string line = Console.ReadLine(); // Get string from user
if (line == "exit") // Check for exit condition
{
break;
}
}
Console.WriteLine("End of Program\n");
}
static void action(Object sender, ElapsedEventArgs args)
{
Console.WriteLine("haha\n");
}
}

Categories