watershed function provided by EmguCv - c#

I want to use watershed function provided by emgucv.I used the following code but all I get is a white picture.Please help me and correct this code.Thanks.
Image im;
Bitmap bm;
Bitmap bmF;
private void button1_Click(object sender, EventArgs e)//setting the background image
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
im = Image.FromFile(openFileDialog1.FileName);
bm = new Bitmap(im);
}
panel1.BackgroundImage = im;
panel1.Width = im.Width;
panel1.Height = im.Height;
panel1.Visible = true;
}
private void button2_Click(object sender, EventArgs e)
{
watershed(bm);
}
private void watershed(Bitmap bm)
{
Image<Bgr, Byte> imWa = new Image<Bgr, byte>(bm);
Image<Gray, Int32> imgr = new Image<Gray, int>(imWa.Width, imWa.Height);
Rectangle rec = imWa.ROI;
imgr.Draw(new CircleF(new PointF(rec.Left + rec.Width / 2.0f, rec.Top + rec.Height / 2.0f), (float)(Math.Min(imWa.Width, imWa.Height) / 4.0f)), new Gray(255), 0);
CvInvoke.cvWatershed(imWa, imgr);
bmF=new Bitmap(bm.Width,bm.Height);
bmF= imgr.ToBitmap();
panel1.BackgroundImage = (Image)bmF;
panel1.Invalidate();
}

You need to better prepare your mask file for the watershed (i.e. imgr).
For this purpose you need to set all to zero first. You can do that by calling:
CvInvoke.cvZero(imgr);
Then you should introduce at least a second "class". Hence you could draw a second circle with different coordinates (something belonging to the background). To be on the safe side use a different greyvalue for the first cirle (e.g. new Gray(100)) than for the second one (e.g. new Gray(200)).
You will get your result in your mask file imgr at the end, with the two classes showing in different greyvalues.
I am not really sure you need the ROI bit...

Instead of:
bmF= imgr.ToBitmap();
Try this:
bmF= imgr.Convert<Gray,byte>().ToBitmap();

Related

Using control functions in a bitmap in C#

I was thinking of implementing a bitmap into a picturebox (or the otherway round), such that I could have the option to:
1.drag and drop the item (Control function with mousebuttons)
2.rotate the item (bitmap function).
This is what I have currently:
Bitmap bmp = new Bitmap(#"my source");
PictureBox item = new System.Windows.Forms.PictureBox();
I create the picturebox on the click of a button:
private void button2_Click(object sender, EventArgs e)
{
item.BackColor = Color.Blue;
item.Location = new Point(400, 200);
item.MouseDown += new MouseEventHandler(textbox_MouseDown);
item.MouseMove += new MouseEventHandler(textbox_MouseMove);
item.MouseUp += new MouseEventHandler(textbox_MouseUp);
item.MouseWheel += new MouseEventHandler(textbox_MouseWheel);
item.Image = bmp;
item.SizeMode = PictureBoxSizeMode.StretchImage;
this.Controls.Add(item);
item.BringToFront();
}
and in the textbox_MouseMove void, I try to use the middle button to signal the rotation of the image
void textbox_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Middle )
{
if (activeControl == null || activeControl != sender)
{
return;
}
this.Paint += new PaintEventHandler(objectrotation_Paint);
Invalidate();
}
}
where the PaintEvent is responsible for the rotation of the image
private void objectrotation_Paint(object sender, PaintEventArgs d)
{
int dpi = 96;
bmp.SetResolution(dpi, dpi);
if (bmp != null)
{
float bw2 = bmp.Width / 2f;
float bh2 = bmp.Height / 2f;
d.Graphics.TranslateTransform(bw2, bh2);
d.Graphics.RotateTransform(angle);
d.Graphics.TranslateTransform(-bw2, -bh2);
d.Graphics.DrawImage(bmp,0,0);
d.Graphics.ResetTransform();
}
}
This however would create two sets of images, i.e. when I press button 2 I get one image, when I move my mouse with middle button down I get the second image (rotating).Refering to some of the questions on here, people recommend using
item.Image = bmp;
but it simply copies the from picturebox to the bitmap while they have seperate controls. While the picturebox class could not perform rotations without implementing a Bitmap, the Bitmap class does not have the option to perform actions like OnMouseMove etc.
Is there any way to combine my bitmap and the picturebox such that I could achieve my two goals?

