You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

处理第二个闪电时取消按钮无法终止操作的技术问题

闪电处理流程的异常问题排查

逻辑规则

  • 点击btnStartProcessing_Click按钮启动处理,再次点击则停止处理
  • 若在闪电处理过程中点击停止按钮,需等待当前闪电处理完成后再终止整个流程

问题现象

该逻辑在处理第一个、第三个及后续闪电时均可正常工作,但处理第二个闪电时出现异常:点击取消按钮后,第二个闪电处理完成后,系统并未终止操作,而是继续处理后续闪电。仅第二个闪电处理存在该问题。

相关代码

基于C#、OpenCVSharp开发的实现代码,各模块相互关联:

引用命名空间

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.UI.WebControls;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.Extensions;

Form1类成员变量

private CancellationTokenSource cancellationTokenSource;
private TaskCompletionSource<bool> lightningProcessingTaskCompletion = new TaskCompletionSource<bool>();
private VideoCapture videoCapture;
private int totalFrames;
private int processedFrames;
private bool processingFrames;
private readonly int framesToCaptureAfterLightning = 4;
private string selectedLightningsFolderPath;
private string selectedVideoFilePath;
private bool paused = false;
private bool lightningDetected = false;
private List<string> lightningDirectories;
private int currentLightningIndex;
private List<string> lightningImages;
private int currentImageIndex;
private Logger logger;

btnStartProcessing_Click事件

private async void btnStartProcessing_Click(object sender, EventArgs e)
{
    btnVideoFileFolder.Enabled = false;
    btnSaveLightnings.Enabled = false;

    if (!processingFrames)
    {
        // Get the current date and time with the desired format
        string startTime = DateTime.Now.ToString("dd/MM/yyyy HH:mm");
        // Log the process start time
        logger.Log($"Process Started At: {startTime}", Color.Green);
        logger.Log("", Color.White); // Empty line

        processingFrames = true;
        btnStartProcessing.Text = "STOP PROCESSING";
        customProgressBar1.UpdateProgress(0);

        videoCapture = new VideoCapture(@"d:\lightnings1.mp4");
        totalFrames = (int)videoCapture.Get(VideoCaptureProperties.FrameCount);
        processedFrames = 0;

        // Create a new cancellationTokenSource for the current processing
        cancellationTokenSource = new CancellationTokenSource();

        try
        {
            await ProcessVideoFramesAsync(cancellationTokenSource.Token);
        }
        catch (OperationCanceledException)
        {
            // Handle cancellation
        }
        finally
        {
            // Always release resources and reset
            cancellationTokenSource?.Dispose();
            videoCapture?.Release();
            processingFrames = false;
            btnStartProcessing.Text = "START PROCESSING";

            // Enable the buttons and check conditions
            EnableButtonsAndCheckConditions();

            if (!lightningDetected)
            {
                logger.Log("Process Cancelled At: " + DateTime.Now.ToString("dd/MM/yyyy HH:mm"), Color.Red);
                logger.Log("", Color.White); // Empty line
            }
        }
    }
    else
    {
        if (!lightningDetected)
        {
            paused = false; // Reset pause state if stopping
            if (cancellationTokenSource != null)
            {
                cancellationTokenSource.Cancel();
                await Task.Delay(100); // Allow current lightning capture to complete before stopping
            }
        }
        else
        {
            await ProcessingLightning();
        }
    }
}

ProcessingLightning方法

