Looking for more efficient software zoom - c#

I am using a C#, Winforms application with the Aforge library to pull video from a USB camera and manipulate that video.
I am doing it by using the new frame event handler and posting that image into a picturebox. So far, it has worked well and done what I want.
However, I recently found out I need to add software zoom to the application. My solution was to increase the size of the overall image and then grab a section of the new, larger image, that fit the measurements I needed. This is done on every new frame.
int imageTopY;
int imageTopX;
Rectangle rect;
bitmap = new Bitmap(bitmap, new Size(bitmap.Width * zoomTrackBar.Value,
bitmap.Height * zoomTrackBar.Value));
imageTopY = ((bitmap.Height - height) / 2);
imageTopX = ((bitmap.Width - width) / 2);
if (imageTopY != 0 && imageTopX != 0)
rect = new Rectangle(imageTopX, imageTopY, width, height);
else
rect = new Rectangle(0, 0, width, height);
bitmap = (Bitmap)bitmap.Clone(rect, bitmap.PixelFormat)
This also does what I need it to. HOWEVER, it is not at all efficient. When the zoome level hits 3, the video becomes exceptionally laggy. There is a latency of 1-2 seconds between the video feed and what is going on. I can get up and do a little dance, and by the time I sit down in my chair, the me in the video starts doing a little dance :-P
Any suggestions on a better way to achieve what I am trying to do? Maybe something more streamlined?

Instead of enlarging the overall image, cut out the section you wish you zoom in to and fill the window with that image. This way, you are always having a max image size of the video window and not enlarging the overall image beyond the window's constraints.

Related

How to set PictureBox.Image to *.jpg-File on Compact Framework?

I am trying to develop a photo slideshow on a panel pc with Windows CE. Each of the images I want to show in a PictureBox on my formular is of *.jpg-Type. Files are e.g. ~1MB big with a resolution of 2304x1728.
When I use following code, I get an OutOfMemory Exception.
Bitmap bitmap = new Bitmap(file_name)
PictureBox.Image = bitmap
After researching I found out that the *.jpg-Files might be "too big" to fit into Bitmap. With Compact Framework on VS2008 it is not possible for me to use something like
Image image1 = Image.From(file_name)
How can I get an image from jpg-Files to my PictureBox ?
EDIT[1]:
Thanks for your comments. I figured out that my pictures can not be loaded correctly because my device does not have enough memory to temporary load "huge" images. I solved the issue by writing some code that resizes my images before I copy them to my device.
Image bitmapNew = null;
using (Bitmap bitmap = (Bitmap)Image.FromFile(filename))
{
double proportion = (double) bitmap.Width / bitmap.Height;
proportion = Math.Round(proportion, 2);
if (proportion > 1)
{
iWidth = iWidthMax;
iHeight = (int)(iWidthMax / proportion);
}
else
{
iHeight = iHeightMax;
iWidth = (int) (iHeightMax * proportion);
}
bitmapNew = new Bitmap(bitmap, new Size(iWidth, iHeight));
}
The deviceĀ“s resolution defines the parameter iWidthMax & iHeightMax
The file size of a JPG or any other compressed image file type does not say how many pixels are stored (5, 10 or more megapixel). To show an image on screen, all pixels have to be loaded into memory. For larger images this is impossible, especially on Windows Mobile with it's 32MB process slot limitation.
And even if the whole image could be loaded it would not make sense, as the screen does not have that number of pixels and would just show only every 10th or 20th pixel.
The best approach is the load only what the screen and the memory can handle. The standard classes all are memory based and so you will reach the memory limit very early. But there is OpenNetCF which is able to 'scale' images on the fly using the file stream only.
I used that in https://github.com/hjgode/eMdiMail/blob/master/ImagePanel/ImageHelper.cs to get scaled images that make sense to load and show. Look at the code for getScaledBitmap() and CreateThumbnail(). These functions are part of a custom control in the code but can easily be used for other purposes.
The project was used to scan documents or business cards, show them as thumbs and zoomed and then eMail the scanned images to a document server.

