I have an image (png) with resolution 1600*1200 (96 dpi).
I have put some text on the image and then saved it to a file for it to be loaded using silverlight's deepzoom with the pivotviewer. The text is blurry when zooming in and I was wondering how I can make the text look sharper (only if zooming in a bit).
This is my first bit of programming with images/graphics, so any info would be great (i.e. links to read, concepts to understand etc)
JD.
I've never used these controls before, but you might end up having to override the zooming algorithm (if that's even possible, I don't know). If you have text in an image and you're not using vector-based images (SVG, EMF, WMF, etc.), any sort of stretching is going to be blurry.
A different zooming algorithm, if it's a possibility, can decide how to stretch the pixels. For text, you're looking for something called "Nearest Neighbor" or maybe even "Bi-cubic" interpolation while the image is resizing. These methods are more expensive in terms of processing, so you might not get as smooth of a zoom as with the default interpolation algorithm (whatever it is).
There are some forum posts that start the same discussion, but with no real direction. Maybe you can follow them and see how they progress. I'm afraid I can't be of much help otherwise.
http://social.expression.microsoft.com/Forums/en-US/deepzoomcomposer/thread/dee528a2-06ae-4426-b096-5baafec499ff
http://weblogs.asp.net/bleroy/archive/2009/12/10/resizing-images-from-the-server-using-wpf-wic-instead-of-gdi.aspx
In the last post they refer to the different interpolation algorithms in a BitmapScalingMode enumeration. One of those options is NearestNeighbor. There are also some examples of resized images.
Update:
In this article, the author takes a look at a way to change the quality of the image tiles that the Deep Zoom control uses (and he's using Silverlight!). The author effectively changes the way images are created with a few lines of code in his project:
if (bSmoothScaling)
{
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
}
In that list of assignments you can find the interpolation mode I've been mentioning, as well as some other things I wasn't aware of. The author does mention a significant impact on performance with everything set to "High Quality."
Hopefully you can take the concept and incorporate it into Silverlight somehow. Good luck!
Related
Im trying to create a little game with C# and GDI+. For learning purposes I'm trying to avoid as much frameworks etc. as possible. So I have some specific questions to GDI+
Is it possible to fill a region object in GDI with an image?
-If not, is there a manual way for it?
Can you read and set single pixels in a graphics object (not a bitmap)?
Have you got any tips for me to increase overall performance in GDI?
Thanks for any help
Is it possible to fill a region object in GDI with an image?
A region can't be filled, it doesn't store pixels. What you are almost certainly looking for here is the Graphics.Clip property. Assign the region to it and draw the image, it will be clipped by the region.
Can you read and set single pixels in a graphics object (not a bitmap)?
No, the Graphics object doesn't store any pixels itself, it only keeps track of where you draw to. The "device context" in Windows speak. Which can be a bitmap, the screen, a printer, a metafile. Not all of these device contexts let you read a pixel back after drawing (not a printer and not a metafile for example). But no problem of course when you draw to a bitmap.
Have you got any tips for me to increase overall performance in GDI?
There is one crucial one, .NET makes it very easy to overlook. The pixel format of the bitmap you draw to is super-duper important. The most expensive thing you'll ever do with a bitmap is copying it, from CPU memory to the video-adapter's memory. That copy is only fast if the format of the pixels exactly match the format the video-adapter uses. On all modern machines that's PixelFormat.Format32bppPArgb. The difference is huge, it is ten times faster than all the other ones.
Many answers that will detail these points:
Once you have a Region it will limit where pixels are drawn. Use Graphics.DrawImage then
No way to read and only a perverted way to set a Pixel by Graphics.FillRectangle(br, x,y,1,1); The reason behind this is probably that Graphics can not only operate in a Pixel mode but also with various other Units from points to inches and mm..
Use Lockbits. Just one example using one Bitmap. Other common jobs demand locking two (one input one output) or or even three (two inputs and one calculated output) bitmaps..
Know what you invalidate, often only a small part really needs it..
Learn about ImageList, it can't do much but is useful for what it does, that is cache images of one size and color depth
Learn when to use a Panel and when a Picturebox
I'm trying to develop object detection algorithm. I plan to compare 2 image with different focus length. One image that correct focus on the object and one image that correct focus on background.
By reading about autofocus algorithm. I think it can done with contrast detection passive autofocus algorithm. It work on light intensity on the sensor.
But I don't sure that light intensity value from the image file has the same value as from the sensor. (it not a RAW image file. a jpeg image.) Is the light intensity value in jpeg image were the same as on the sensor? Can I use it to detect focus correctness with contrast detection? Is there a better way to detect which area of image were correct focus on the image?
I have tried to process the images a bit and I saw some progress. THis is what I did using opencv:
converted images to gray using cvtColor(I, Mgrey, CV_RGB2GRAY);
downsampled/decimated them a bit since they are huge (several Mb)
Took the sum of absolute horizontal and vertical gradients using http://docs.opencv.org/modules/imgproc/doc/filtering.html?highlight=sobel#cv.Sobel.
The result is below. The foreground when in focus does look brighter than background and vice versa.
You can probably try to match and subtract these images using translation from matchTemplate() on the original gray images; and then assemble pieces using the convex hull of the results as initialization mask for grab cut and plugging in color images. In case you aren’t familiar with the grab cut, chceck out my answer to this question.
But may be a simpler method will work here as well. You can try to apply a strong blur to your gradient images instead of precise matching and see what the difference give you in this case. The images below demonstrate the idea when I turned the difference in the binary masks.
It will be helpful to see your images. It I understood you correctly you try to separate background from foreground using focus (or blur) cue. Contrast in the image depends on focus but it also depend on the contrast of the target. So if the target is clouds you will never get sharp edges or high contrast. Finally jpeg image that use little compression should not affect the critical properties of your algorithm.
I would try to get a number of images at all possible focus lengths in a row and then build a graph of the contrast as a function of focal length (or even better focusing distance). The peak in this graph will give you the distance to the object regardless of object's own contrast. Note, however, that the accuracy of such visual cues goes down sharply with viewing distance.
This is what I expect you to obtain when measuring the sum of absolute gradient in a small window:
The next step for you will be to combine areas that are in focus with the areas that are solid color that is has no particular peak in the graph but none the less belong to the same object. Sometimes getting a convex hull of the focused areas can help to pinpoint the raw boundary of the object.
Question:
What is a fast way to scale and/or crop a bitmap provided from a WritableBitmap for display in the UI?
Requirements:
Have Low CPU usage
Handle large images (5 Megapixel, abt 2500x2000 pixels)
Resize and/or crop to the same resolution/area as the UI element the bitmap is displayed in.
Use WPF
Specifically, it must allow a 14FPS 5 Megapixel camera image stream to be displayed in a WPF UI element at full speed.
Update:
I have been able to speed up the drawing quite a bit by painting to a Canvas control using an ImageBrush as follows, where m_bitmap is my WriteableBitmap:
ImageBrush brush = new ImageBrush();
brush.ImageSource = m_bitmap;
brush.Stretch = Stretch.Uniform;
canvas.Background = brush;
I'm now able to get the full 14FPS, though it still using about 20% CPU, so I'm not sure how well it preform if I add another camera or two (the plan is to have 4 or so running).
Another thing I think might be slowing down the drawing is the images are in a mono, Gray8, format, not the standard RGB32 (or is it bgra32 for WPF?) format. If I understand correctly, the image has to be converted to the standard format to be displayed, which would add significant overhead to each frame's drawing time.
Some background:
I'm currently working with a 5 Megapixel, 14 FPS, video camera and am trying to get the frames to render to the screen at full speed. I would like to do this using WPF.
I currently have an example in WinForms that runs full speed for an unscaled image, but (as I would expect) it has major trouble if I set the pictureBox.SizeMode = Zoom;. The example reads raw data directly from the camera stream to a buffer and then copies the data from the buffer into the bitmap set to the PictureBox control. The copy algorithm uses LockBits to speed things up.
I converted that example into WPF, rewriting the parts using Bitmap objects to instead use WritableBitmap objects and an Image control instead of PictureBox. Unforunately this is not able to render the stream to the screen at any decent rate, scaled or unscaled. Both have significant CPU load and very slow updates.
The performance when rendering to the screen is turned off is great. It is able to process the image stream at full speed and resolution while using around 3% CPU and less than 100MB memory.
Note: when I say rendering to the screen is turned off, the WritableBitmap is still being continuously updated, only is not set to the Image control.
I've seen a lot of discussion about getting fast bitmap updating in WPF, but have been unsuccessful in getting it to work at an reasonable speed/cpu load. Also I would like to have the image scaled in such a way that I can see the whole image.
I imagine the key will lie in some sort of scaling/crop combination that needs to be done so that WPF will not try to render(cache?) all 5 million pixels, but only those on the screen, and only at the current screen resolution. I imagine/hope this can be done fairly easily and without too much hit to memory or CPU, but currently have no idea how to do so. I have found the DecodePixelWidth and DecodePixelHeight properties, but those are only applicable when loading an image from a file to a BitmapImage.
Did you have a look at the following post?
Resizing WritableBitmap
If it does not solve your problem, I have more questions for you:
What is the resolution of your image?
Is the size of you UI element constant? What's its size?
Edit:
After your edit, I noticed that you want to display a BitmapImage in Gray8 PixelFormat, why don't you try to set this property when creating your BitmapImage (m_bitmap)?
m_bitmap.Format = PixelFormat.Gray8; // could not test
I am certain that taking your 8 bits/pixel and multiplying the amount of bits needed per pixel by 4 while not gaining any quality is slowing down your application. Especially because you run operations on 32 bits per pixel images when you could be running those operations on 8 bits per pixel images.
While its interface is a bit old-fashioned, I believe that convert (see http://en.wikipedia.org/wiki/ImageMagick) is very often used (and may in fact be the industry standard).
Edit: StackOverflow has about 2,300 question tagged with imagemagick here. See for example What is the difference for sample/resample/scale/resize/adaptive-resize/thumbnail operators in ImageMagick convert?
The OP for https://apple.stackexchange.com/a/41531 decided to go with ImageMagick. And the accepted answer to Efficient JPEG Image Resizing in PHP also suggests ImageMagick, with 19 votes.
However, I don't know whether ImageMagick is capable of meeting your requirements of 14FPS, 5 Megapixels.
The only answer to Recommendation for real time image processing tools on Linux suggests a fork graphicsmagick, which seems to also be available for Windows.
I have an array of graphs, that are 2000x1000 pixels pngs. When I put them into a silverlight Image that auto-sized with the browser window, DisplayImage.Source = new BitmapImage(GetHeatmapURL()); they images look distorted and for some browser sizes much worse than for some others.
I want to fiddle with some setting that would improve the quality of this downsampling, is this possible? Am I doing something wrong? My first approach was to put the Image into a Viewbox. That looked even worse. Googling gives virtually nothing useful...
Any help much appreciated.
PS. I'm working with Silverlight 4.
You could check out the WriteableBitmapEx project on CodePlex which gives you a Resize() extension method for the Silverlight WritableBitmap class where you can use either Bilinear or Nearest Neighbor interpolation. Resizing with the Bilinear interpolation might give you something that looks better than the ViewBox resizing, but you would have to test it out.
var resized = writeableBmp.Resize(200, 300, WriteableBitmapExtensions.Interpolation.Bilinear);
When making use of the Viewbox you need to make sure to set Stretch to Uniform to respect the original height/width ratio.
In regards to the rendering of the image at the given aspect ratio and size; that is contingent on the framework.
I am creating a custom control using C# GDI+.
Quick explanation...the control will be say 500 pixels on screen but will contain perhaps 500000 pixels of information. So although i'm only showing 500px at a time i need to obviously scroll in the horizontal plane (left & right). The tricky part is that each 500px chunk of bitmap takes a while (between 100ms - 1000ms) to render.
So my plan is to maintain a 1500px bitmap in memory. i.e. the 500px visible part and 500px either side of the visible area and draw the off-screen parts asynchronously as the user scrolls.
I would like some feedback, advice, criticism or examples of code to help me achieve this. It seems fairly straight forward but after a few initial test attempts its proving more difficult than one would imagine.
Thanks.
The effectiveness of this approach depends on, amongst other things, the amount of moving around the user will do. If the user is making small movement, then stopping to consider the new information, this could work. However, if the user is whizzing back and forth, you'll still have an issue.
Does your application lend itself to gradually improving the quality of the image - i.e. providing a quick usable image and then improving it as the user stops to consider it?
I had a similar problem a few years back. As dommer mentions, if you're processing chunks of the image before displaying them you're best off showing something and improving it later. If you're having problems blitting the original image, you've got something wrong with your method. GDI+ is very particular about pixel depth (you want 32bpp with alpha).
In our case, we processed in 500px tiles and padded out a tile around the visible view Ff the user scrolled outside the area we'd processed we blitted bits of the original image with a dark semi-opaque rectangle super-imposed on them. These chunks were queued for processing. As we processed chunks of the image (centre-out) they semi-opaque rectangles would disappear.
It worked reasonably well, was very responsive and very fast. It's very fast to blit the original bitmap onto the screen, and in our case the processing was usually very close behind. The effect of the tiles getting lighter was actually quite pretty.
Draw only the visible area.
Build a method
Bitmap DrawGraph(leftMargin, rightMargin) {...}
and then in OnPaint() do
Bitmap bmp = new Bitmap(e.ClipRectangle.Width, e.ClipRectangle.Height);
bmp = DrawGraph(e.ClipRectangle.Left, e.ClipRectangle.Right);
e.Graphics.DrawImageUnscaled(bmp, e.ClipRectangle.Location);