Reputation: 85
Hello I am trying to eliminate all the orange tones of an image saved in a bitmap, I need to do OCR in the image with tesseract and the orange color of the scanned document seems to hinder the process producing errors in the text, I have tried removing the orange color I with photoshop, making the OCR and works perfectly, the main problem is that the pixels are not all of the same color, they are orange but in different shades
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);
}
}
}
This code does absolutely nothing, the image remains identical.
Then it occurs to me to compare with the pixel (0,0) since it is always the color I want to eliminate.
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);
}
}
}
But the problem is that it only removes a small part, orange pixels remain because as I mentioned before, not all orange tones are the same, can someone think of something?
Upvotes: 2
Views: 2137
Reputation: 81573
Here are some key points to help you along your way
GetPixel
SetPixel
, its extremely slow unsafe
with pointer access and call lockbits
to get a Pinned Array
A simple color threshold can be calculated by the following (you can also calculate this on Hue)
Given
threshold
is some int
Threshold
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.
Use lockbits
to get access to the Scanlines and Pin our memory
Bitmap.LockBits Method (Rectangle, ImageLockMode, PixelFormat)
Locks a Bitmap into system memory.
Code
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);
}
}
Usage
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
Original image
Threshold 25
Threshold 75
Threshold 150
Orange Test threshold 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.
Upvotes: 6