从位图中删除某种颜色的所有色调

Cri*_*ani 2 c# ocr image image-processing c#-4.0

您好,我正在尝试消除保存在位图中的图像的所有橙色色调,我需要使用超立方体在图像中进行 OCR,扫描文档的橙色似乎阻碍了在文本中产生错误的过程,我已经尝试过用photoshop去除橙色I,使OCR工作完美,主要问题是像素并不都是相同的颜色,它们是橙色但深浅不同

Bitmap modificar = new Bitmap("imagenamodificar.png");
        for (int ycount2 = 0; ycount2 < modificar.Height; ycount2++)
        {
            for (int xcount2 = 0; xcount2 < modificar.Width; xcount2++)
            {
                if (modificar.GetPixel(xcount2, ycount2) == Color.Orange)
                {
                    modificar.SetPixel(xcount2, ycount2, Color.White);
                }
            }
        }
Run Code Online (Sandbox Code Playgroud)

该代码绝对不执行任何操作,图像保持不变。

然后我想到与像素 (0,0) 进行比较,因为它始终是我想要消除的颜色。

Bitmap modificar = new Bitmap("imagenamodificar.png");
        for (int ycount2 = 0; ycount2 < modificar.Height; ycount2++)
        {
            for (int xcount2 = 1; xcount2 < modificar.Width; xcount2++)
            {
                if (modificar.GetPixel(xcount2, ycount2) == modificar.GetPixel(0,0))
                {
                    modificar.SetPixel(xcount2, ycount2, Color.White);
                }
            }
        }
Run Code Online (Sandbox Code Playgroud)

但问题是它只删除了一小部分,橙色像素仍然存在,因为正如我之前提到的,并非所有橙色色调都是相同的,有人能想到什么吗?

AAA*_*ddd 6

以下是一些可以为您提供帮助的关键点

\n\n
    \n
  1. 不要使用GetPixel SetPixel,它非常慢
  2. \n
  3. 为了提高速度,最好使用unsafe指针访问并调用lockbits来获取Pinned Array
  4. \n
  5. 您可能想使用阈值来确定特定像素颜色是否接近您要删除的颜色
  6. \n
\n\n

一个简单的颜色阈值可以通过以下方式计算(您也可以在色调上计算)

\n\n

给定

\n\n
    \n
  • threshold是一些int
  • \n
  • 源颜色
  • \n
  • 像素颜色
  • \n
\n\n

临界点

\n\n
var thresh = threshold * threshold;\n\n// decode the RBG from the image Pointer\nvar r = ((*p >> 16) & 255) - sR;\nvar g = ((*p >> 8) & 255) - sG;\nvar b = ((*p >> 0) & 255) - sB;\n\n// compare it against the threshold\nif (r * r + g * g + b * b > thresh)\n   continue;\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

注意: TaW评论中给出的链接对于计算颜色距离非常有帮助。

\n
\n\n

用于lockbits访问扫描线固定我们的内存

\n\n

Bitmap.LockBits 方法(矩形、\xe2\x80\x82ImageLockMode、\xe2\x80\x82PixelFormat)

\n\n
\n

将位图锁定到系统内存中。

\n
\n\n

代码

\n\n
private static unsafe void ConvertImage(string fromPath, string toPath, Color source, Color targetColor, double threshold)\n{\n   var thresh = threshold * threshold;\n   var target = targetColor.ToArgb();\n\n   using (var bmp = new Bitmap(fromPath))\n   {   \n      // lock the array for direct access\n      var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppPArgb);\n      // Convert the source to rgb\n      int sR = source.R, sG = source.G, sB = source.B;\n      // store the max length so we don\'t have to recalculate it\n      var length = (int*)data.Scan0 + bmp.Height * bmp.Width;\n\n      for (var p = (int*)data.Scan0; p < length; p++)           \n      {\n\n         // get the rgb Distance\n         var r = ((*p >> 16) & 255) - sR;\n         var g = ((*p >> 8) & 255) - sG;\n         var b = ((*p >> 0) & 255) - sB;\n\n         // compare it against the threshold\n         if (r * r + g * g + b * b > thresh)\n            continue;\n         // poke the target color in\n         *p = target;\n      }\n\n      // unlock the bitmap\n      bmp.UnlockBits(data);\n      bmp.Save(toPath);\n   }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

用法

\n\n
ConvertImage(@"d:\\test.jpg", @"D:\\result.bmp", Color.FromArgb(247, 107, 1), Color.Black, 25);\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

笔记:我使用的是 jpg 色轮,所以它并不像它应该的那样干净

\n
\n\n
\n\n

原图

\n\n

在此输入图像描述

\n\n

阈值 25

\n\n

在此输入图像描述

\n\n

门槛 75

\n\n

在此输入图像描述

\n\n

门槛150

\n\n

在此输入图像描述

\n\n

橙色 测试阈值 75

\n\n

在此输入图像描述

\n\n

在此输入图像描述

\n\n
\n\n

不安全(C# 参考)

\n\n
\n

unsafe 关键字表示不安全的上下文,任何涉及指针的操作都需要它

\n
\n\n

不安全代码和指针(C# 编程指南)

\n\n
\n

在公共语言运行时 (CLR) 中,不安全代码被称为\n 不可验证的代码。C# 中的不安全代码不一定是危险的;它只是 CLR 无法验证其安全性的代码。因此,如果不安全的代码位于完全受信任的程序集中,则 CLR 将仅执行该代码。如果您使用不安全的代码,您有责任确保您的代码不会引入安全风险或指针错误。

\n
\n