print form on the full page instead of a part of it

i want to print my form on the whole page but instead the picture looks like this :
http://i.stack.imgur.com/JSXh2.jpg
it looks very small that's why i need the form to be printed on the whole full page
here is my code :
private void button5_Click(object sender, EventArgs e)
{
CaptureScreen();
printDocument1.Print();
}
private Bitmap _memoryImage;
private void CaptureScreen()
{
// put into using construct because Graphics objects do not
// get automatically disposed when leaving method scope
using (var myGraphics = CreateGraphics())
{
var s = Size;
_memoryImage = new Bitmap(s.Width, s.Height, myGraphics);
using (var memoryGraphics = Graphics.FromImage(_memoryImage))
{
memoryGraphics.CopyFromScreen(Location.X, Location.Y, 0, 0, s);
}
}
}
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
var wScale = e.MarginBounds.Width / (float)_memoryImage.Width;
var hScale = e.MarginBounds.Height / (float)_memoryImage.Height;
// choose the smaller of the two scales
var scale = wScale < hScale ? wScale : hScale;
// apply scaling to the image
e.Graphics.ScaleTransform(scale, scale);
// print to default printer's page
e.Graphics.DrawImage(_memoryImage, 0, 0);
}
your help would be appreciated
try this to make a bitmap of your form:
Bitmap bm = new Bitmap(f1.Width, f1.Height);
this.DrawToBitmap(bm, new Rectangle(f1.Location, f1.Size));
maybe that's the problem! Report back if it works!
If you want to print it in landscape format than you have to rotate your bitmap using:
public Bitmap rotateInternalFunction(Bitmap bitmap)
{
bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone);
return bitmap;
}

Paint with brush on existing image

I have embedded the code below in a project in which a want to paint with a brush OVER a picture. The problem is that if a write this code for a main panel , everything goes fine, but as I want to use it for an existing image, I can not see the brush. I suppose that the brush paints but it is a matter of foreground / background.
//the first line goes to the main form - under the initialize component
graphics = DisplayPicturebox.CreateGraphics();
bool draw = false;
Graphics graphics;
private void DisplayPicturebox_MouseDown(object sender, MouseEventArgs e)
{
draw = true;
}
private void DisplayPicturebox_MouseUp(object sender, MouseEventArgs e)
{
draw = false;
}
private void DisplayPicturebox_MouseMove(object sender, MouseEventArgs e)
{
if (draw)
{
//create a brush:
SolidBrush MysolidBrush = new SolidBrush(Color.Red);
graphics.FillEllipse(MysolidBrush, e.X, e.Y,
Convert.ToInt32(toolStripTextBox1.Text),
Convert.ToInt32(toolStripTextBox1.Text));
}
}
A few important things to note here:
Graphics need to be processed in a pipeline or saved in some way so that repaints don't eliminate the changes the user had made.
Keeping a graphics context open indefinitely is a bad idea. You should open the context log enough to draw what you need to either to a buffer or to the screen, then close that context.
If you want to use an offscreen buffer you need to keep in mind the coordinate system you are working in ("Screen" versus "control", versus "buffer"). If you get these confused you may not see what you expect
Those concepts in mind, you might consider the following changes to your code:
// at the beginning of your class declare an offscreen buffer
private System.Drawing.Bitmap buffer;
// .. later create it in the constructor
public Form1() {
InitializeComponent();
// use the w/h of the picture box here
buffer = new System.Drawing.Bitmap(picBox.Width, picBox.Height);
}
// in the designer add a paint event for the picture box:
private picBox_Paint(object sender, System.Windows.Forms.PaintEventArgs e) {
e.Graphics.DrawImageUnscaled(buffer);
}
// finally, your slightly modified painting routine...
private picBox__MouseMove(object sender, MouseEventArgs e)
{
if (draw)
{
using (var context = System.Drawing.Graphics.FromImage(buffer)) {
//create a brush:
SolidBrush MysolidBrush = new SolidBrush(Color.Red);
graphics.FillEllipse(MysolidBrush, e.X, e.Y,
Convert.ToInt32(toolStripTextBox1.Text),
Convert.ToInt32(toolStripTextBox1.Text));
}
}
}
This isn't meant to be perfect code but the general template should work and get you closer to what I think you are looking for. Hope that helps some!
Try this one, modify the mousemove event:
private void DisplayPicturebox_MouseMove(object sender, MouseEventArgs e)
{
if (draw)
{
graphics = DisplayPicturebox.CreateGraphics();
SolidBrush MysolidBrush = new SolidBrush(Color.Red);
float newX = (float)DisplayPicturebox.Image.Size.Width / (float)DisplayPicturebox.Size.Width;
float newY = (float)DisplayPicturebox.Image.Size.Height / (float)DisplayPicturebox.Size.Height;
graphics = Graphics.FromImage(DisplayPicturebox.Image);
graphics.FillEllipse(MysolidBrush, e.X * newX, e.Y * newY, Convert.ToInt32(toolStripTextBox1.Text), Convert.ToInt32(toolStripTextBox1.Text));
DisplayPicturebox.Refresh();
}
}

