I'm writing a simple game - snake. I would like to have background and my snake on it. I think that the best way is use two pictureBox (one with background and second - transparent with snake on it).
This is a good way? And how can I put several small images (snake's segments) on one picture box in different places (just copy pixel's (one after one) from image to pictureBox or maybe there is fastest way - putting all image in correct place)? I have pictureBox with background (parent) and and another, transparent (child) on it now.
The result should be look something like that:
I've made something like that (thanks to #dotTutorials), but my snake's segments are a little bit bigger than original images and cookie is smaller. Where can be a problem?
Drawing Code:
public Bitmap PrinPlayground()
{
char[,] tempPitch = play.getPitch();
Graphics g = pb2.CreateGraphics();
Bitmap bitmap = new Bitmap(512, 512);
Graphics BBG = Graphics.FromImage(bitmap);
Bitmap head = CookieSnake.Properties.Resources.head;
Bitmap body01 = CookieSnake.Properties.Resources.body01;
Bitmap tail = CookieSnake.Properties.Resources.tail;
Bitmap cookie = CookieSnake.Properties.Resources.cookie;
BBG.Clear(Color.Transparent);
for (int i = 0; i < 16; i++)
for (int j = 0; j < 16; j++)
{
if (tempPitch[i, j] == 'H')
{
BBG.DrawImage(head, new Point(32*j, 32*i));
}
else if (tempPitch[i, j] == 'B')
{
BBG.DrawImage(body01, new Point(32*j, 32*i));
}
else if (tempPitch[i, j] == 'T')
{
BBG.DrawImage(tail, new Point(32 * j, 32 * i));
}
else if (tempPitch[i, j] == 'C')
{
BBG.DrawImage(cookie, new Point(32 * j, 32 * i));
}
}
g.DrawImage(bitmap, new Point(0,0));
return bitmap;
}
Result:
The best way to achieve this is definitely to use the 'Graphics' class. Please look further into the GDI, and the namespace System.Drawing.
If you want to use a Picturebox representing the game space, you can easily implement graphics to a picturebox as well, by calling the member CreateGraphics.
I hope this helps you! :)
Please notice that when you get into serious game development, you'll have to find a better alternative than GDI. I personally prefer the XNA library
Example usage of GDI [This written fast, and should not be copy - pasted. However; It is a good point of origin :)]
Graphics g = pictureBox1.CreateGraphics();
Bitmap BB = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Graphics BBG = Graphics.FromImage(BB);
Bitmap Background = (Bitmap)Bitmap.FromFile("BackgroundPicture.png");
Bitmap Head = (Bitmap)Bitmap.FromFile("SnakeHead.png");
Bitmap Tail = (Bitmap)Bitmap.FromFile("SnakeTail.png");
Point snakeLocation = new Point((BB.Width / 2) - (Head.Width / 2), (BB.Height / 2) - (Head.Height / 2));
while (true) {
#region Update
// update method here!
snakeLocation.X += 1;
#endregion
#region Draw
BBG.Clear(Color.CornflowerBlue);
BBG.DrawImage(Background, new Point(0, 0));
BBG.DrawImage(Head, snakeLocation);
BBG.DrawImage(Tail, new Point(snakeLocation.X - Head.Width, snakeLocation.Y));
g.DrawImage(BB, new Point(0, 0)); // draw to screen
#endregion
}
UPDATE: The DrawImage method also accepts a RectangleF input. A RectangleF consits of 4 datatypes, float X, float Y, float Width and float Height.
With a RectangleF you can easily specify the size of the drawn image. Take a look at the code below:
public Bitmap PrinPlayground() {
char[,] tempPitch = play.getPitch();
Graphics g = pb2.CreateGraphics();
Bitmap bitmap = new Bitmap(512, 512);
Graphics BBG = Graphics.FromImage(bitmap);
Bitmap head = CookieSnake.Properties.Resources.head;
Bitmap body01 = CookieSnake.Properties.Resources.body01;
Bitmap tail = CookieSnake.Properties.Resources.tail;
Bitmap cookie = CookieSnake.Properties.Resources.cookie;
BBG.Clear(Color.Transparent);
for (int i = 0; i < 16; i++)
for (int j = 0; j < 16; j++) {
if (tempPitch[i, j] == 'H') {
BBG.DrawImage(head, new RectangleF(new Point(32 * j, 32 * i), new SizeF(/*Adjust the size after your pleasure*/32, 32)));
}
else if (tempPitch[i, j] == 'B') {
BBG.DrawImage(body01, new RectangleF(new Point(32 * j, 32 * i), new SizeF(32, 32)));
}
else if (tempPitch[i, j] == 'T') {
BBG.DrawImage(tail, new RectangleF(new Point(32 * j, 32 * i), new SizeF(32, 32)));
}
else if (tempPitch[i, j] == 'C') {
BBG.DrawImage(cookie, new RectangleF(new Point(32 * j, 32 * i), new SizeF(/*Half the size of the head [Adjust after your needs!]*/32 / 2, 32 / 2)));
}
}
g.DrawImage(bitmap, new Point(0, 0));
return bitmap;
}
}
Related
This simple code gives me very bad result.
Image global_src_img = Image.FromFile(Application.StartupPath + "\\src.png");
Image src_img = ((Bitmap)global_src_img).Clone(new Rectangle(160, 29, 8, 14), PixelFormat.Format32bppArgb);
src_img.Save(Application.StartupPath + "\\src_clonned.png", ImageFormat.Png);
Bitmap trg_bmp = new Bitmap(100, 100);
Graphics gfx = Graphics.FromImage(trg_bmp);
gfx.FillRectangle(new Pen(Color.FromArgb(255, 0, 0, 0)).Brush, 0, 0, trg_bmp.Width, trg_bmp.Height);
gfx.DrawImageUnscaled(src_img, (trg_bmp.Width / 2) - (src_img.Width / 2), (trg_bmp.Height / 2) - (src_img.Height / 2));
gfx.Dispose();
trg_bmp.Save(Application.StartupPath + "\\trg.png", ImageFormat.Png);
It clones part of the big image with letters and writes it to another image.
Written image has extra pixels at outer borders that does not present in source image same as in cloned image.
How to avoid it?
This is cloned image (src_clonned.png) that later will be drawn on graphics.
This is saved resulting image (trg.png).
Draw directly on bitmap to avoid any pixels modifications with this:
public static void DrawImgOnImg(Image src, Bitmap trg, int x, int y)
{
for (int i = x; i < x + src.Width; i++)
for (int j = y; j < y + src.Height; j++)
{
Color src_px = ((Bitmap)src).GetPixel(i - x, j - y);
trg.SetPixel(i, j, src_px);
}
}
I am writing a .Net wrapper for Tesseract Ocr and if I use a grayscale image instead of rgb image as an input file to it then results are pretty good.
So I was searching the web for C# solution to convert a Rgb image to grayscale image and I found this code.
This performs 3 operations to increase the accuracy of tesseract.
Resize the image
then convert into grayscale image and remove noise from image
Now this converted image gives almost 90% accurate results.
//Resize
public Bitmap Resize(Bitmap bmp, int newWidth, int newHeight)
{
Bitmap temp = (Bitmap)bmp;
Bitmap bmap = new Bitmap(newWidth, newHeight, temp.PixelFormat);
double nWidthFactor = (double)temp.Width / (double)newWidth;
double nHeightFactor = (double)temp.Height / (double)newHeight;
double fx, fy, nx, ny;
int cx, cy, fr_x, fr_y;
Color color1 = new Color();
Color color2 = new Color();
Color color3 = new Color();
Color color4 = new Color();
byte nRed, nGreen, nBlue;
byte bp1, bp2;
for (int x = 0; x < bmap.Width; ++x)
{
for (int y = 0; y < bmap.Height; ++y)
{
fr_x = (int)Math.Floor(x * nWidthFactor);
fr_y = (int)Math.Floor(y * nHeightFactor);
cx = fr_x + 1;
if (cx >= temp.Width)
cx = fr_x;
cy = fr_y + 1;
if (cy >= temp.Height)
cy = fr_y;
fx = x * nWidthFactor - fr_x;
fy = y * nHeightFactor - fr_y;
nx = 1.0 - fx;
ny = 1.0 - fy;
color1 = temp.GetPixel(fr_x, fr_y);
color2 = temp.GetPixel(cx, fr_y);
color3 = temp.GetPixel(fr_x, cy);
color4 = temp.GetPixel(cx, cy);
// Blue
bp1 = (byte)(nx * color1.B + fx * color2.B);
bp2 = (byte)(nx * color3.B + fx * color4.B);
nBlue = (byte)(ny * (double)(bp1) + fy * (double)(bp2));
// Green
bp1 = (byte)(nx * color1.G + fx * color2.G);
bp2 = (byte)(nx * color3.G + fx * color4.G);
nGreen = (byte)(ny * (double)(bp1) + fy * (double)(bp2));
// Red
bp1 = (byte)(nx * color1.R + fx * color2.R);
bp2 = (byte)(nx * color3.R + fx * color4.R);
nRed = (byte)(ny * (double)(bp1) + fy * (double)(bp2));
bmap.SetPixel(x, y, System.Drawing.Color.FromArgb(255, nRed, nGreen, nBlue));
}
}
//here i included the below to functions logic without the for loop to remove repetitive use of for loop but it did not work and taking the same time.
bmap = SetGrayscale(bmap);
bmap = RemoveNoise(bmap);
return bmap;
}
//SetGrayscale
public Bitmap SetGrayscale(Bitmap img)
{
Bitmap temp = (Bitmap)img;
Bitmap bmap = (Bitmap)temp.Clone();
Color c;
for (int i = 0; i < bmap.Width; i++)
{
for (int j = 0; j < bmap.Height; j++)
{
c = bmap.GetPixel(i, j);
byte gray = (byte)(.299 * c.R + .587 * c.G + .114 * c.B);
bmap.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
}
}
return (Bitmap)bmap.Clone();
}
//RemoveNoise
public Bitmap RemoveNoise(Bitmap bmap)
{
for (var x = 0; x < bmap.Width; x++)
{
for (var y = 0; y < bmap.Height; y++)
{
var pixel = bmap.GetPixel(x, y);
if (pixel.R < 162 && pixel.G < 162 && pixel.B < 162)
bmap.SetPixel(x, y, Color.Black);
}
}
for (var x = 0; x < bmap.Width; x++)
{
for (var y = 0; y < bmap.Height; y++)
{
var pixel = bmap.GetPixel(x, y);
if (pixel.R > 162 && pixel.G > 162 && pixel.B > 162)
bmap.SetPixel(x, y, Color.White);
}
}
return bmap;
}
But the problem is it takes lot of time to convert it
So I included SetGrayscale(Bitmap bmap)
RemoveNoise(Bitmap bmap) function logic inside the Resize() method to remove repetitive use of for loop
but it did not solve my problem.
The Bitmap class's GetPixel() and SetPixel() methods are notoriously slow for multiple read/writes. A much faster way to access and set individual pixels in a bitmap is to lock it first.
There's a good example here on how to do that, with a nice class LockedBitmap to wrap around the stranger Marshaling code.
Essentially what it does is use the LockBits() method in the Bitmap class, passing a rectangle for the region of the bitmap you want to lock, and then copy those pixels from its unmanaged memory location to a managed one for easier access.
Here's an example on how you would use that example class with your SetGrayscale() method:
public Bitmap SetGrayscale(Bitmap img)
{
LockedBitmap lockedBmp = new LockedBitmap(img.Clone());
lockedBmp.LockBits(); // lock the bits for faster access
Color c;
for (int i = 0; i < lockedBmp.Width; i++)
{
for (int j = 0; j < lockedBmp.Height; j++)
{
c = lockedBmp.GetPixel(i, j);
byte gray = (byte)(.299 * c.R + .587 * c.G + .114 * c.B);
lockedBmp.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
}
}
lockedBmp.UnlockBits(); // remember to release resources
return lockedBmp.Bitmap; // return the bitmap (you don't need to clone it again, that's already been done).
}
This wrapper class has saved me a ridiculous amount of time in bitmap processing. Once you've implemented this in all your methods, preferably only calling LockBits() once, then I'm sure your application's performance will improve tremendously.
I also see that you're cloning the images a lot. This probably doesn't take up as much time as the SetPixel()/GetPixel() thing, but its time can still be significant especially with larger images.
The easiest way would be to redraw the image onto itself using DrawImage and passing a suitable ColorMatrix. Google for ColorMatrix and gray scale and you'll find a ton of examples, this one for example: http://www.codeproject.com/Articles/3772/ColorMatrix-Basics-Simple-Image-Color-Adjustment
After using STFT(Short-time Fourier transform) the output is a matrix that represents a 3d plot as though (A[X, Y] = M) A is the output matrix, X is the time , Y is the frequency, and the third dimension M is the amplitude illustrated by the intensity of the pixel color as in the following pictures:
Spectrogram 2
How do I draw the output matrix A with a gradient of colors like in the pictures in C#? Is there a library that contains a spectrogram control for C#?
Update:
After some modifications on the given algorithm I could draw the spectrogram, I didn't change the color palette except the first color changed to black but I don't know why it's very faded!
This one represents a sound saying
Bye Bye
Bye Bye Spectrogram
And this one of a pure sine wave so it's almost the same frequency all the time
Pure sine wave Spectrogram
The output is accepted it represents the frequencies of the input signal as expected, but i think there is a way to make the spectrogram as well illustrated as the ones in the examples, could you please take a look at my code and suggest modifications?
This is the event handler:
private void SpectrogramButton_Click(object sender, EventArgs e)
{
Complex[][] SpectrogramData = Fourier_Transform.STFT(/*signal:*/ samples, /*windowSize:*/ 512, /*hopSize:*/ 512);
SpectrogramBox.Image = Spectrogram.DrawSpectrogram(SpectrogramData, /*Interpolation Factor:*/ 1000, /*Height:*/ 256);
}
And this one is the drawing function after my modifications:
public static Bitmap DrawSpectrogram(Complex[][] Data, int InterpolationFactor, int Height)
{
// target size:
Size sz = new Size(Data.GetLength(0), Height);
Bitmap bmp = new Bitmap(sz.Width, sz.Height);
// the data array:
//double[,] data = new double[222, 222];
// step sizes:
float stepX = 1f * sz.Width / Data.GetLength(0);
float stepY = 1f * sz.Height / Data[0].GetLength(0);
// create a few stop colors:
List<Color> baseColors = new List<Color>(); // create a color list
baseColors.Add(Color.Black);
baseColors.Add(Color.LightSkyBlue);
baseColors.Add(Color.LightGreen);
baseColors.Add(Color.Yellow);
baseColors.Add(Color.Orange);
baseColors.Add(Color.Red);
// and the interpolate a larger number of grdient colors:
List<Color> colors = interpolateColors(baseColors, InterpolationFactor);
// a few boring test data
//Random rnd = new Random(1);
//for (int x = 0; x < data.GetLength(0); x++)
// for (int y = 0; y < data.GetLength(1); y++)
// {
// //data[x, y] = rnd.Next((int)(300 + Math.Sin(x * y / 999) * 200)) +
// // rnd.Next(x + y + 111);
// data[x, y] = 0;
// }
// now draw the data:
float Max = Complex.Max(Data);
using (Graphics G = Graphics.FromImage(bmp))
for (int x = 0; x < Data.GetLength(0); x++)
for (int y = 0; y < Data[0].GetLength(0); y++)
{
int Val = (int)Math.Ceiling((Data[x][y].Magnitude / Max) * (InterpolationFactor - 1));
using (SolidBrush brush = new SolidBrush(colors[(int)Val]))
G.FillRectangle(brush, x * stepX, (Data[0].GetLength(0) - y) * stepY, stepX, stepY);
}
// and display the result
return bmp;
}
I don't really understand the log thing that you are talking about in your answers, I'm sorry for my little knowledge.
Update:
This is the output after adding taking log10 to the magnitudes (negative values neglected):
This one of "Bye bye" from before:
A Shotgun Blast:
A Music Box:
I Think this output is acceptable, it is different from the examples I brought in the beginning but I think it's better.
No, there is no out of the box control I know of. There may well be outside libraries you can buy, of course, but shhh, you can't ask on SO about them..
In theory you could use, or I guess I should rather say abuse a Chart control for this. But since DataPoints are rather expensive objects, or at least more expensive than they look, this seems not advisable.
Instead you can simply draw the graph into a Bitmap yourself.
Step one is to decide on a gradient of colors. See the interpolateColors function here for an example of this!
Then you would simply do a double loop over the data using floats for the step and pixel sizes and do a Graphics.FillRectangle there.
Here is a simple example using GDI+ to create a Bitmap and a Winforms PictureBox for display. It doesn't add any axes to the graphic and fills it completely.
It first creates a few sample data and a gradient wih 1000 colors. Then it draws into a Bitmap and displays the result:
private void button6_Click(object sender, EventArgs e)
{
// target size:
Size sz = pictureBox1.ClientSize;
Bitmap bmp = new Bitmap(sz.Width, sz.Height);
// the data array:
double[,] data = new double[222, 222];
// step sizes:
float stepX = 1f * sz.Width / data.GetLength(0);
float stepY = 1f * sz.Height / data.GetLength(1);
// create a few stop colors:
List<Color> baseColors = new List<Color>(); // create a color list
baseColors.Add(Color.RoyalBlue);
baseColors.Add(Color.LightSkyBlue);
baseColors.Add(Color.LightGreen);
baseColors.Add(Color.Yellow);
baseColors.Add(Color.Orange);
baseColors.Add(Color.Red);
// and the interpolate a larger number of grdient colors:
List<Color> colors = interpolateColors(baseColors, 1000);
// a few boring test data
Random rnd = new Random(1);
for (int x = 0; x < data.GetLength(0); x++)
for (int y = 0; y < data.GetLength(1); y++)
{
data[x, y] = rnd.Next( (int) (300 + Math.Sin(x * y / 999) * 200 )) +
rnd.Next( x + y + 111);
}
// now draw the data:
using (Graphics G = Graphics.FromImage(bmp))
for (int x = 0; x < data.GetLength(0); x++)
for (int y = 0; y < data.GetLength(1); y++)
{
using (SolidBrush brush = new SolidBrush(colors[(int)data[x, y]]))
G.FillRectangle(brush, x * stepX, y * stepY, stepX, stepY);
}
// and display the result
pictureBox1.Image = bmp;
}
Here is the function from the link:
List<Color> interpolateColors(List<Color> stopColors, int count)
{
SortedDictionary<float, Color> gradient = new SortedDictionary<float, Color>();
for (int i = 0; i < stopColors.Count; i++)
gradient.Add(1f * i / (stopColors.Count - 1), stopColors[i]);
List<Color> ColorList = new List<Color>();
using (Bitmap bmp = new Bitmap(count, 1))
using (Graphics G = Graphics.FromImage(bmp))
{
Rectangle bmpCRect = new Rectangle(Point.Empty, bmp.Size);
LinearGradientBrush br = new LinearGradientBrush
(bmpCRect, Color.Empty, Color.Empty, 0, false);
ColorBlend cb = new ColorBlend();
cb.Positions = new float[gradient.Count];
for (int i = 0; i < gradient.Count; i++)
cb.Positions[i] = gradient.ElementAt(i).Key;
cb.Colors = gradient.Values.ToArray();
br.InterpolationColors = cb;
G.FillRectangle(br, bmpCRect);
for (int i = 0; i < count; i++) ColorList.Add(bmp.GetPixel(i, 0));
br.Dispose();
}
return ColorList;
}
You would probably want to draw axes with labels etc. You can use Graphics.DrawString or TextRenderer.DrawText to do so. Just leave enough space around the drawing area!
I used the data values cast to int as direct pointers into the color table.
Depending on your data you will need to scale them down or even use a log conversion. The first of your images show a logarithmic scale going from 100 to 20k, the second looks linear going from 0 to 100.
If you show us your data structure we can give you further hints how to adapt the code to use it..
You can create a bitmap as per the other answer. It's also common to use a color lookup table to convert FFT log magnitude to the color to use for each pixel or small rectangle.
Hello How to draw a circle with the bitmap. That is, I need to get the image of the circle, using it to draw something.
Use ColorTranslator.FromHtml for this purpose.
This will give you the corresponding System.Drawing.Color:
using (Bitmap btm = new Bitmap(25, 30))
{
using (Graphics grf = Graphics.FromImage(btm))
{
using (Brush brsh = new SolidBrush(ColorTranslator.FromHtml("#ff00ffff")))
{
grf.FillEllipse(brsh, 0, 0, 19, 19);
}
}
}
Or Refer Code:
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Graphics g = Graphics.FromImage(bmp);
Pen blackPen = new Pen(Color.Black);
int x = pictureBox1.Width/4;
int y = pictureBox1.Height/4;
int width = pictureBox1.Width / 2;
int height = pictureBox1.Height / 2;
int diameter = Math.Min(width, height);
g.DrawEllipse(blackPen, x, y, diameter, diameter);
pictureBox1.Image = bmp;
If the PictureBox already contains a bitmap, replace the first and second lines with:
Graphics g = Graphics.FromImage(pictureBox1.Image);
Referance Link:
http://www.c-sharpcorner.com/Forums/Thread/30986/
Hope Its Helpful.
Bitmap b = new Bitmap(261, 266);// height & width of picturebox
int xo = 50, yo = 50;// center of circle
double r, rr;
r = 20;
rr = Math.Pow(r, 2);
for (int i = xo - (int)r; i <= xo + r; i++)
for (int j = yo - (int)r; j <= yo + r; j++)
if (Math.Abs(Math.Pow(i - xo, 2) + Math.Pow(j - yo, 2) - rr) <= r)
b.SetPixel(i, j, Color.Black);
pictureBox1.Image = b;
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