从位图中删除一种颜色的所有色调
Remove all tones of a color from a bitmap
你好,我正在尝试消除保存在位图中的图像的所有橙色色调,我需要使用 tesseract 在图像中进行 OCR,而扫描文档的橙色似乎阻碍了产生错误的过程文本,我尝试用 photoshop 去除橙色,使 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);
}
}
}
此代码完全没有任何作用,图像保持不变。
然后我想到与像素 (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);
}
}
}
但问题是它只去除了一小部分,橙色像素仍然存在,因为正如我之前提到的,并不是所有的橙色调都是一样的,有人能想到点什么吗?
这里有一些关键点可以帮助您一路走来
- 不要使用
GetPixel
SetPixel
,它非常慢
- 为了提高速度,最好使用
unsafe
指针访问并调用 lockbits
以获得 Pinned Array
- 您可能想使用 阈值 来确定特定像素颜色是否接近您要删除的颜色
一个简单的颜色阈值可以通过以下计算(你也可以在Hue上计算)
给定
threshold
有点int
- 一种源颜色
- 像素颜色
阈值
var thresh = threshold * threshold;
// decode the RBG from the image Pointer
var r = ((*p >> 16) & 255) - sR;
var g = ((*p >> 8) & 255) - sG;
var b = ((*p >> 0) & 255) - sB;
// compare it against the threshold
if (r * r + g * g + b * b > thresh)
continue;
Note : The link given in the comments by TaW is extremely helpful at figuring out color distance.
使用lockbits
访问扫描线和固定我们的记忆
Bitmap.LockBits Method (Rectangle, ImageLockMode, PixelFormat)
Locks a Bitmap into system memory.
代码
private static unsafe void ConvertImage(string fromPath, string toPath, Color source, Color targetColor, double threshold)
{
var thresh = threshold * threshold;
var target = targetColor.ToArgb();
using (var bmp = new Bitmap(fromPath))
{
// lock the array for direct access
var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppPArgb);
// Convert the source to rgb
int sR = source.R, sG = source.G, sB = source.B;
// store the max length so we don't have to recalculate it
var length = (int*)data.Scan0 + bmp.Height * bmp.Width;
for (var p = (int*)data.Scan0; p < length; p++)
{
// get the rgb Distance
var r = ((*p >> 16) & 255) - sR;
var g = ((*p >> 8) & 255) - sG;
var b = ((*p >> 0) & 255) - sB;
// compare it against the threshold
if (r * r + g * g + b * b > thresh)
continue;
// poke the target color in
*p = target;
}
// unlock the bitmap
bmp.UnlockBits(data);
bmp.Save(toPath);
}
}
用法
ConvertImage(@"d:\test.jpg", @"D:\result.bmp", Color.FromArgb(247, 107, 1), Color.Black, 25);
Note : i'm using a jpg color wheel so its not as clean as it could be
原图
阈值 25
阈值 75
阈值 150
橙色测试阈值 75
The unsafe keyword denotes an unsafe context, which is required for
any operation involving pointers
Unsafe Code and Pointers (C# Programming Guide)
In the common language runtime (CLR), unsafe code is referred to as
unverifiable code. Unsafe code in C# is not necessarily dangerous; it
is just code whose safety cannot be verified by the CLR. The CLR will
therefore only execute unsafe code if it is in a fully trusted
assembly. If you use unsafe code, it is your responsibility to ensure
that your code does not introduce security risks or pointer errors.
你好,我正在尝试消除保存在位图中的图像的所有橙色色调,我需要使用 tesseract 在图像中进行 OCR,而扫描文档的橙色似乎阻碍了产生错误的过程文本,我尝试用 photoshop 去除橙色,使 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);
}
}
}
此代码完全没有任何作用,图像保持不变。
然后我想到与像素 (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);
}
}
}
但问题是它只去除了一小部分,橙色像素仍然存在,因为正如我之前提到的,并不是所有的橙色调都是一样的,有人能想到点什么吗?
这里有一些关键点可以帮助您一路走来
- 不要使用
GetPixel
SetPixel
,它非常慢 - 为了提高速度,最好使用
unsafe
指针访问并调用lockbits
以获得Pinned Array
- 您可能想使用 阈值 来确定特定像素颜色是否接近您要删除的颜色
一个简单的颜色阈值可以通过以下计算(你也可以在Hue上计算)
给定
threshold
有点int
- 一种源颜色
- 像素颜色
阈值
var thresh = threshold * threshold;
// decode the RBG from the image Pointer
var r = ((*p >> 16) & 255) - sR;
var g = ((*p >> 8) & 255) - sG;
var b = ((*p >> 0) & 255) - sB;
// compare it against the threshold
if (r * r + g * g + b * b > thresh)
continue;
Note : The link given in the comments by TaW is extremely helpful at figuring out color distance.
使用lockbits
访问扫描线和固定我们的记忆
Bitmap.LockBits Method (Rectangle, ImageLockMode, PixelFormat)
Locks a Bitmap into system memory.
代码
private static unsafe void ConvertImage(string fromPath, string toPath, Color source, Color targetColor, double threshold)
{
var thresh = threshold * threshold;
var target = targetColor.ToArgb();
using (var bmp = new Bitmap(fromPath))
{
// lock the array for direct access
var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppPArgb);
// Convert the source to rgb
int sR = source.R, sG = source.G, sB = source.B;
// store the max length so we don't have to recalculate it
var length = (int*)data.Scan0 + bmp.Height * bmp.Width;
for (var p = (int*)data.Scan0; p < length; p++)
{
// get the rgb Distance
var r = ((*p >> 16) & 255) - sR;
var g = ((*p >> 8) & 255) - sG;
var b = ((*p >> 0) & 255) - sB;
// compare it against the threshold
if (r * r + g * g + b * b > thresh)
continue;
// poke the target color in
*p = target;
}
// unlock the bitmap
bmp.UnlockBits(data);
bmp.Save(toPath);
}
}
用法
ConvertImage(@"d:\test.jpg", @"D:\result.bmp", Color.FromArgb(247, 107, 1), Color.Black, 25);
Note : i'm using a jpg color wheel so its not as clean as it could be
原图
阈值 25
阈值 75
阈值 150
橙色测试阈值 75
The unsafe keyword denotes an unsafe context, which is required for any operation involving pointers
Unsafe Code and Pointers (C# Programming Guide)
In the common language runtime (CLR), unsafe code is referred to as unverifiable code. Unsafe code in C# is not necessarily dangerous; it is just code whose safety cannot be verified by the CLR. The CLR will therefore only execute unsafe code if it is in a fully trusted assembly. If you use unsafe code, it is your responsibility to ensure that your code does not introduce security risks or pointer errors.