I am making some "statistical" Analysis over different Videos and Images. It´s Histogram-like over every Frame. In each Frame I take 16 prededefined Colors and rate them.
I am drawing Lines (up to down) into an Canvas where every Line can consist of that 16 colors in different intensities. For every Frame there is an new Line in the Canvas.
My Question:
1.) How can I draw Lines with different colors? So far I only came up that I draw an Part of the Line with an specified color then (if needed) draw again from the last point of that Line an new Subline with an new Color. So, in worst case I do that 16 times for one Line. How can I do that more easily?
2.) How can I apply some kind of "intensity" (brighter/darker) to that colors?
3.) Since it´s possible that I have to draw 100.000+ Lines for one Video, what can I do in order to speed up draw time and save memory? (well, at least I guess that that will take some time, I have no code so far and can only assume that...). Would it be an good approach to "precompute" every Line an save that somewhere and when it´s needed to pop it into the Canvas?
Html5 lines are drawn using path commands beginning with context.beginPath. You can draw multiple line segments with a single set of line path commands but each single set can only have one style (== one color). Your workaround (as you suspected) will be to issue a separate beginPath command for each desired colored line segment.
Html5 colors default to the RGBA color format, but you can also use the HSLA color format. This way you can change your "L" value to lighten or darken your hue. (The hue, "H", is basically your color).
Optimizing your line drawings is very dependent on the conditions in your own app. If the lines require significant processing to determine their position, color or other styling then you might (or might not) gain performance by pre-calculating those line values. On balance, canvas draws path commands (lines) very, very quickly so I would certainly start by test drawing your lines "live" to see if the canvas can keep up.
Good luck with your project!
Related
I'm looking for a way to create a svg like path from a binary image (only black and white pixels). The image itself will be a blob with irregular shape that could have holes in it.
Without holes I only need a bounding path the recreates the border of the blob. When there are holes in the blob, I'm fine with additional paths (as one path alone wont be able to recreate this, I guess). At the end I just need to know which path is the outer one and which are the holes.
I already found these:
How to add stroke/outline to transparent PNG image in JavaScript canvas
Creating a path from the edge of an image
How can I find hole in a 2D matrix?
Additionally I need the detection of holes. It doesn't really matter to me if the result is a polygon or a path. I just need the points with high enough accuracy that curves keep being curvy :)
It would be great if someone has an idea or even some further sources.
PS: I'm working with canvas and javascript (fabricJS) if this makes any difference.
Finally I successfully went with the other option as markE described (although it's a bit modified). I'm using the Marching Squares Algorithm (MSA) and the Floodfill Algorithm (FFA) to achieve this. Simplifying the resulting points is done via Douglas-Peucker Algorithm (DPA).
MAA: https://stackoverflow.com/a/25875512/2577116
FFA: http://www.williammalone.com/articles/html5-canvas-javascript-paint-bucket-tool/
DPA: https://stackoverflow.com/a/22516982/2577116
(Smoothing: https://stackoverflow.com/a/7058606/2577116)
I put everything together in this jsFiddle.
Steps:
get path object after user finished free drawing
create image from path via base64 dataURL
convert to binary image (only 0 and 255 pixel, no transparency)
apply FFA on position 0,0 with random color, save color
go to next pixel
if pixel has known floodfill color or path color (black), move on to next
otherwise floodfill with new random color, save color
move over all pixels, repeating 5.-7.
remove saved color on index 1 (it's the color surrounding the path contour (padding), so it's neither the path nor a hole)
for all other colors apply MSA and simplify resulting points (with DPA)
Either create polygons from simplified points OR ...
... smooth points and create path
add to canvas, remove input path
DONE :)
For simpler code my random color at the moment only creates shades of grey. R=G=B and A=255 allows for simpler checks. On the other hand this solution limits the contour to have max. 254 holes (256 shades of grey - path color (0) - padding color (no hole)). If one needs more it's no problem to extend the code to create random values for R, G, B and even A. Don't forget to adopt the color checks accordingly ;)
The whole algorithm may not be optimized for performance but honestly I see no need to do so at the moment. It's fast enough for my use-case. Anyway, if someone has a hint regarding optimization I'm glad to hear/read about :)
Best Option
If you drew the Blobs with your code, then the simplest & best way is to decompose each blob (and sub-blob) into it's component Bezier curves. FabricJS is open source so you can see how they create the curves -- and therefore how you can decompose the curves. The result will be a dozen or so Bezier curves that are easy to redraw or navigate. If you need help navigating Bezier Curves, see this tutorial covering Navigating along a Path.
Other Option
You will need to get the pixel information, so you will need to context.drawImage your Fabric Blob onto a native canvas and use context.getImagedata to fetch the pixel information.
Assuming:
All pixels are either white or black.
The blob is black: rgba(0,0,0,255)
Outside the blob is white: rgba(255,255,255,255)
The holes in the blob are white: rgba(255,255,255,255)
A plan to find the blob & hole paths:
Load the imageData: context.getImageData(0,0,canvas.width,canvas.height)
Find a white pixel on the perimeter of the image.
Use a FloodFill Algorithm (FFA) to replace the outer white with transparency.
Use the Marching Squares Algorithm (MSA) find the outermost blob perimeter and save that blob path.
Use a Floodfill Algorithm to fill the blob you've discovered in #4 with transparency. This makes the outer blob "invisible" to the next round of MSA. At this point you only have white holes -- everything else is transparent.
Use the Marching Squares Algorithm (MSA) find the perimeter of the next white hole and save that hole path.
Use a Floodfill algorithm to fill the white hole in #6 with transparency. This makes this hole invisible to the next round of MSA.
Repeat #6 & #7 to find each remaining white hole.
If MSA reports no pixels you're done.
For efficiency, you can repeatedly use the imageData from Step#1 in the subsequent steps. You can abandon the imageData when you have completed all the steps.
Since blobs are curves, you will find your blob paths contain many points. You might use a path point reduction algorithm to simplify those many points into fewer points.
I'm creating a planning tool for a game. Imagine two 2D static gun emplacements with different ranges and damage per second. I want to draw these ranges with different colours according to damage, in a scale similar to this http://www.celtrio.com/support/documentation/coverazone/2.1.0/ui.viewmode.heatmapcolorscale.html
I got that part working with CSS border radiuses. My problem is that if ranges overlap, the overlapping area doesn't show the combined damage.
I found heatmap.js http://www.patrick-wied.at/static/heatmapjs/ but it doesn't allow you to set a different radius for each point. I also can't find a way to turn off the gradient... the damage of these guns at its maximum range is the same at its minimum range. I realise that's sort of the point of a heatmap normally haha but I'm not too sure what I should be googling.
I had a think about a PHP solution which would create a greyscale image using varying levels of opacity to represent different damage. I'd then loop through all the pixels and recolour them according to the scale. But that would be far too slow. It needs to update in as close to realtime as possible as the user drags the guns around the screen.
There's probably a very simple way to do this, a CSS filter maybe, but I can't find anything. Any ideas? Thanks!
CSS is the wrong tool for this job -- you really ought to be doing stuff like this using SVG or Canvas. It'll be a lot easier to achieve complex graphical effects using a proper graphics system than trying to hack it with shapes created in CSS.
For example, in SVG, you would simply need to use the fill feature to fill each area with whatever colour you wanted. See an example SVG image here. It's an SVG Venn diagram where the overlap areas are completely different colours to the parent circles. Canvas has similar functionality.
You might also want to consider using a Javascript library such as RaphaelJS or PaperJS to help you with this. (using Canvas would imply that you're using some Javascript anyway, and it will make SVG easier to work with too).
However if you must do it using CSS, if you want elements to show through so the colours are merged when they overlay each other, then you'll want to use some sort of opacity effect.
Either opacity:0.5 or an rgba colour for the background.
That's as good as you'll get with CSS; you won't be able to get arbitrary colours in the overlap portions; just a combination of colours from the layered opacity effects.
If you look at the code of heatmap.js, you'll see that it works like this:
Paint circles onto a canvas, using a radial gradient from transparent to some percent opaque (depending on the strength of the point).
Color-map that grayscale image (converting each gray value to one of an array of 256 colors).
Your problem could be solved in the same way, but painting a circle of constant opacity and variable radius in step 1.
I have a large number of rectangles, and some overlap others; each rectangle has an absolute z-order and a colour. (Each 'rectangle' is actually the axis-aligned bounding box of a particle effect, mesh or texture and may be semi-transparent. But its easier to think abstractly about coloured rectangles as long as you don't try to cull rectangles behind others, so I will use that in the problem description:)
The cost of changing the 'colour' is quite high; its much faster to draw two blue rectangles in succession than it is to draw two different-coloured rectangles.
The cost of drawing rectangles that are not even on the screen is quite high too and should be avoided.
If two rectangles do not overlap, the order they are drawn relative to one-another is not important. Its only if they overlap that the z-order is important.
For example:
1 (red) and 4 (red) can be drawn together. 2 (blue) and 5 (blue) can also be drawn together, as can 3 (green) and 7 (green). But 8 (red) must be drawn after 6 (blue). so its either we draw all three red together and draw the blue in two sets, or we draw all the blue together and draw the red in two sets.
And some of the rectangles may move occasionally. (Not all of them; some rectangles are known to be static; others are known to move.)
I will be drawing this scene in JavaScript/webGL.
How can I draw the rectangles in a reasonable order to minimize colour changes, with a good trade-off of JavaScript culling code vs letting the GPU cull?
(Just working out which rectangles overlap and which are visible is expensive. I have a basic quadtree and this sped my scene drawing up immensely (compared to just emitting the draw-ops for the whole scene); now the question is how to minimize OpenGL state changes and concatenate attribute arrays as much as possible)
UPDATE I have created a very simple test app to illustrate the problem and serve as a basis for demonstration of solutions: http://williame.github.com/opt_rects/
The source-code is on github and can easily be forked: https://github.com/williame/opt_rects
It turns out its hard to make a little test app with sufficient state change to actually recreate the problem I see in my full game. At some point you'll have to take it as a given that state changes can be sufficiently expensive. What is also important is how to speed up the spatial index (quadtree in demo) and the overall approach.
You are making the very wrong assumption that the performance you will be getting on the desktop browser will somehow determine the performance on your iPhone. You need to understand that the iPhone hardware implements tile-based deferred rendering which means that the fragment shader is used very late in the pipeline anyway. As Apple themselves say (“Do not waste CPU time sorting objects front to back”), Z-sorting your primitives will get you little performance gain.
But here’s my suggestion: if changing the colour is expensive, just don’t change the colour: pass it as a vertex attribute, and merge the behaviours into one super shader so you can draw everything in one or a few batches without even sorting. Then benchmark and determine the optimal batch size for your platform.
Choose colours, not boxes!
At any point in time, one or more boxes will be paintable, i.e. they are able to be painted next without introducing problems (though possibly introducing a cost due to having a different colour from the most recently painted box).
The question at every point is: What colour should we pick to draw next? It's not necessary to think about picking individual paintable boxes to draw, because as soon as you pick a particular box to draw next, you might as well draw all available boxes of the same colour that can be drawn at that time. That's because painting a box never adds constraints to the problem, it only removes them; and choosing not to paint a paintable box when you could do so without changing the current colour cannot make the solution less expensive than it would otherwise be, since you will later have to paint this box and that may require a colour change. This also means it doesn't matter in which order we paint paintable boxes of the same colour, since we will paint all of them at once in a single "block" of box painting operations.
The dependency graph
Start by building a "lies underneath" dependency graph, where each coloured rectangle is represented by a vertex and there is an arc (arrow) from v to u if rectangle v overlaps rectangle u and lies underneath it. My first thought was to use this to build a "must be drawn before" dependency graph by finding the transitive closure, but actually we don't need to do this, since all the algorithms below care about is whether a vertex is paintable or not. Paintable vertices are the vertices that have no predecessors (in-arcs), and taking the transitive closure does not alter whether a vertex has 0 in-arcs or not.
In addition, whenever a box of a given colour has only boxes of the same colour as its ancestors, it will be painted in the same "block" -- since all those ancestors can be painted before it without changing colours.
A speedup
To cut down on computation, notice that whenever all paintable boxes of some particular colour have no different-coloured descendants, painting this colour won't open up any new opportunities for other boxes to become paintable, so we don't need to consider this colour when considering which colour to paint next -- we can always leave it till later with no risk of increasing the cost. In fact it's better to leave painting this colour till later, since by that time other boxes of this colour may have become paintable. Call a colour helpful if there is at least one paintable box of that colour that has a different-coloured descendant. When we get to the point when there are no helpful colours remaining (i.e. when all remaining boxes overlap only boxes of the same colour, or no boxes at all) then we are done: just paint the boxes of each remaining colour, picking colours in any order.
Algorithms
These observations suggest two possible algorithms:
A fast but possibly suboptimal greedy algorithm: Choose to paint next the colour that produces the most new paintable vertices. (This will automatically consider only helpful colours.)
A slower, exact DP or recursive algorithm: For each possible helpful colour c, consider the dependency graph produced by painting all paintable c-coloured boxes next:
Let f(g) be the minimum number of colour-changes required to paint all boxes in the dependency graph g. Then
f(g) = 1 + min(f(p(c, g)))
for all helpful colours c, where p(c, g) is the dependency graph produced by painting all paintable boxes of colour c. If G is the dependency graph for the original problem, then f(G) will be the minimum number of changes. The colour choices themselves can be reconstructed by tracing backwards through the DP cost matrix.
f(g) can be memoised to create a dynamic programming algorithm that saves time whenever 2 different permutations of colour choices produce the same graph, which will happen often. But it might be that even after DP, this algorithm could take an amount of time (and therefore space) that is exponential in the number of boxes... I will have a think about whether a nicer bound can be found.
Here's a possibility. You'll have to benchmark it to see if it's actually an improvement.
For all rectangles, back to front:
If this rectangle has been marked as drawn, skip to the next one
Set a screen-sized unseen surface to all black
Call this rectangle's color "the color"
For rectangles starting with this one and proceeding toward the front
If (this rectangle's color is the color and
all the pixels of this rectangle on the unseen are black) then
Add this rectangle to the to-draw list
Draw a white rectangle with this rectangle's shape on the unseen surface
If the unseen surface is more than half white, break
For all rectangles on the to-draw list:
Draw the rectangle
Mark it as drawn
It's not guaranteed to be the most optimal in terms of ordering, but I think it will come pretty close, and it's worst-case quadratic in the pre-drawing step. It does depend on readbacks from the graphics buffer being fast. One trick that might help there is to create a new one pixel surface that is a shrunken version of the area of interest. Its color will be the fraction of the original that was white.
Start by drawing in a random (but correct) order, for example in strict z order. When drawing each frame, either count the number of color changes, or possibly the actual time a complete frame takes. Each frame, try swapping the order of two rectangles. The rectangles to be swapped must not overlap, therefore they can be drawn in any order without violating correctness; aside from that they can be chosen at random, or do a linear pass through the list, or... If doing the swap reduces the number of color changes, keep the new order, if not revert it and try a different swap in the next frame. If doing the swap neither reduces nor increases the number of color changes, keep it with 50% odds. For any rectangles which did not overlap in a previous frame but which start overlapping due to a move, simply exchange them so they are in z order.
This has some relationship to sorting algorithms which swap pairs of items, except that we cannot compare items, we need to go through the whole list and count color changes. This will perform very badly at first but converge to a good order relatively quick, and will adapt to scene changes. I think it is probably not worth it to go through and calculate an optimum order every frame; this will get to, and maintain, a near-optimum order with very little extra work.
Referring to the drawing you have: Initial draw order picked at random: 1,6,2,4,5,8,3,7 (5 color changes). Swap 5,8. New order: 1,6,2,4,8,5,3,7 (4 color changes) => Keep new order.
So I’m trying to draw a simple hue wheel showing the red, green, and blue components and how they relate. The problem is that my (simple, one-degree) arcs are taking on the strokes of later arcs, even though I’m using beginPath() and closePath().
My current progress is at http://meyerweb.com/eric/css/colors/hsl-from-rgb.html. The innermost ring is what’s intended for that ring, with the blue-fade-to-black. The next ring out should show only green-fade-to-black, and the third ring out should have only red-fade-to-black. The outermost, thickest ring is meant to show the full spectrum around the hue wheel, which you can kind of see in the thin spokes (as you can in the other rings).
If I reverse the order of the drawing blocks, then the outermost ring is fine and all the inner rings are messed up, so clearly the stroke styles are leaking forward. I just can’t figure out how or why, nor how to overcome the problem. Should I just define four separate objects (say, ctx1 through ctx4) and draw to each one separately?
I looked at different fillStyle colors for arc in canvas but the recommendations there didn’t seem to help me. Other Googling produced nothing of use.
You can't use decimals for your RGB values, you need to round them.
http://jsfiddle.net/M6KbD/
I didn't take a very long look at your code but the problem is probably not with canvas, its probably the order in which you're drawing everything.
There are 4 sets you've got, right? You are drawing 1 from the first set, 1 from the second, 1 from the third, 1 from the fourth, then another 1 from the first...
If you change the order everything will be fine:
http://jsfiddle.net/muatT/
(lazily, I just copied the entire for-loop cruft as it was. You can probably simplify that code a lot)
I googled it but didn't find a good answer. Specifically, I want to learn:
to slice an image into curved pieces
to create individual objects from those pieces (i assume that i need
this to reassemble)
thanks.
There are several pieces to this puzzle. :)
The first piece is SVG and its Canvas. That's what you'll need to draw, because otherwise you can't make a curved piece out of a picture. Only rectangles are possible with standard HTML/CSS.
The second piece is an algorithm for generating jigsaw pieces from the picture. Google should help you with that if you can't figure one out by yourself (though it doesn't seem very complicated).
The rest should be straightforward.
Added: A quick Google search gave just such a jigsaw engine in the first result. Check out the source of that.
I'll assume the image you want to saw to pieces is a raster image with a resolution that you will use for the puzzle pieces, call that /picture/. Also, I assume you have the edges along which you wish to saw in a second raster image with the same dimensions, call that /raster/. Then your problem amounts to determining all connected areas in the raster. Each pixel of the raster gets annotated with the id of the jigsaw piece it belongs to, initially 'none', -1 or whatever. Then your algorithm scans across all pixels in the raster, skipping pixels that already belong to a piece. For each unassigned piece it executes a flood fill, "coloring" the pixels with the pieces id (e.g. number). In a second scan, after allocating an image for each piece, you add the corresponding pixels of the image to the piece. As part of your first pass you can maintain for each piece id the bounding box. That allows you to allocate the the images for the pieces to their proper dimensions.
You need a suitable convention to deal with border pixels: e.g. border pixels to the right belong to the piece if they have the same x-position, but are above they also belong to the piece.