private async Task ProcessingLightning()
{
    // Simulate the lightning processing. Replace this with your actual logic.
    for (int i = 0; i < 3; i++) // Simulate 3 steps of processing
    {
        await Task.Delay(1000); // Simulate a 1-second processing step

        if (cancellationTokenSource != null)
        {
            // Check if the main cancellation token is requested (indicating a full cancellation)
            if (cancellationTokenSource.IsCancellationRequested)
            {
                // Perform any cleanup or cancel logic here
                paused = false; // Reset pause state if stopping
                videoCapture?.Release();
                processingFrames = false;
                btnStartProcessing.Text = "START PROCESSING";

                // Signal that the lightning processing is canceled
                lightningProcessingTaskCompletion.TrySetResult(false);

                logger.Log("Process Cancelled At: " + DateTime.Now.ToString("dd/MM/yyyy HH:mm"), Color.Red);
                logger.Log("", Color.White); // Empty line

                return; // Exit the method
            }
            else if (!lightningDetected)
            {
                // Check if lightningDetected is false (assuming this is when you want to cancel the current lightning)
                // Perform any cleanup or cancel logic here for the current lightning
                paused = false; // Reset pause state if stopping
                cancellationTokenSource.Cancel();
                cancellationTokenSource.Dispose();
                cancellationTokenSource = null;
                await Task.Delay(100); // Allow current lightning capture to complete before stopping
                videoCapture?.Release();
                processingFrames = false;
                btnStartProcessing.Text = "START PROCESSING";

                // Signal that the lightning processing is canceled
                lightningProcessingTaskCompletion.TrySetResult(false);

                logger.Log("Process Cancelled At: " + DateTime.Now.ToString("dd/MM/yyyy HH:mm"), Color.Red);
                logger.Log("", Color.White); // Empty line

                return; // Exit the method
            }
            else
            {
                // Log the lightning processing canceled or ended with an empty line before and after
                /*logger.Log("", Color.White); // Empty line before
                logger.Log("Process " + (lightningDetected ? "Ended" : "Cancelled") + " At: " + DateTime.Now.ToString("dd/MM/yyyy HH:mm"), lightningDetected ? Color.Green : Color.Red);
                logger.Log("", Color.White); // Empty line after*/
            }
        }
    }

    // Signal that the lightning processing is complete
    lightningProcessingTaskCompletion.TrySetResult(true);
}

ProcessVideoFramesAsync方法

private async Task ProcessVideoFramesAsync(CancellationToken cancellationToken)
{
    int framesCaptured = 0; // Track the number of frames captured after lightning
    string currentLightningFolderPath = null;
    int currentLightningStartFrame = 0;
    int folderNameCounter = 0;

    await Task.Run(async () =>
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            using (Mat frame = new Mat())
            {
                videoCapture.Read(frame);

                if (frame.Empty())
                {
                    break;
                }

                lightningDetected = LightningDetector.DetectLightning(frame); // Use the new class

                if (lightningDetected)
                {
                    if (currentLightningFolderPath == null)
                    {
                        currentLightningStartFrame = processedFrames + 1;
                        currentLightningFolderPath = Path.Combine(selectedLightningsFolderPath, $"Lightning{processedFrames + 1:D3}");
                        Directory.CreateDirectory(currentLightningFolderPath);
                    }

                    while (framesCaptured < framesToCaptureAfterLightning && !cancellationToken.IsCancellationRequested)
                    {
                        using (Mat capturedFrame = new Mat())
                        {
                            videoCapture.Read(capturedFrame);

                            if (capturedFrame.Empty())
                            {
                                break;
                            }

                            string frameFileName = $"Frame{framesCaptured + 1:D2}.png"; // Example filename
                            await SaveLightningImageAsync(capturedFrame, currentLightningFolderPath, frameFileName);
                            DisplayFrameInPictureBox(capturedFrame);
                        }

                        framesCaptured++;
                        await Task.Delay(1000, cancellationToken); // Optional delay between captured frames
                    }
                }
                else if (currentLightningFolderPath != null)
                {
                    int currentLightningEndFrame = currentLightningStartFrame + framesCaptured - 1;
                    string frameRange = $"[{currentLightningStartFrame:D4}-{currentLightningEndFrame:D4}]";
                    string lightningFolderName = $"Lightning{folderNameCounter.ToString("D3")}_{frameRange}";
                    Directory.Move(currentLightningFolderPath, Path.Combine(selectedLightningsFolderPath, lightningFolderName));
                    currentLightningFolderPath = null;
                    framesCaptured = 0; // Reset the counter
                    folderNameCounter++;

                    logger.Log("Lightning Detected: " + lightningFolderName, Color.Yellow); // Empty line
                }

                processedFrames++;
                float progressValue = (float)processedFrames / (totalFrames - 1) * 100;
                customProgressBar1.UpdateProgress((int)progressValue);

                await Task.Yield(); // Allow UI updates before continuing to the next frame
            }
        }

        // Finish capturing the current lightning before completing
        if (currentLightningFolderPath != null)
        {
            // Wait for lightning processing to complete before finishing
            await lightningProcessingTaskCompletion.Task;
        }

        customProgressBar1.UpdateProgress(100);

        // Enable the buttons and check conditions
        EnableButtonsAndCheckConditions();
    });
}

内容的提问来源于stack exchange,提问作者Daniel Lip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 14:07:01