Image Processing in C# - A smart solution? - c#

I have an image with letters in it, the letters are in two colors black and blue, I want to read the blue colored letters from the image.
Can anyone suggest me a method to do this in C#. Iam studying GDI+,but still didn't get any logic to develop this program..
I tried OCRing it, but the issue with common OCRs is that they dont recognize the color difference.
I only want to read the Blue characters....
Any guidance is highly appreciated.

Try this one ;) But that's unsafe code.
void RedAndBlue()
{
OpenFileDialog ofd;
int imageHeight, imageWidth;
if (ofd.ShowDialog() == DialogResult.OK)
{
Image tmp = Image.FromFile(ofd.FileName);
imageHeight = tmp.Height;
imageWidth = tmp.Width;
}
else
{
// error
}
int[,] bluePixelArray = new int[imageWidth, imageHeight];
int[,] redPixelArray = new int[imageWidth, imageHeight];
Rectangle rect = new Rectangle(0, 0, tmp.Width, tmp.Height);
Bitmap temp = new Bitmap(tmp);
BitmapData bmpData = temp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int remain = bmpData.Stride - bmpData.Width * 3;
unsafe
{
byte* ptr = (byte*)bmpData.Scan0;
for (int j = 0; j < bmpData.Height; j++)
{
for (int i = 0; i < bmpData.Width; i++)
{
bluePixelArray[i, j] = ptr[0];
redPixelArray[i, j] = ptr[2];
ptr += 3;
}
ptr += remain;
}
}
temp.UnlockBits(bmpData);
temp.Dispose();
}

Modify the color of the image to gray scaled then use OCR
public Bitmap MakeGrayscale(Bitmap original)
{
//make an empty bitmap the same size as original
Bitmap newBitmap = new Bitmap(original.Width, original.Height);
for (int i = 0; i < original.Width; i++)
{
for (int j = 0; j < original.Height; j++)
{
//get the pixel from the original image
Color originalColor = original.GetPixel(i, j);
//create the grayscale version of the pixel
int grayScale = (int)((originalColor.R * .3) + (originalColor.G * .59)
+ (originalColor.B * .11));
//create the color object
Color newColor = Color.FromArgb(grayScale, grayScale, grayScale);
//set the new image's pixel to the grayscale version
newBitmap.SetPixel(i, j, newColor);
}
}
return newBitmap;
}

You could probably modify the palette to have only black and white on the image

Related

How to convert gray image into colormap

enter image description here
i have a color feet image, it transform to grayscale, and then to colormap (jet)
i did it in emgucv, but the color doesnt look so diferent, i need that the result image like the second (only 4-6 color, red, orange*, yellow, green, blue, purple*)
it is possible?
i already try on emgucv and read something gdi+, but i dont understand, i just begin to program
i try this but the color are the same, just more pixel, no gradient
int divideWith = 48;
byte[] table = new byte[256];
for (int i = 0; i < 256; i++)
{
table[i] = (byte)(divideWith * (i / divideWith));
}
Mat mat = ConvertBitmapToMat(rgb);
//_Stopwatch.Reset();
int rows = mat.Rows;
int cols = mat.Cols;
byte[,,] data = mat.ToImage<Bgr, byte>().Data;
byte[,,] resData = new byte[rows, cols, 3];
Parallel.For(0, rows, i =>
{
for (int j = 0; j < cols; j++)
{
resData[i, j, 0] = table[data[i, j, 0]];
resData[i, j, 1] = table[data[i, j, 1]];
resData[i, j, 2] = table[data[i, j, 2]];
}
});
Image<Bgr, byte> resImg = new Image<Bgr, byte>(resData);
Bitmap im = resImg.ToBitmap();
pictureBox2.Image = im;

How to change value of red/green/blue/alpha values from pixels