Trying to print form in C#

I've done some more work on printing forms in C# since my last question, I've got this code now:
public void printToolStripMenuItem_Click(object sender, EventArgs e)
{
Rectangle bounds = this.Bounds;
Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
Graphics g = Graphics.FromImage(bitmap);
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
PrintDocument doc = new PrintDocument();
doc.PrintPage += this.Doc_PrintPage;
PrintDialog dlgSettings = new PrintDialog();
dlgSettings.Document = doc;
if (dlgSettings.ShowDialog() == DialogResult.OK)
{
doc.Print();
}
}
private void Doc_PrintPage(object sender, PrintPageEventArgs e)
{
float x = e.MarginBounds.Left;
float y = e.MarginBounds.Top;
e.Graphics.DrawImage(bitmap);
}
Where printToolStripMenuItem_Click is the print button. I know I'm close because I saw the print dialogue before I edited the code to fit my needs. Right now, I'm getting an error that says "bitmap" in "e.Graphics.DrawImage(bitmap);" doesn't exist in context.
What can I change to make this print the image? I'm trying to print the image of the screen before I try creating the print document, because this seems easier, and just incase it works. I'm lazy sometimes :P
Note: This is all code inside my form2.cs file, the form I need to print.
Thanks :)
You're declaring bitmap in printToolStripMenuItem_Click but using it in Doc_PrintPage. You need to pass it some way. The easiest way would be to make it an instance variable (i.e. declare it in the class instead of the method, then assign it in printToolStripMenuItem_Click).
public class SomeForm
{
private Bitmap bitmap;
public void printToolStripMenuItem_Click(object sender, EventArgs e)
{
//...
bitmap = new Bitmap(bounds.Width, bounds.Height);
//...
}
}
You also are missing a parameter in the e.Graphics.DrawImage call. You need to specify where to draw the image. For instance, if you want it in the upper left corner do:
e.Graphics.DrawImage(bitmap, new Point(0,0));
You should use an anonymous method to create an event handler inside your function.
This way, it will still be able to read your local variables, through the magic of closures.
doc.PrintPage += (s, e) => {
float x = e.MarginBounds.Left;
float y = e.MarginBounds.Top;
e.Graphics.DrawImage(bitmap);
};

How to save a picturebox control as a jpeg file after it's edited

