C# 托管代码优化 [关闭]

Posted

技术标签:

【中文标题】C# 托管代码优化 [关闭]【英文标题】:C# Managed Code optimization [closed] 【发布时间】:2015-11-30 23:37:49 【问题描述】:

我有一个在我的 C# 应用程序中使用的托管 C++ DLL。 DLL 正在处理大量图像(数千张)并使用 OCR 从中提取文本;尽管我知道 OCR 处理会消耗大量 CPU,但我想知道是否可以优化代码以获得更好的性能。

目前解析大约需要一分钟。 15 页 PNG 页面。我会降低到大约 30-40 秒。

C++ 代码:

        char* OCRWrapper::GetUTF8Text(char* path, char* lang, char* imgPath)
        
            char* imageText;
            tesseract::TessBaseAPI *api = new tesseract::TessBaseAPI();

            if (api->Init(path, lang)) 
                fprintf(stderr, "Could not initialize tesseract. Incorrect datapath or incorrect lanauge\n"); /*This should throw an error to the caller*/
                exit(1);
            

            /*Open a reference to the imagepath*/
            Pix *image = pixRead(imgPath);

            /*Read the image object;*/
            api->SetImage(image);

            // Get OCR result
            imageText = api->GetUTF8Text();

            /*writeToFile(outText);*/
            /*printf("OCR output:\n%s", imageText);*/

            /*Destroy the text*/
            api->End();

            pixDestroy(&image);
            /*std::string x = std::string(imageText);*/

            return imageText;
        

创建 OCROBject 类实例的 C# 方法。 OCRObject 是实际调用 DLL 的类,请参见下面的此方法。

  private void GetTextFromSavedImages(List<string> imagesPath)
    
        try
        
            StringBuilder allPagesText = new StringBuilder();
            OCRObject ocr = new OCRObject(this.dbHandler.GetApplicationSetting(this.m_ProfileName, "TesseractLanguage").ApplicationSettingValue, this.dbHandler.GetApplicationSetting(this.m_ProfileName, "TesseractConfigurationDataPath").ApplicationSettingValue); //Settings.Default.TesseractConfigurationDataPath
            for (int i = 0; i < imagesPath.Count; i++)
            

                string pageText = ocr.GetOCRText(imagesPath[i]);
                this.m_pdfDictionary.Add(i + 1, pageText);
                allPagesText.Append(pageText);
            
            this.AllPageText = allPagesText.ToString();
        
        catch (Exception ex)
        
            Logger.Log(ex.ToString(), LogInformationType.Error);
        
    

最后是 OcrObject 类:

public class OCRObject
        
            private string m_tessLanguage;
            private string m_tessConfPath;
            [DllImport(@"\OCR\OCR.dll", EntryPoint = "GetUTF8Text", CallingConvention = CallingConvention.Cdecl)]
            private static extern IntPtr GetUTF8Text(string path, string lang, string imgPath);

            public OCRObject(string language, string tessConfPath)
            
                if (string.IsNullOrEmpty(language))
                
                    throw new ArgumentException("Tesseract language is null or empty.");
                
                if (!System.IO.Directory.Exists(tessConfPath))
                
                    throw new DirectoryNotFoundException("Could not find directory => " + tessConfPath);
                    
                this.m_tessLanguage = language;
                this.m_tessConfPath = tessConfPath;
                
            public string GetOCRText(string imagePath)
            
                return this.StringFromNativeUtf8(GetUTF8Text(this.m_tessConfPath, this.m_tessLanguage, imagePath));
            

            private string StringFromNativeUtf8(IntPtr nativeUtf8)
            
                try
                
                    int len = 0;
                    if (nativeUtf8 == IntPtr.Zero)
                    
                        return string.Empty;
                    
                    while (Marshal.ReadByte(nativeUtf8, len) != 0) ++len;
                    byte[] buffer = new byte[len];
                    Marshal.Copy(nativeUtf8, buffer, 0, buffer.Length);
                    //GC.Collect(GC.MaxGeneration, GCCollectionMode.Optimized); /*If this help???*/
                    string text = Encoding.UTF8.GetString(buffer);
                    return text;
                
                catch
                
                    return string.Empty;
                
            
        

如果您需要更多详细信息,请告诉我。

【问题讨论】:

您是否分析过代码以确定您的瓶颈在哪里?如果是这样,您大部分时间都花在了哪里? 是的,这可能是可能的。不,我不会为你做的。你在这里甚至没有任何要求。 “足够快”有多快? @DanBryant:我该怎么做?我真的不知道。 @EdS.:我已经更新了这个问题。希望对您有所帮助。 知道总时间也不算多,应该衡量流程执行的不同阶段。只有通过细粒度的测量,您才能知道瓶颈在哪里并因此得到改进。输入分布在其代码中的测量点,并定位首次处理成本较高的点。 【参考方案1】:

Tesseract FAQ 建议人们并行运行其可执行文件(即暗示它是单线程的)。

您也许可以尝试使用 Parallel.For 替换您的 for 循环,看看您是否可以快速而肮脏地取胜。

编辑:他们已移至 GitHub,新的常见问题解答建议

使用 Tesseract 生成一页 PDF,您将获得更好的结果 并行文件,然后在最后将它们拼接在一起

【讨论】:

谢谢,大大提高了性能。 哪一个?是并行还是 PDF 技巧? 我添加了一个 Parallel.ForEach 而不是循环来更快地提取文本。我没有尝试过 PDF 部分,因为我不想让 Tesseract 生成 PDF 页面,因为我已经有了 PDF。

以上是关于C# 托管代码优化 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

从非托管 C 库访问 C# 方法是不是安全? [关闭]

如何从托管 C# 代码跟踪 CRT 调试内存泄漏输出的来源?

让非托管 c++ 代码调用调用 c# 代码的托管 c++ 代码

托管 C# 代码未发生非托管调用

C# 托管非托管代码

非托管 C# 与 C++ [关闭]