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

使用Parallel.For并行处理OCR时Bitmap锁定/被占用错误求助

问题:并行处理图像OCR时出现Bitmap锁定错误

我开发了一个对图像中选定文本行执行OCR的程序,原本用for循环运行正常,但串行处理耗时累积,所以尝试用Parallel.For并行处理最多5行文本。单条文本行时无报错,多文本行时出现以下错误:

System.InvalidOperationException: 'Bitmap region is already locked.'

OR Bitmap is in use elsewhere

使用EMGU和Tesseract类的相关代码如下:

private void ocrmethod()
{
    this.Invoke((MethodInvoker)delegate
    {
            Image<Gray, byte> temp = frame.Convert<Gray, byte>().Clone();
          //  for (int i = 0; i < imgcount; i++)
             Parallel.For(0, imgcount, i =>
            {      
                    temp.ROI = LineRect[i]; // Selected text line region in the image
                    OCR_Class doocr = new OCR_Class();
                    Image<Gray, byte> foundareafilter = temp.Copy();                           
                    
                    bitmap2 = new Bitmap(foundareafilter.ToBitmap<Gray, byte>());                           

                    //OCR SECTION

                    doocr.trainingdatapath(@"./OCRtraindata", "eng");  
                    doocr.ProcessOCR(bitmap2, 1);
                    string result = doocr.result().Replace(" ", "").Replace("  ", ""); 
           // } 
            });           
      });           
}

问题根源

多个并行线程同时修改并访问同一个temp对象的ROI属性、调用Copy()方法,而EMGU的Image对象本身不是线程安全的,Bitmap对象也不支持多线程并发访问,导致资源锁定冲突。此外,共享变量bitmap2也会引发线程间的覆盖问题。

修复方案

  1. 每个线程独立创建图像副本:不在并行循环外创建共享的temp对象,而是在每个线程内部单独克隆原始图像并设置ROI,彻底避免线程间的资源竞争。
  2. 使用局部变量替代共享变量:将bitmap2改为线程内的局部变量,防止多个线程互相覆盖数据。
  3. 分离UI线程与并行计算:不要将整个Parallel.For包裹在Invoke中,仅在需要更新UI时单独调用Invoke,避免阻塞并行处理。
  4. 及时释放资源:用using语句包裹所有实现IDisposable的对象(如Image、Bitmap),确保资源及时释放,避免内存泄漏和锁定问题。

修改后的代码示例:

private void ocrmethod()
{
    // 先在UI线程外获取原始图像的独立副本
    Image<Gray, byte> originalFrame = frame.Convert<Gray, byte>().Clone();

    Parallel.For(0, imgcount, i =>
    {
        // 每个线程单独克隆图像,避免共享资源冲突
        using (Image<Gray, byte> temp = originalFrame.Clone())
        {
            temp.ROI = LineRect[i];
            using (Image<Gray, byte> foundareafilter = temp.Copy())
            using (Bitmap bitmap2 = foundareafilter.ToBitmap<Gray, byte>())
            {
                OCR_Class doocr = new OCR_Class();
                doocr.trainingdatapath(@"./OCRtraindata", "eng");  
                doocr.ProcessOCR(bitmap2, 1);
                string result = doocr.result().Replace(" ", "").Replace("  ", "");

                // 仅在需要更新UI时调用Invoke
                this.Invoke((MethodInvoker)delegate
                {
                    // 此处处理结果的UI更新逻辑,例如显示识别结果
                });
            }
        }
    });
}

额外优化建议

  • 将OCR_Class的初始化(包括trainingdatapath)移到并行循环外,创建线程安全的OCR实例池,或者让OCR_Class支持复用,减少重复加载训练数据的开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 21:20:19