gridding extraction in image - c#

There is an image, and there are some grid lines which are vertical or horizontal in the image. I just want to extract the gridding from the image, but there are many unnecessary lines in the image, interfering my work. Do anyone have a more methods to extract the gridding via C#?
My idea is that for grid lines, there are some basic unit that compose the whole gridding, so if I know the size of the basic unit and I know the initial point of the gridding, maybe I can re-draw the gridding. Thus, I think it is the key to resolve the problem.

There are two direction you can take:
Either you take a look at the image and draw a grid just like the one there
Or you try to analyze the image to find out the parameters it takes to draw thw grid
I loaded the image into Photoshop and found that the gridlines start at (6,10) with a raster of 43 pixels and a line width of 1.5-2 pixels.
Using these values to draw those lines is trivial:
Image img = Image.FromFile(yourImage);
Bitmap bmp = new Bitmap(img.Width, img.Height);
using (Graphics G = Graphics.FromImage(bmp) )
using (Pen pen = new Pen(Color.DarkBlue, 2f) )
{
G.Clear(Color.Black);
for (int x = 6; x < img.Width; x += 43)
G.DrawLine(pen, x, 0, x, img.Height);
for (int y = 10; y < img.Height; y += 43)
G.DrawLine(pen, 0, y, img.Width, y);
}
bmp.Save(yourGrid);
bmp.Dispose();
img.Dispose();
The second option is not trivial. If the image is in fact typical, the good news is that the lines are straight and the raster regular. But pulling those values from the image automagically is still not so simple. One dificulty id the varying color of the grid.. I would scan a number of rows and test the pixels for being not black. Those would go into lists and then I would discard points that are only in a minority of those lists. This would then be repeated for a number of columns.
The effort to put into this will only pay if you need this analysis to be done for a considerable number of files with different grids. If the number is small a semi-automatic analysis may be easier and if it is only about one file go for the manual analysis!

Related

How to draw a lot of clickable rectangles in WPF?

