I want to create some heat-map style tiles to overlay over our base maps using Open Layers. Basically, I want to divide some some bounding box into a grid, and display each square of the grid using a different color based on how many points of a sample fall within that grid square.
The technologies involved are C#, OpenLayers, SQL Server 2008 and GeoServer.
My question is basically one of general approach, I'm not really sure where to put the tip of the chisel on this one.
My ultimate goal is to be able to take any arbitrary bounding box, calculate an x-mile by x-mile grid that fits within that bounding box, the iterate over a collection of individual points and assign them to one grid square or another so I can calculate point density per grid square, then color the grid according to the densities, then overlay that on a CloudMade base map using Open Layers.
Any help at all would be greatly appreciated, on the whole thing or any piece of it.
If your bounding box is axis aligned, this is fairly simple. Just make your image, and create a world file for it by hand. The world file is just 6 lines of text, and you already know everything needed (x & y pixel size, coordinate of your upper left corner).
Just make sure that you use the CENTER of the upper left corner pixel, not the corner of the box.
------ Here's how you'd make the world file -------
Say your bounding box's upper left corner is at 203732x598374, and you want an image that has rectangles that are 200m wide east<->west and 300m tall north<->south.
You'd make an image that was the appropriate number of pixels, then a world file that had the following 6 lines:
200
0
0
-300
203632
598524
This corresponds to:
200 == size of one pixel in X
0 == shear1
0 == shear2
-300 == size of one pixel in Y (from top down)
203632 == left edge - 1/2 pixel size (to center on pixel instead of edge of box)
598524 == top edge - 1/2 pixel size (to center on pixel instead of edge of box)
If you use a .png image, you'll want to save this with the same name, but as .pgw. If you use a .jpg, it'd be .jgw, etc.
For complete details, see:
Wiki on World Files
"Dividing some some bounding box into a grid, and displaying each square of the grid using a different color based on how many points of a sample fall within that grid square." This is a raster and there are features in GeoServer for displaying these with colour shading, legends and so on. I think it will be more flexible to use these features than to create image tiles in C#.
From the GeoServer documentation:
Raster data is not merely a picture,
rather it can be thought of as a grid
of georeferenced information, much
like a graphic is a grid of visual
information (with combination of reds,
greens, and blues). Unlike graphics,
which only contain visual data, each
point/pixel in a raster grid can have
lots of different attributes, with
possibly none of them having an
inherently visual component.
This is also called thematic mapping or contour plots or heatmaps or 2.5D plots in other GIS packages.
You could use a free GIS like Grass to create the raster grids, but from your description you don't need to interpolate (because every cell contains at least one point) so it might be just as easy to roll your own code.
EDIT: there is an open source library GDAL which you can use to write raster files in various formats. There are C# bindings.
I think the formulas for computing the center of the upper left pixel are wrong. In the example, the center of the upper left pixel would be down and to the right of (203732,598374). So shouldn't it be the following?
203832 == left edge + 1/2 pixel size (to center on pixel instead of edge of box)
598224 == top edge - 1/2 pixel size (to center on pixel instead of edge of box)
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 working to a software that need a strange feature. I choose a png image like image attached and I need to place uniformly a certain number of points on black surface. I started with loop each pixel and change it's color to black, only for design, but now I need to think an algorithm to fill it with points (like 200 points (pixels with red color). You have a idea how to do this ?
Now in my mind is to count black pixels, then do something like this blackPixelsPerPoint = blackPixels / numberOfPoints. After this I now i need to have a red point every blackPixelsPerPoint.
The result need to be something like N letter
The points need to have almost same space between them and fill all the black surface if is possible (depend by number of points).
I am creating a visualizer in WPF to display flowfield information for a game I am writing and have come across a problem with some labels being very close to each other.
In the above screen shot, sector (0,0) is the top left. In sector (1,1) I have highlighted two labels with arrows that are very close to each other. In sector (2,1) I have circled two labels that overlap completly. I need to be able to place labels in a way so that they do not overlap and have a margin of distance. I am after preferably a simple algorithm that allows me to place labels on a contended spot.
The blue/black cells are virtualized items on an Items Control with a canvas as the ItemsPanel. The red sector squares are on one adorner while the green lines, boxes, bezier curves and red cost labels are on a second adorner. Both adorners use the drawing context with everything dynamically created upon render.
var typeface = new Typeface(new FontFamily("Segoe UI"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
var formattedText = new FormattedText(curve.Cost.ToString(), CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeface, 12, Brushes.Red, null, TextFormattingMode.Display);
var textLocation = new Point(midPoint2.X - (formattedText.WidthIncludingTrailingWhitespace / 2), midPoint2.Y - formattedText.Height);
drawingContext.DrawText(formattedText, textLocation);
A suggestion:
The Voronoi diagram of a set of geometric entities is the partition of the plane into regions where points are closer to a given entity than to all others.
If you construct the Voronoi diagram of your curves, and if you place the labels wholly in the corresponding regions, this solves your problem.
Assuming that all labels have the same extent (same bounding box), you can find suitable empty spaces by applying an erosion operation, i.e. removing layers of pixels on the region outlines for the desired width/height. The remaining pixels are possible centers for the labels.
In the general case, computing a Voronoi diagram by geometric means is extremely difficult. But if you work with a digital image, it suffices to draw the geometric entities and compute the distance map from them.
This requires that you be somewhat familiar with the techniques of digital image processing.
After considering several ways to place labels includng
Word Clouds, physics based approaches, voronoi diagrams. I decided to base my approach on An Empirical Study of Algorithms
for Point-Feature Label Placement as I could see a simple and quick way to position labels. Page 2 gave me the idea of having four possible locations for a desired point and I built my own implementation with very simple rules.
I created a class called PointLabelPlacer with two methods
AddLabel
ComputeNewPositions
I would send all my labels along with the point to the AddLabel method.
Once I was done and ready I would call ComputeNewPositions. This would for all four possible locations count the number of locations from another labels that have overlapped.
I would also flag a location if it overlapped an original point of another label.
If two labels overlapped exactly, i would again choose the first one without overlaps, but I would mark all the other labels location as used
Then I would just choose the first one I found with the lowest number of overlaps and did not overlap another point and was not marked as used.
If after all that no alternate location could be found, I default to the top left and allow overlaps.
This is with the alternate locations displayed in yellow
This is the final result
I'm working on an experimental project in which the challenge is to identify and extract an image of the icon or control that the user is has clicked on/touched. The method I'm trying is as follows (I need some help with step 3):
1) Take a screen shot when the user clicks/touches the screen:
2) Apply edge detection:
3) Extract the possible icon images around the Point associated with the user's cursor (Don't know how to do this)
There are easier cases in which the mouse-over event will highlight the icon/control, which allows me to identify the control with a simple screen shot comparison (before and after mouse-over). The above method is specifically for cases in which the icon is not highlighted. I'm new to emgu, so if anyone has any pointers on how to better achieve this, I'm all ears.
Cheers! Matt
Instead of doing edge detection. Consider taking the following steps:
Only grab pixels which are within a certain radius of the point of the user's cursor. Create a new image with just these pixels.
Use thresholding to classify into foreground and background.
Calculate the centroid, (use mean x coordinate and mean y coordinate). Calculate deviation from the mean. Discard foreground pixels which are beyond a certain deviation from the mean. Eg: discard pixels that are more than 1.6 deviations from the mean.
(You may need to experiment with this step ).
Use a convex hull to find the area of the image with the icon in it.
I have to extract the red mark graph using Aforge blob extraction method but I am unable to extract that particular grid in order to read it.
This task may be pretty simply solved without further AForge using.
If all grids in your sample have a similar structure: i.e. homogeneous grid with vertical-horizonal graphic of function, you can use following algorithm:
Calculating white pixel density for vertical direction as you can see at image below. It's just a normalized value of sum of all RGB components in each horizontal line (Dont know what's name of it. If anybody knows it, please report).
You must extract y-axis values with lowest white pixel density and ignore y-axis values in green ellipses. If this minimums has not been founded, you must consider values in green ellipses too. If in considered y-axis values there are white pixels at right in image too many, just ignore it. Otherwise, congrats! We found segment of black line until right angle.
After that this process must be repeated for next horizontal line detection until end of image.
Construction of final function from founded horizontal lines.
If you want to just retain the graph in the grid and remove all other lines or line segments and if your image is a sample of all the images that you are planning to process, then I see two options to try out:
1) If there is a difference in greyscale threshold of area which is not having graph line to that of graph line, then use that and apply one of the Thresholding APIs of Aforge.Net, like IterativeThreshold.
2) You may try errosion API of AForge.Net and iterate that for N times, until all other lines are eroded except the graph line. If graph line becomes lighter due to erossion, apply Dillation on top of it.