How do I draw a pixel at a specific position on a window?

I need to create a program that will display lines or dots of coordinates read from a txt file. The application will be attached to the output of an eye-tracking program, and will display the data.
How do I display some sort of graphic at a particular coordinate on the screen?
Note: The window is full-screen, and I can use WPF or WinForms.
I would overlay your video with an Image element; something like:
<Grid>
<Image x:Name=TrackingImage />
<MediaElement/>
</Grid>
Then in your code behind; set the source to a WriteableBitmap. The documentation has an excellent sample, but to summarize it here:
WriteableBitmap writeableSource = new WriteableBitmap(100, 100, 96, 96, PixelFormats.Bgra32, null);
// Calculate the number of bytes per pixel.
int _bytesPerPixel = (writeableSource .Format.BitsPerPixel + 7) / 8;
// Stride is bytes per pixel times the number of pixels.
// Stride is the byte width of a single rectangle row.
int _stride = writeableSource .PixelWidth * _bytesPerPixel;
private void SomeUpdateFunction()
{
// Define the rectangle of the writeable image we will modify.
// The size is that of the writeable bitmap.
Int32Rect _rect = new Int32Rect(0, 0, _wb.PixelWidth, _wb.PixelHeight);
//Update writeable bitmap with the colorArray to the image.
_wb.WritePixels(_rect, pixelBuffer, _stride, 0);
TrackingImage.Source = writeableSource;
}
Note that it uses WritePixels (specifically; this overload: MSDN)
Obviously you will need to modify the parameters to get the correct pixel in the correct place. This is the right technique though.
This answer was inspired by: Drawing Pixels in WPF It might be worth looking at if you need more info.
Various bitmap formats are instructions to put colored dots at specific locations. Why not use something like that? What ELSE do you need it to do?
Regarding your eye-tracking and point-data comment, if you want to composite it with captured video, then you don't need to worry about how to display the images so much as you need to think about how to add the dots to the video itself. The video player will do the displaying.
From what I know about screen-capture and video codecs (not a whole lot) it will be best to work with the uncompressed video before it gets encoded. Otherwise you'll have to decode, add, and re-encode. I'd look for a way to hook into the capture program and add the live eye-tracker data to the captured frames.

Grid on top of image with editing ability

I'm hoping someone can give me some guidance here. I have been gogleing for a while now and I can't come up with anything that suits my needs. I'm a bit of a programmer but not a pro and I have no graphics experience. I am trying to develop a program for my wife to more easily transfer images to her needlepoint drawings. I want to write a C# application that will let me load an image of almost any type and overlay a "grid" on top of it. I want to also be able to implement simple "paint" operations like change the color of a grid square, color selector from the base image, bucket fill, etc. Any suggestions and examples would be greatly appreciated.
Thanks,
Tom
I've implemented something similar for my wife. My basic approach:
1) Scale the image down to the number of necessary pixels. For example, if she's stitching the image on a 10x10 13-mesh canvas, that equates to an image of 130x130 pixels.
Here's some example code to start you off:
// use NearestNeighbor algorithm
public static unsafe Bitmap Reduce(Bitmap source, SizeF toSize, int threadCount)
{
Bitmap reduced = new Bitmap((int)(toSize.Width * threadCount), (int)(toSize.Height * threadCount));
using (Graphics g = Graphics.FromImage(reduced))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(source, new Rectangle(Point.Empty, reduced.Size));
}
return reduced;
}
2) Display the pixelated image full screen. This will provide a grid-like effect.
3) Display a color palette from DMC's yarn code card, or taken from the image (after down-scaling). Then have the mouse cursor pick up a color by clicking on it, then applying it to the cell that it was subsequently clicked on.
Here's some code for picking up the mouse cursor:
public Point GetPicturePointAtClick()
{
Point p = Cursor.Position;
Point picturePoint = previewBox.PointToClient(p);
if (Zoom != 0)
{
picturePoint.X = (int)(picturePoint.X / Zoom);
picturePoint.Y = (int)(picturePoint.Y / Zoom);
}
return picturePoint;
}
The idea here is to map the clicked area to the correct pixel in the reduced image, math:
Point reducedPoint =
new Point(
(int)(picPoint.X * (_reduced.Width / (float)WorkingBitmap.Width)),
(int)(picPoint.Y * (_reduced.Height / (float)WorkingBitmap.Height)));
There's a lot of code ahead of you. Did you try an online custom needlepoint provider? Try one of these sites, they're both pretty good and customization is free:
http://www.needlepaint.com/
http://www.pepitaneedlepoint.com/