I'm working on a basic mindmap program but I don't have a lot of experience with drawing with WPF. I want to be able to draw rectangles with text on them and i would like to be able to click on the rectangles to change the text for example.
As of now I have:
private void DrawSubject(int curve, double X, double Y, Brush clr)
{
Rectangle rect = new Rectangle();
rect.Width = 62;
rect.Height = 38;
rect.Fill = clr;
rect.Stroke = line;
rect.RadiusX = rect.RadiusY = curve;
Canvas.SetLeft(rect, X);
Canvas.SetTop(rect, Y);
mindmap.Children.Add(rect);
}
SolidColorBrush line = new SolidColorBrush(Color.FromArgb(255, 21, 26, 53));
minmap is the name of the canvas. I want to be able to draw a lot of these rectangles which present branches of the mindmap. However, when I drew 10,000 of these on random locations the process memory in the diagnostic tools went up by 100 MB, after it was done drawing all of them. I did this to sort of simulate a mindmap with 10,000 branches. So i was wondering if there might be a way to decrease the used memory for these rectangles?
Or is it better to use DrawingVisual and a grid.click event which checks if the clicked position matches the position of a rectangle by putting the coordinates of the rectangle in a List?
I would attempt the DrawingVisual method you described, if that proves costly in performance(I don't know how well DrawingVisual works) you could look into embedding OpenGL or DirectX into your application and rendering them via that.
But raytracing drawn visuals rather than making a Control for each is definitely the way to go for your scale.

Custom Cursor - Colour Issues

I'm having a problem where a the colours in a custom cursor are sometimes not displaying correctly.
I have a Windows Forms application and on one of the forms there is a PictureBox control. When an image is loaded into that PictureBox and the mouse is moved over that control I want to display a custom cursor. This cursor is a little unusual in that for each image that's loaded into the PictureBox there's another associated image, and as the user moves the mouse pointer over the PictureBox control I want the cursor to be a square and within that square I want it to display the corresponding pixels from the associated image. Within certain limits, the size of the cursor may be changed by the user.
In principle I've nearly got it to work. Certainly at any given point the cursor is showing the right part of the associated image and it updates properly as I move the pointer around.
The problem is that the colours being displayed in the cursor are not always correct. They're in the right ballpark: a shade of red will always display as a shade of red for instance, just not necessarily the right shade. Sometimes the cursor colours look slightly darker, other times slightly lighter. I've noticed that for any colours where all three of the R, G and B components are a combination of 0 or 255, the colours always look correct.
In addition, this only happens if the cursor is a 64x64 pixel square or smaller. If the user increases the size of the cursor beyond that point the problem disappears, though it will reappear if the cursor size is later reduced back to 64x64 or smaller.
This is the code which does the work. X and Y come from the MouseMove event. CursorSize is a form-wide int variable which holds the size of the cursor in pixels (always an even number) and imgAssoc is a form-wide Image variable into which the associated image was loaded. picMain is the PictureBox control.
private void LoadCursorFromBitmap(int X, int Y)
{
int halfSize = CursorSize / 2;
// The new cursor image is a [CursorSize] x [CursorSize] pixel square.
using (Bitmap bmp = new Bitmap(CursorSize, CursorSize))
{
using (Graphics g = Graphics.FromImage(bmp))
{
// Create a [CursorSize] x [CursorSize] pixel square, centered on the X and Y co-ordinates.
Rectangle square = new Rectangle(X - halfSize, Y - halfSize, CursorSize, CursorSize);
// Copy the square section of the image to the bitmap.
g.DrawImage(imgAssoc, 0, 0, square, GraphicsUnit.Pixel);
// Draw a line around the edge of the bitmap.
using (Pen pen = new Pen(Color.FromArgb(64, Color.Black), 1F))
{
g.DrawRectangle(pen, 0, 0, CursorSize - 1, CursorSize - 1);
}
}
picMain.Cursor = new Cursor(bmp.GetHicon());
}
}
Any ideas how to solve this?

How to adjust axis scales for datavisualization.charting after resizing a chart?

I updated a chart from essentially being 72dpi, to 300dpi. This is because I am using itextsharp to add an image to my pdf and the quality was poor. So I increased the size of the image by 3X and the image does look better, but here is the problem.
DPI has increased, but detail has become very hard to see.
Original Chart Image
Refactored Chart Image
Code
This is how I resized my chart.
private static System.Drawing.Bitmap GetChartBitmap()
{
System.Drawing.Rectangle targetBounds = new System.Drawing.Rectangle(0, 0, chart_runs.Width, chart_runs.Height);
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(targetBounds.Width, targetBounds.Height);
bitmap.SetResolution(1000, 1000);
chart_runs.DrawToBitmap(bitmap, targetBounds);
bitmap.Save(#"C:\Temp\OriginalChartImage.bmp");
System.Drawing.Bitmap bitmap3 = new System.Drawing.Bitmap(1650, 990);
bitmap3.SetResolution(300, 300);
chart_runs.DrawToBitmap(bitmap3, new System.Drawing.Rectangle(0, 0, 1650, 990));
bitmap3.Save(#"C:\Temp\RefactoredChartImage.png");
//This stuff below is for my code elsewhere. Using bitmap3 to be added to pdf.
//chart_runs.DrawToBitmap(bitmap, targetBounds);
string path = System.IO.Path.GetTempPath();
bitmap1.Save(path + #"\Image.png");
return bitmap1;
}
I have looked at the Microsoft msdn examples and haven't found anything that addresses my problem. Namely, how can I either increase the size of my labels so people can read them again. OR, is there a way for me to increase the DPI and keep the same label x and label y scale that was used in the first picture? That is, have a larger image and 300DPI, but scale 0 to 300 by 20's and not 5's like my refactored picture?
Attempts to fix
Scaling the axis? See here. I don't think this is working right. Not much success here.
Been trying to find a way in Chart class to see if there is a way to specify strict scales. (20 on y scale vs 15 seconds on x scale).
Most online resources are pleased just to increase the scale of the picture and walk away. And things like this here.
I would greatly appreciate any help and assistance.
Couple different questions, with a couple different answers. The easiest would be to change the font size of your axis labels to be bigger. This can be done via
chart1.ChartAreas[0].AxisX.LabelStyle.Font = new Font...;
Without doing that, your labels won't be readable no matter what else you do, and that's just because you changed the DPI (that's exactly what changing the DPI does).
If you want the labels to be displayed every 20 units on the y axis and every 15 on the x, you can use the Interval and IntervalType properties of the axis. The IntervalType is used when you have DateTime objects being displayed:
chart1.ChartAreas[0].AxisX.Interval = 15;
chart1.ChartAreas[0].AxisX.IntervalType = DateTimeIntervalType.Seconds;
chart1.ChartAreas[0].AxisY.Interval = 20;
Your first link about scaling the axis is essentially zooming in or out, which is why you haven't had success.

How to get the pixels on a form drawn from the paint event?

I want to be able to get the pixels that are drawn on the form from the paint event. I've tried:
public Bitmap bmp;
Then later:
bmp = new Bitmap(this.BackgroundImage);
And then I could loop through the pixels:
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
bmp.GetPixel(x, y);
}
}
But this doesn't work, and I was wondering if anyone knew another way to do it.
Thanks.
(Warning: gross simplifications ahead!) Generally you can't, because the GDI target for window painting is (traditionally) the graphics card's framebuffer and you cannot read from it, only write to it.
(Of course, in practice it is possible to read from the framebuffer, but you shouldn't because it cannot be trusted as another window might overlap yours, or another process might be painting to it in another thread; Also, on modern systems (2006+) with composited window managers each window paints to an offscreen buffer rather than the framebuffer, it is also possible to read from these per-window buffers, but it isn't very fast or optimised - which is why XOR painting is so slow with the DWM on Windows)
For your approach, I suggest using the DrawToBitmap method in WinForms which will repaint the window into your own bitmap object:
using(Bitmap b = new Bitmap( this.Width, this.Height )) {
this.DrawToBitmap( b, new Rectangle( 0, 0, this.Width, this.Height ) );
// Use LockBits here to iterate through each pixel
}
I recommend against using GetPixel/SetPixel because they're very slow and inefficient for iterating through pixels in a bitmap; furthermore it's more efficient to make the outer-loop y instead of x to take advantage of your CPU's cache (as consecutive x values are closer in memory than consecutive yvalues).
I'm not sure I understand your question. But if you want to get at the pixels of a Control (and a form is just a control) you can use the Control.DrawToBitmap() method and then work with the resulting bitmap.
If you want to get at thing that are happening in a special Paint event you should look there, but the final result, after all Paint events have fired will be in the bitmap mentioned above.
If you actually have set a background image (do you?) then you could work with it directly..

Replace part of an image with another in C# with WinForms

I have a big .PNG that has many little images on it. I want to replace part of the big image with a smaller one. So at X and Y coordinates, that part of the image will be replaced starting from the top left hand corner, while still leaving the rest of the original image intact.
I have been reading about the Graphics methods on MSDN and also had a look for some examples of a similar thing but didn't find much.
Had anyone done anything similar?
Thanks!
I would suggest this approach. X and Y are the coordinates on the big image where you want to put the small one. You can check the DrawImage method overloads, there are 30 of them but I think this one best suites your case:
Bitmap bigBmp = new Bitmap("bigBmp.png");
Bitmap smallBmp = new Bitmap("smallBmp.png");
Graphics g = Graphics.FromImage(bigBmp);
Rectangle destRect = new Rectangle(x, y, smallBmp.Width, smallBmp.Height);
Rectangle sourceRect = new Rectangle(0, 0, smallBmp.Width, smallBmp.Height);
g.DrawImage(smallBmp, destRect, sourceRect, GraphicsUnit.Pixel);
g.Dispose();
EDIT: Based on the comment of KvanTTT, I have decided to add another solution to the question using DrawImageUnscaled because it is the fastest way to draw images. There are four overloads of this method, but this one is the simplest one that matches the question.
Bitmap bigBmp = new Bitmap("bigBmp.png");
Bitmap smallBmp = new Bitmap("smallBmp.png");
Graphics g = Graphics.FromImage(bigBmp);
g.DrawImageUnscaled(smallBmp, x, y);
g.Dispose();

Categories