WPF QR解码应用程序的优化,该应用程序在Intel NUC NUC7CJYH上使用约100%的CPU使用率

时间:2018-09-06 12:53:53

标签: c# wpf aforge zxing.net

我一直在研究WPF,该WPF可以解码用户持有的网络摄像头的QR码。该应用程序运行良好,可以在我的开发机上正常运行(Core i7 3770 CPU,NVidia Quadro K4200 GPU上最多可使用23%CPU和4%GPU),但是当我在计算机上安装并运行它时,它将在(一个Intel NUC NUC7CJYH)该应用程序的CPU使用率> 94%,导致该计算机上的使用率达到100%。

当前,该应用程序扫描了用户的QR码两次-第一个是员工的QR码,第二个是他们从事的项目编号的QR码。该应用程序使用ZXing.Net解码QR码,并使用AForge.Net访问网络摄像头。

我已经运行了VS Profiler,这是结果的屏幕截图: VS Profiler Output

根据VS Profiler的结果,有4个方法调用占用了最多的CPU时间,大概我应该专注于:

  • videoSource_NewFrame:这将获取VideoCaptureDevice(AForge.Video.DirectShow类的一部分)中呈现的每个帧,并将其显示在名为imgSource的Image控件中。这占用了大约10.56%的CPU总时间(3745ms)

    void videoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
    {
        try
        {
            BitmapImage bi;
            using (var bitmap = (Bitmap)eventArgs.Frame.Clone())
            {
                bi = new BitmapImage();
                bi.BeginInit();
                MemoryStream ms = new MemoryStream();
                bitmap.Save(ms, ImageFormat.Bmp);
                ms.Seek(0, SeekOrigin.Begin);
                bi.StreamSource = ms;
                bi.CacheOption = BitmapCacheOption.OnLoad;
                bi.EndInit();
            }
            bi.Freeze();
            Dispatcher.BeginInvoke(new ThreadStart(delegate { imgSource.Source = bi; }));
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error with attaching video frame.\n " + ex.Message);
            MessageBox.Show("An error occurred. \nPlease contact the Systems Development team for assistance.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            return;
        }
    
    }        
    
  • timer_Tick:此方法是DispatcherTimer Tick EventHandler,并且以1秒的间隔被调用。这用于在lblTime控件中显示当前时间,它使用约9.56%的CPU时间(3389毫秒)

    private void timer_Tick(object sender, EventArgs e)
    {
        currentTime = new DateTime();
        ts = new TimeSpan(DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second);
        currentTime = currentTime.Date + ts;
    
        lblTime.Content = $"{currentTime.ToString("HH:mm")}"; 
    }  
    
  • qrTimer_Tick:另一个DispatcherTimer Tick事件处理程序。该方法每3秒调用一次,并在每个间隔开始扫描QR码。它正在使用〜5.52%(1959ms)

    try
    {
        MemoryStream memoryStream = new MemoryStream();
        var encoder = new System.Windows.Media.Imaging.BmpBitmapEncoder();
        encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(imgSource.Source as System.Windows.Media.Imaging.BitmapSource));
        encoder.Save(memoryStream);
        memoryStream.Flush();
    
        capturedImage = (Bitmap)System.Drawing.Image.FromStream(memoryStream);
    
        BarcodeReader reader = new BarcodeReader();
    
        reader.AutoRotate = true;
        reader.TryInverted = true;
        reader.Options = new DecodingOptions { TryHarder = true };
    
        if (capturedImage != null)
            result = reader.Decode(capturedImage);
    
        if (result != null)
        {
            if (isStep1 == true)
            {
                QRScanUserID();                        
            }
            else if (isStep1 == false & isStep2 == true)
            {
                QRScanProjectID();                        
            }
        }                
    
    }
    catch (Exception)
    {                
        MessageBox.Show("An error occurred. \nPlease contact the Systems Development team for assistance.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
        return;
    }
    
  • 对ZXing.Net的Decode方法的外部调用。这占用了CPU总时间(1895ms)的5.34%

我不确定如何优化代码。我已经看过为两个DispatcherTimer中的每个设置DispactherPriority,但是在测试中这对应用程序的CPU使用率没有影响,并且会干扰每个DispatcherTimer的间隔。我还尝试将我在qrTimer_Tick方法中配置的3个BarcodeReader选项更改为false,这带来了大约1%的改进。但是,我认为这可以忽略不计,因为它取决于多种因素,例如用户将QR码放置在相机前面的速度以及qrTimer_Tick是否已经触发。

我缺少什么吗?难道仅仅是该应用程序正在运行它的NUC机器上压倒一切?

编辑 在遵循kennyzx和lerthe61的建议之后,我设法使NUC NUC7CJYH上的应用程序的CPU使用率高峰降低至〜58%。最大的好处是删除了DispatcherTimer对象,该对象每秒调用一次timer_Tick事件处理程序。进行此更改后不久运行VS Profiler,显示我的开发机上的CPU峰值使用率为18%,这是在启动应用程序后必须自行运行的不久之后。

在lerthe61输入之后,我然后看了我对MemoryStream和Bitmap对象的使用。 videoSource_NewFrame方法现在如下所示:

void videoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            try
            {
                BitmapImage bi;

                capturedImage = (Bitmap)eventArgs.Frame.Clone();
                bi = new BitmapImage();
                bi.BeginInit();
                ms = new MemoryStream();
                capturedImage.Save(ms, ImageFormat.Bmp);
                ms.Seek(0, SeekOrigin.Begin);
                bi.StreamSource = ms;
                bi.CacheOption = BitmapCacheOption.OnLoad;
                bi.EndInit();
                bi.Freeze();
                Dispatcher.BeginInvoke(new ThreadStart(delegate { imgSource.Source = bi; }));
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error with attaching video frame.\n " + ex.Message);
                MessageBox.Show("An error occurred. \nPlease contact the Systems Development team for assistance.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

        }          

我现在在qrTimer_Tick方法中使用了锁定功能,以锁定来自网络摄像头的当前捕获图像:

if (capturedImage != null)
{
   lock (_qrTimerLock)
   {
      result = reader.Decode(capturedImage);
   }
}

尽管我使用了锁,但该应用程序偶尔会抛出错误“对象在其他地方当前正在使用”。在删除timer_Tick之前,我的代码重构对应用程序的CPU使用效率影响不大,因此我可以保持原样,但是效率显然较低。

1 个答案:

答案 0 :(得分:0)

我决定决定删除每秒运行的DispatcherTimer,剩下第二个DispatcherTimer对象,该对象每3秒运行一次。仅使用此修复程序,应用程序的性能就会令人满意。

感谢大家的帮助!