I'm working on a processing image software and now i want to change white balance and add some saturation on my photos, so i have to work with each pixel value.
I've tried to transform my BitmapImage to WritableBitmap and then I've tried this code. But if i run it, my image turns to green.
I want to take pixels from that image and then set them to new values.
I've searched many solutions but found none, so maybe someone can help me with my code. Thanks.
public static WriteableBitmap Colors(Bitmap Image)
{
int width = Image.Width;
int height = Image.Width;
byte[,,] pixels = new byte[height, width, 4];
WriteableBitmap wbitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
var target = new Bitmap(Image.Width, Image.Height);
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
pixels[i, j, 1] -= 30;
pixels[i, j, 3] -= 30;
}
}
byte[] pixels1d = new byte[height * width * 4];
int index = 0;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
for (int i = 0; i < 4; i++)
pixels1d[index++] = pixels[row, col, i];
}
}
Int32Rect rect = new Int32Rect(0, 0, width, height);
int stride = 4 * width;
wbitmap.WritePixels(rect, pixels1d, stride, 0);
return wbitmap;
}
And then I'm running it like this:
private void run_OnClick(object sender, RoutedEventArgs e)
{
// Contrastt(BitmapImage2Bitmap(bitmap), 10);
// MedianFilter(BitmapImage2Bitmap(bitmap),5);
WriteableBitmap writeableBitmap = new WriteableBitmap(imageX);
BitmapImage colored = ConvertWriteableBitmapToBitmapImage(Colors((BitmapImage2Bitmap(bitmap))));
ImageBrush brush = new ImageBrush();
brush.ImageSource = imageX ;
CanvasProcessedImage.Background = brush;
}
Assuming that you already have a BitmapSource (or an instance of a derived class like BitmapImage) in a source variable, you would first create a BitmapSource with a known pixel format, and then create a WritabelBitmap from that:
// source is a BitmapSource with whatever PixelFormat
var format = PixelFormats.Bgra32;
var temp = new FormatConvertedBitmap(source, format, null, 0); // force BGRA
var bitmap = new WriteableBitmap(temp);
Now you could either directly manipulate the data in the WriteableBitmap's BackBuffer property, or first do it a bit simpler and create a copy of the buffer like this:
var width = bitmap.PixelWidth;
var height = bitmap.PixelHeight;
var stride = bitmap.BackBufferStride;
var buffer = new byte[stride * height];
bitmap.CopyPixels(buffer, stride, 0);
Then manipulate the buffer and write it back to the WriteableBitmap. Since you have specified the PixelFormat, you know which byte of each 4-byte pixel value is B, G, R and A respectively.
for (int i = 0; i < buffer.Length; i += 4)
{
// Blue
//buffer[i + 0] = ...
// Green
buffer[i + 1] = (byte)Math.Max(buffer[i + 1] - 30, 0);
// Red
buffer[i + 2] = (byte)Math.Max(buffer[i + 2] - 30, 0);
// Alpha
//buffer[i + 3] = ...
}
bitmap.WritePixels(new Int32Rect(0, 0, width, height), buffer, stride, 0);
When you have assigned the WriteableBitmap to the Source property of an Image element, or the ImageSource property of an ImageBrush, you can call WritePixels later (and as often as necessary) without needing to reassign it it to the Source/ImageSource property. It is changed "in place".

Convert ARGB to PARGB

I've been looking for a fast alternative method of SetPixel() and I have found this link : C# - Faster Alternatives to SetPixel and GetPixel for Bitmaps for Windows Forms App
So my problem is that I've an image and I want to create a copy as a DirectBitmap object but first I need to convert ARGB to PARGB so I used this code:
public static Color PremultiplyAlpha(Color pixel)
{
return Color.FromArgb(
pixel.A,
PremultiplyAlpha_Component(pixel.R, pixel.A),
PremultiplyAlpha_Component(pixel.G, pixel.A),
PremultiplyAlpha_Component(pixel.B, pixel.A));
}
private static byte PremultiplyAlpha_Component(byte source, byte alpha)
{
return (byte)((float)source * (float)alpha / (float)byte.MaxValue + 0.5f);
}
and Here's my copy code:
DirectBitmap DBMP = new DirectBitmap(img.Width, img.Height);
MyImage myImg = new MyImage(img as Bitmap);
for (int i = 0; i < img.Width; i++)
{
for (int j = 0; j < img.Height; j++)
{
Color PARGB = NativeWin32.PremultiplyAlpha(Color.FromArgb(myImg.RGB[i, j].Alpha,
myImg.RGB[i, j].R, myImg.RGB[i, j].G, myImg.RGB[i, j].B));
byte[] bitMapData = new byte[4];
bitMapData[3] = (byte)PARGB.A;
bitMapData[2] = (byte)PARGB.R;
bitMapData[1] = (byte)PARGB.G;
bitMapData[0] = (byte)PARGB.B;
DBMP.Bits[(i * img.Height) + j] = BitConverter.ToInt32(bitMapData, 0);
}
}
MyImage : a class containing a Bitmap object along with an array of struct RGB storing the colors of each pixel
However, this code gives me a messed up image. what am I doing wrong?
Bitmap data is organized horizontal line after horizontal line. Therefore, your last line should be:
DBMP.Bits[j * img.Width + i] = BitConverter.ToInt32(bitMapData, 0);

