This is a work project. I inherited some code using SharpDX (a DirectX layer). One of my tasks is to fix a piece of code where certain image effects are applying to a geometric shape containing a fill. If the filter is applied to the fill itself, it doesn't conform to the edges. I've figured out the code to pull out an excerpt using the Geometry of the object. For various reasons, they want to keep the fill that exists outside of the shape (namely, we have some distortion effects that pull in pixels outside of the shape), so I need to overlay it over the background. The problem I'm running into is that I'm getting this single-pixel border...
Applying the Soft Edge filter to the visible part
The background with the shape cut out
The two composited together in the program
What I'm actually getting
I can't share a good bit of the code, due to parts of it being proprietary, but the mask is a byte array. I'm building it using the following code:
SingleChannelBitmap mask = new SingleChannelBitmap(MaxRequiredPixels.Width, MaxRequiredPixels.Height, 255);
mask.FillShape(new RectangleF(new PointF(0,0), mask.Size), this.Geometry, 0);
255 is the maximum Alpha value (transparent). I invert it to take the slice out of the background. The only thing I can think of is that, when I do the masking, it's not including the outer edge of the Geometry. I'm going to try expanding the mask by one pixel in the crudest way possible (basically, scanning through and taking anything which is 0 transparency and adding a 0 transparency pixel to the left, right, up, and down), but I know there has to be a more elegant solution.
This has to work for the 3D Edge bevel filter as well, so doing an arbitrarily large whitespace probably won't work for me either.
What you describe is essentially the same haloing problem that sometimes occurs with displaying PNG images. The PNG export process from several programs will store a solid color for any portions of the PNG that has zero alpha, instead of the actual color at those pixels. This makes them function similar to other image formats (GIF) which use a specific color to encode transparent pixels. This significantly reduces the size of the file, however, can cause issues when sampling the image.
Your situation is similar. Although the masked pixels have zero alpha, when doing bilinear sampling, you may sample in between pixels, mixing both color and alpha values (unless pixel and texel centers are perfectly aligned). For example, if you have a 100% alpha, white pixel, next to a 0% alpha red pixel, and sample in between both, the result will be a pink pixel at 50% alpha.
There are several possible solutions:
You could extend the borders of the color layer, such that the 0% alpha border has the same color as its non-0% alpha adjacent pixels.
Intentionally line up the pixel and texel centers, although this can be tricky and/or not possible, depending on your requirements (mostly dependent on resolution).
Use 'nearest' sampling, instead of bilinear when displaying the image. This way, you will never blend in a 0% alpha pixel. However, this may also not be desirable, because your image will likely exhibit more aliasing effects.
Related
I do have different images which all have some kind of border around the "real" image. What I would like to achieve is to find the "real" image (size and location in pixels).
For me the challenge is that the border is not always black (can be any kind of black or grey with a lot of noise) and the "real" image (water with shark in this example) can have any combination of color, saturation, ...
Now in general I'm aware of algorithms like Canny, Blob detection, hough lines, ..., but I have just started using them. So far I managed to find the border for a specific image, but as soon as I try to apply the same algorithms and parameters to the next image it doesn't work. My current approach looks like this (pseudo code):
convert to gray CvInvoke.CvtColor(_processedImage, tempMat, CvEnum.ColorConversion.Rgb2Gray)
downsample with CvInvoke.PyrDown(srcImage, targetImage) and CvInvoke.PyrUp(srcImage, targetImage)
blur image with CvInvoke.GaussianBlur(_processedImage, bluredImage, New Drawing.Size(5, 5), 0)
Binarize with CvInvoke.Threshold(_processedImage, blackWhiteImage, _parameters.BinarizeThreshold, 255, CvEnum.ThresholdType.Binary)
Detect Edges with CvInvoke.Canny(_processedImage, imgEdges, 60, 100)
Find Contours with CvInvoke.FindContours(_processedImage, contours, Nothing, CvEnum.RetrType.External, CvEnum.ChainApproxMethod.ChainApproxSimple)
Assume that largest contour is the real image
I already tried different approaches based on for example:
Thresholding saturation channel and bounding box
Thresholding, canny edge and finding contours
Any hint especially on how to find proper parameters (that apply for all images) for algorithms like (adaptive) threshold and canny as well as ideas for improving the processing pipeline would be highly appreciated.
you can try to subtract black image from this image , and you will get the inside image , way to do this:
Use image subtraction to compare images in C# ,
If the border was uniform, this would be easy. Use cv::reduce to find MIN and MAX of each row and column; then count the top,left,bottom,right rows/columns whose MIN and MAX are equal (or very close) to the pixel value in a nearby corner. For sanity, maybe check the border colour is the same on all sides.
In your example the border contains faint red stuff, but a row/column approach might still be a useful way to simplify the problem. Maybe, as Nofar suggests, take an absolute difference with what you think is the background colour; square it, convert to grey, then reduce to Sums of rows and columns. You still need to find edges, but have reduced the data from two dimensions to one.
If there's a large border and lots of noise, maybe iterate: in the second pass, exclude the rows you think comprise the border, from statistics on columns (and vice versa).
EDIT: The above only works for an upright rectangle! If it could be rotated then the row/column projection method won't work. In that case I might go for sum-of-squared differences as above (don't start by converting to grey as it could throw away information), followed by blurring or some morphology, edge detection then some kind of Hough transform to find straight edges.
I'm writing an application for the windows store that uses Canny Edge Detection to find the borders of a document on an image. I need to be able to crop this image once the corners are found. I can use the WriteableBitmapExtension methods to crop a rectangle, but the problem is that it will rarely be a rectangle, but rather a quadrilateral.
I read about something called Aforge that may be able to do it, but it doesn't support Silverlight/WinRT it looks like. I know this should be possible with OpenGL, but it would most likely require I change a large portion of my application. Are there any alternatives?
You could implement it with WriteableBitmapEx using Blit and n alpha mask for the region you want to crop. Just create the mask dynamically with the result from the Canny edge detection. Make sure all pixels you want to keep have an alpha value of 255 and the ones you want to crop have an alpha value of 0 in the mask bitmap. Then use the Blit method on the original image, supply the generated alpha mask bitmap as parameter and the BlendMode.Alpha as well. This won't really reduce the size of the original image but at least the unwanted pixels are gone.
Before the alpha masking you could already crop rectangular using the min, max of x and y from your edge detection result. This way the size is also reduced and your alpha masking should be faster as a bonus.
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.
I have an image like below.
What I want is a monochrome image such that white parts are kept white, the rest is black. However, the tricky part is that I also want to reduce the white parts to be one pixel in thickness.
It's the second part that I'm stuck with.
My first thought was to do a simple threshold, then use a sort of "Game of Life" type iterative process where a white pixel was removed if it had neighbours on one side but not the other (i.e. it's an edge) however I have a feeling this would reduce ends of lines to nothing over time so I'd end up with a blank image.
What algorithm can I use to get the image I want, given the original image?
(My language of choice is C#, but anything is fine)
Original Image:
After detecting the morphological extended maxima of a given height:
and then thinning gives:
You can also manipulate the height parameter, or prune the thinned image.
Code in Mathematica:
img = ColorConvert[Import["http://i.stack.imgur.com/zPtl6.png"], "Grayscale"];
max = MaxDetect[img, .55]
Thinning[max]
EDIT I followed my own advice and a height of .4 gives segments which are more precisely localized:
I suggest that you look into Binary Morphological transformations such as Erosion and Dilation. Graphics libraries such as OpenCV() http://opencv.willowgarage.com/wiki/ and that statistical/matrix tool Gnu Octave http://octave.sourceforge.net/image/function/bwmorph.html support these operations.
I'm bored and I'd like to create my own color picket.
First I'd like to generate a color swatch. How would I create a color swatch?
This is a two part question.
How do I draw a single pixel point given an ARGB value.
What values existing in those ARGB values? What are my ranges?
Would looping and drawing these points be efficient? My intention is to create this image in memory, then cast it to a Drawing.Image class, then set it to a picturebox.
Thanks for the suggestions.
It's relatively simple, as long as you're smart about performance-related issues. Color pickers are one of my favorite wheels to re-implement when I'm bored or feeling creative.
You can draw a single pixel point given an ARGB value using the SetPixel method of the Bitmap class. Looping over each pixel of a new, appropriately-sized Bitmap object, and setting it to the appropriate color, is the easiest way to get this done. If you do this once when your color picker is opened, and cache the bitmap object in a class-level variable, repainting it onto the control when necessary instead of redrawing it each time, the performance is perfectly respectable.
Otherwise, SetPixel is about the slowest way of painting a bitmap imaginable. There are tricks to speed it up, like locking the bitmap and/or dropping into native code, but these don't make things any simpler. What will simplify your code drastically, and even provide a modest performance increase, is using a gradient brush for drawing purposes, instead. The Graphics class encapsulates the drawing functionality of GDI+ extremely well, and creating a LinearGradientBrush object to do your drawing
is quite straightforward.
As far as your second question, what are the ranges of the values you need to use, the first order of business is understanding the color models that you want to present on your color picker. The two choices that are probably most common and easy to work with are RGB and HSV (also known as HSB; HSL is something entirely different).
In the RGB color space, a single color is represented by its component values of red, green, and blue. The standard scale represents those values from 0 (minimum) to 255 (maximum). White is represented by (255, 255, 255), while black is represented as (0, 0, 0). Since this is the native color space for monitors, many graphics programs use it. Of course, it's not very intuitive to humans, who have difficulty figuring out exactly how to express, say, orange, purple, or brown in the RGB model.
Rather, the HSV model is much more intuitive, and generally the one you see used to draw fancy looking color grids/gradients. This is the model used (by default) on Photoshop's color picker, which is probably the most famous of all:
In HSV, a color is represented by three attribute values: hue, saturation, and value (or brightness).
Hue corresponds roughly to the degrees of a color circle, so it ranges from 0 to 360.
The saturation and value attributes are often thought of as percentages, ranging from 0 to 100 (although they can really be represented by any range of values).
Saturation describes the distance of the color from the center of the circle. Colors on the edge of the circle are fully saturated (100), while colors towards the center are unsaturated (white, or 0).
Value (or brightness) is intuitive. A fully bright color has the maximum value of 100, while a color lacking brightness has the minimum value of 0 (black).
Since this answer is getting long already, I'll refer you to a couple of sample implementations of color pickers already available on the Internet, instead of explaining the step-by-step here:
The ColorPicker.NET control is a very comprehensive offering, with a surprisingly thorough article
to accompany it.
A Primer on Building a Color Picker User Control with GDI+ in VB.NET or C# from the MSDN Magazine is the first color picker implementation I ever saw online, and though relatively simple by comparison, does an outstanding job of explaining the technical details. (I've taken many of the explanatory diagrams used in this answer from his article.)
I'd say get an image of the color pane you want, then detect where the mouse cursor is on the image. The pointer position is X and Y properties in MouseEventArgs. From those coordinates, calculate the color/transparency.
RGB range is 0-255 and A is 0-100
Hope this help