I have a PictureBox on my Windows Forms application.
I load a picture in it and I have enabled the Paint event in my code. It draws a rectangle.
Like this:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics gr = e.Graphics;
Pen p = new Pen(Color.Red);
p.Width = 5.0f;
gr.DrawRectangle(p, 1, 2, 30, 40);
}
And I click the "save" button:
private void button2_Click(object sender, EventArgs e)
{
pictureBox1.Image.Save(#"C:\Documents and Settings\tr1g3800\Desktop\WALKING\30P\100000test.jpg",ImageFormat.Jpeg);
}
But the saved file never contains the rectangle that I drew.
Does anyone have any idea?
Thanks.Your anwers all helped.
This worked
private void button1_Click(object sender, EventArgs e)
{
pictureBox1.ImageLocation=#"C:\Documents and Settings\tr1g3800\Desktop\WALKING\30P\100000.jpg" ;
}
private void button2_Click(object sender, EventArgs e)
{
pictureBox1.Image.Save(#"C:\Documents and Settings\tr1g3800\Desktop\WALKING\30P\100000test.jpg",ImageFormat.Jpeg);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
}
private void button3_Click(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap(pictureBox1.Image);
Graphics gr = Graphics.FromImage(bmp);
Pen p = new Pen(Color.Red);
p.Width = 5.0f;
gr.DrawRectangle(p, 1, 2, 30, 40);
pictureBox1.Image = bmp;
}
You probably shouldn't draw directly on the PictureBox.
You need to use a Bitmap instead. Try putting the bitmap in the PictureBox.Image and then call Save().
Check this for more details
Here is my solution with additional support to various file types:
public void ExportToBmp(string path)
{
using(var bitmap = new Bitmap(pictureBox.Width, pictureBox.Height))
{
pictureBox.DrawToBitmap(bitmap, pictureBox.ClientRectangle);
ImageFormat imageFormat = null;
var extension = Path.GetExtension(path);
switch (extension)
{
case ".bmp":
imageFormat = ImageFormat.Bmp;
break;
case ".png":
imageFormat = ImageFormat.Png;
break;
case ".jpeg":
case ".jpg":
imageFormat = ImageFormat.Jpeg;
break;
case ".gif":
imageFormat = ImageFormat.Gif;
break;
default:
throw new NotSupportedException("File extension is not supported");
}
bitmap.Save(path, imageFormat);
}
}
Here is a small example that clarified a few things for me (I was struggling with this a bit too).
pBox is a PictureBox on Form1, make it at least 50x50
appPath was derived from System.Reflection but use any path you like
There are two buttons, one for drawing, one for saving, their click events are in the code below.
Things I learned:
(1) "pBox.Image =" doesn't do anything but initialize the pBox image, it DOES NOT have to be a filename as EVERY example I found used (had problem saving to that same file because it was share locked). Also, if your goal is to see things on the entire control's surface, you'll probably like setting the size at initialize time to the size you need. I used the pBox's size in this example but normally I use the bitmap size (because I typically begin with a real picture file).
(2) I always had problems either seeing my draws show up on the control or seeing my changes saved in the output file (or both). In my prior attempts I would duplicate the draws both on the control and on the bitmap. Of course that isn't necessary but the edited bitmap DOES need to be reloaded into the control.image... and THAT was the piece of this puzzle I was missing.
(A) Create a bitmap from the control.image and draw on the bitmap
(B) Load the bitmap into the control.Image (so you can see the changes caused by the draw)
(C) Save the control.Image
(2-option) You have a global (or passed) bitmap (probably from a real file)
(A) Draw on the bitmap
(B) Load the bitmap into the control.Image (so you can see the changes)
(C) Save the bitmap
public Form1()
{
InitializeComponent();
pBox.Image = new Bitmap(pBox.Width, pBox.Height);
}
private void DrawStuff1_Click(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap(pBox.Image);
Graphics g = Graphics.FromImage(bmp);
g.FillRectangle(Brushes.Red, 5, 5, 25, 25); //hard-coded size to reduce clutter
pBox.Image = bmp; //this makes your changes visible
}
private void Save_Click(object sender, EventArgs e)
{
pBox.Image.Save(appPath + "SavedImage.bmp");
}
You need paint to image of picture, not to the Graphics control on Paint event.
EDIT:
using( Graphics g = Graphics.FromImage( pictureBox1.Image ) ) {
// there you will be do, what you do in Paint event
}
// ... somewhere else ...
pictureBox1.Save( _required_parameters_ );

Categories