Strange colors while displaying bitmap with PixelFormat.Format8bppIndexed

I would like to ask for help. I want to create an image from array and show it in PictureBox. But image, that was supposed to be in gray scale, is displayed in strange colors. In the past, I have had such a problem, but the methods used until now have failed. Here is my code:
public static Bitmap BitmapFromArray(int[] pixelValues,int rows, int columns)
{
Bitmap bitmap = new Bitmap(rows, columns);
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, rows, columns), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
byte[] pixelValuesOriginal = new byte[Math.Abs(bmpData.Stride) * bitmap.Height];
//Pobierz wartosc wszystkich punktow obrazu
System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, pixelValuesOriginal, 0, pixelValues.Length);
for (int i = 0; i < pixelValues.Length; i++)
{
pixelValuesOriginal[i] = (byte)pixelValues[i];
}
//Ustaw wartosc wszystkich punktow obrazu
System.Runtime.InteropServices.Marshal.Copy(pixelValuesOriginal, 0, bmpData.Scan0, pixelValuesOriginal.Length);
bitmap.UnlockBits(bmpData);
return bitmap;
}
I tried the method that I found here: Editing 8bpp indexed Bitmaps
ColorPalette pal = bitmap.Palette;
for (int i = 0; i <= 255; i++)
{
pal.Entries[i] = Color.FromArgb(i, i, i);
}
bitmap.Palette = pal;
But this time it did not work because bitmap.Palette.Entries is an array with 0 elements.
I also tried to change the PixelFormat for PixelFormat.Format24bppRgb and use such a trick:
for (int i = 0; i < pixelValues.Length; i++)
{
for (int j = 0; j < 3; j++)
{
pixelValuesOriginal[i + j] = (byte)pixelValues[i];
}
}
But then I have three gray scaled pictures side by side.
I will be grateful for hints on what to do with this problem.

How to draw an image?

How can I create a 256x256 color space image using graphics draw? Currently I'm using pointers to loop through each pixel location and setting it. Blue goes from 0...255 on X and Green goes from 0...255 on Y. The image is initialized as so.
Bitmap image = new Bitmap(256, 256);
imageData = image.LockBits(new Rectangle(0, 0, 256, 256),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
for (int row = 0; row < 256; row++)
{
byte* ptr = (byte*)imageData.Scan0 + (row * 768);
for (int col = 0; col < 256; col++)
{
ptr[col * 3] = (byte)col;
ptr[col * 3 + 1] = (byte)(255 - row);
ptr[col * 3 + 2] = 0;
}
}
I have a slider that goes 0...255 on Red. On each scroll, it goes through this loop and updates the image.
for (int row = 0; row < 256; row++)
{
byte* ptr = (byte*)imageData.Scan0 + (row * 768);
for (int col = 0; col < 256; col++)
{
ptr[col * 3 + 2] = (byte)trackBar1.Value;
}
}
I've figured out how to use a ColorMatrix instead for the scrolling part but how can I initialize the image without using pointers or SetPixel?
First of all, add PictureBox control to the Form.
Then, this code will assign different color to each pixel based on the index in the loop and assign the image to the control:
Bitmap image = new Bitmap(pictureBox3.Width, pictureBox3.Height);
SolidBrush brush = new SolidBrush(Color.Empty);
using (Graphics g = Graphics.FromImage(image))
{
for (int x = 0; x < image.Width; x++)
{
for (int y = 0; y < image.Height; y++)
{
brush.Color = Color.FromArgb(x, y, 0);
g.FillRectangle(brush, x, y, 1, 1);
}
}
}
pictureBox3.Image = image;
For some reason there's no SetPixel or DrawPixel like I expected, but the FillRectangle will do exactly the same thing when you give it 1x1 dimensions to fill.
Note that it will work fine for small images but the larger the image the slower it will be.
If you don't want to use pointers or SetPixel you'll have to build the gradient in a byte array and then Marshal.Copy it to your bitmap:
int[] b = new int[256*256];
for (int i = 0; i < 256; i++)
for (int j = 0; j < 256; j++)
b[i * 256 + j] = j|i << 8;
Bitmap bmp = new Bitmap(256, 256, PixelFormat.Format32bppRgb);
BitmapData bits = bmp.LockBits(new Rectangle(0, 0, 256, 256),
ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);
Marshal.Copy(b, 0, bits.Scan0, b.Length);
This would create you a white image of 256x256
Bitmap image = new Bitmap(256, 256);
using (Graphics g = Graphics.FromImage(image)){
g.FillRectangle(Brushes.White, 0, 0, 256, 256);
}

Categories

Resources