Get the width and height of an frame image bypassing all the center transparency

I have many images that contains only frames (styled borders) in PNG format.
All the center of the images are transparent.
I am looking for a way to detect the frame height and width without the transparency.
I tried some pixel by pixel in GDI+ C# to check but didn't manage to make it work correctly.
All this assuming that the top frame height and bottom frame height have the same height and the right frame width and left frame width have the same width.
the frames are linear and shouldn't have any special glitches, so if i detect the width of the right frame i should be the same of the left frame.
Hope anyone have any idea of how to achieve this.
Frame Example:
Frame example http://www.digitalimageautorotate.com/images/frame_demo.png
Usually when you work with images, you use .LockBits and pointers for speed, since you're typically accessing millions of pixels over and over again. (And if you're not doing it like that - you're probably neglecting it because you're not realizing how much overhead you get otherwise).
In this case however, you will access very few pixels, so .GetPixel should actually be perfectly in order.
public Size GetBorderSize(Bitmap bmp)
{
var hx = bmp.Width/2;
var hy = bmp.Height/2;
var sz = new Size();
while ( bmp.GetPixel(sz.Width, hy).A == 255 && sz.Width < hx)
sz.Width++;
while (bmp.GetPixel(hx, sz.Height).A == 255 && sz.Height < hy)
sz.Height++;
return sz;
}

Efficient Zoom At C#

To zoom images in and out, there is a possible way to resize the pictureBox and showing image in strechmode. Although I can not use it efficiently becauce in general over 8x it gives storage error [think that a pictureBox has the Size(32k, 32k) it needs over 1GB memory !
Is there a special method, or should I zoom only the seen part of the image by using ImageClone ?
Update:
Here is the project at first try to zoom at the project [impossible, storage error] than delete the 41. line in form.cs :
pictureBox1.Image = youPicture;
After deleting this line, the program will work, please move the zoomed image.
Here is the link: http://rapidshare.com/files/265835370/zoomMatrix.rar.html
By using the matrix object and the transform property of your graphics object:
using(Graphics g = this.CreateGraphics())
{
using(Bitmap youPicture = new Bitmap(yourPictureFile))
{
g.DrawImage(youPicture, 0, 0, 300, 100); //set the desired size
//Now you need to create a matrix object to apply transformation on your graphic
Matrix mat = new Matrix();
mat.Scale(1.5f, 1.5f, MatrixOrder.Append); //zoom to 150%
g.Transform = mat;
g.DrawImage(youPicture, new Rectangle(...), 0, 0, youPicture.Width,
youPicture.Height, GraphicsUnit.Pixel) ;
}
}
I personally would just zoom the visible part as the rest is hidden anyway (and thus no use)
See this answer to an earlier question. You definitely don't want to zoom by making the image huge and showing only part of it - you'll run into the memory problem that you've already encountered. Also, the stretch mode of a picture box doesn't use high-quality interpolation, so the result will look pretty crappy.
In the answer I linked here, I included a link to a C# project that shows you how to do this kind of zooming.
Update: here is a direct link to the downloadable project.

Categories

Resources