A digital shape is a set of connected pixels in a binary image (a blob).
It can be compactly represented by run-length coding, i.e. grouping the pixels in horizontal line segments and storing the starting endpoint coordinates and the lengths. Usually, the RLC representation stores the runs in raster order, i.e. row by row and let to right.
For smooth shapes, the storage requirement drops from O(N²) to O(N).
The outline of a shape is a closed chain of pixels which restores the shape when its interior is filled (by a flood filling algorithm). It is also an O(N) representation. Wen the shape is available as a bitmap, the outline can be obtained by a contouring algorithm.
I am looking for an algorithm that directly computes the outline of a shape given its RLC representation, without drawing it in an intermediate bitmap. The algorithm is expected to run in time linear in the number of runs.
Have you come across a solution ?
A pixel is a boundary pixel if it is filled but adjacent to a pixel that is not filled. Given a per-row RLE encoding of the filled pixels, we can operate on three adjacent rows to compute a RLE version of the boundary pixels, then decode it.
Basically, we have a sweep line algorithm. With three rows like
*********** ****
************************
**** ******
we get event points (^) from the RLE:
*********** ****
************************
**** ******
^ ^^ ^ ^ ^ ^^ ^
The first thing to do is to designate middle filled pixels that have empty pixels above or below as boundary. (If you need guidance, the algorithms for set difference on a list of intervals are very similar.)
*********** ****
BBB***BBBBBBBBBBB***BBBB
**** ******
Then, for the intervals that are filled but not known to be boundaries, check whether left endpoint has space to the left and whether the right endpoint has space to the right. If so (respectively), they're boundaries.
Note: This answer assumes that "non-outline" means "surrounded by 4 neighbours", so the result will be slightly different to your example (1 pixel green instead of blue).
All outline pixels are pixels where not all of the 4 "neighbour pixels" (left, right, above, below of the pixel) are set.
When decoding the RLC from top to bottom, you can get the outline pixels with the following pseudo code algorithm:
For the first line
All decoded pixels are outline pixels
For the subsequent lines
Leftmost and rightmost pixels of each RLC run are outline pixels
All other pixels are outline pixels if:
The pixel above isn't set (case A)
The pixel below isn't set (case B)
Case A and B mean that you'll have to look at pixels above/below the current pixel, so the algorithm should actually be kind of pipelined/looking ahead one line, because case B will not be able to be detected until the next line was decoded.
EDIT: To sort the pixels in clockwise order afterwards, you can use the fact that your outline is a diagonally connected one-pixel-width line. Picking one of the pixels in the topmost line, you'll have two possible next pixels, follow the one that is right of, below or right and below the current pixel. After that, just follow the neighbour pixels that you haven't visited yet until there is no neighbour pixel. Example:
/----- First pixel you pick, A and B are neighbour candidates, A is the "correct" one
v
xAxxx
B x
x x xxx
x xxxxxx x
xx x
xxxxxxxxxxx
s0123 Result after following the neighbours (s = start, e = end),
e 4 numbers from 0-9 show order of traversal
1 5 234
0 678901 5
98 6
76543210987
Hint:
As said in other answers, emitting the list of the outline pixels can be implemented as a sweepline process, during which the 3x3 neighborhoods of the run endpoints are examined.
This procedure will emit the pixels in a scrambled way, as a sequence of direct and reverse arcs that need to be stored and reordered.
An alternative could be based on the idea of implementing the standard Moore Neighborhood algorithm that has the advantage to enumerate the outline pixels in the desired order.
This procedure requires to know the 8-neighborhood configuration around the current pixel, and the idea is to update this neighborhood on every move to another pixel: we maintain indexes to the run that contains the current pixel and to the two facing runs in the rows above and below.
On every move to another pixel, we need to update these three indexes, which will involve short sequential searches in the list of sorted runs. This can be seen as a pseudo-random access mechanism to pixels, taking into account that the successive accesses are strongly local and can be sort-of cached.
Update:
In the run-length-coded representation that I use, only the black runs are coded, as triples (X, Y, L). The runs are sorted by rows top to bottom, and then left to right in a row.
For convenience, we can switch to a "linear adressing" scheme, as if all image rows had been appended after each other, and every pixel is designated by a single number Z = X + Y.Nx (where Nx is the image width).
So we have a list of black runs, and the white runs are implicitly found between two consecutive black ones.
During processing, we can remember at all times the index of the run that starts immediately before or on the current pixel (R[I].Z <= Z < R[I+1].Z). We can tell the color of the pixel by checking if we are inside the run or between it and the next (Z < R[I].Z + R[I].L).
If we move one position to the left, Z decreases by 1 and we may have to select the previous run (I--).
If we move one position up, Z decreases by Nx and we may have to backtrack by several runs (I-- until R[I].Z <= Z again).
The picture shows the current pixel and its 4-neighbors, as well as the"influence zones" of the black runs.
We can handle all eight displacement directions similarly.
As we see, every move takes a number of operations at worse equal to the number of runs in a row, deemed to be a small value. Using this concept, we can traverse the RLC representation following an arbitrary path at a reasonable cost, without reconstructing the whole bitmap.
As the Moore Neighborhood algorithm takes time linear in the length of the outline, an implementation based on this linear run addressing will also take linear time (for a bounded number of runs per row).
Related
Given a 2D pixel array where any pixel can be either 0 or 1, what algorithm would output a new 2D pixel array, where each pixel with a value of 1 would get a new value based on the minimum amount of line segments required to reach a specific "light source" pixel, while only crossing pixels that have an input value of 1? Input values of 0 would not change.
Example of input array, magenta cross represents the "light source" pixel:
https://cdn3.imggmi.com/uploads/2019/1/8/2a5f6dd0ebdc9c72115f9ce93af3337a-full.png
Output array with output values 1 and 2 (Photoshopped, not a pixel perfect image):
https://cdn3.imggmi.com/uploads/2019/1/8/0025709aaa826c26ee0a8e17476419cb-full.png
Red region = 1 line segment away from source
Yellow region = 2 line segments away from source
White region = 3 or more line segments away from source
(The algorithm wouldn't stop at 3, it would continue until every pixel is evaluated.)
EDIT: I'm not sure whether StackOverflow is the right Stack Exchange site to post this in, if not please let me know!
Make your point of origin the origin of a polar coordinate system. Convert the block corners to polar coordinates.
Now, treat your point source as a searchlight, sweeping from 0 to 2*PI. The beam continues until it hits the frame edge or a black box. This defines a polygon that you fill with magenta (1 line segment, direct lighting).
That's the easy part. Now you get to repeat this for every pixel that lies on a magenta-white (1-0) boundary of the polygon. This defines a finite set of secondary polygons; fill those with yellow (code 2).
Repeat this process with the yellow-white (2-0) boundaries to identify the 3 pixels; iterate until you run out of pixels.
In other paradigms, I've applied interval algebra to blocking segments (e.g. where one block partially shadows another), but I think that the polar polygon attack will get you to a solution in fewer hours of coding.
By "Group", I mean a set of pixels such that every pixel at least have one adjacent pixel in the same set, the drawing shows an example of a group.
I would like to find the pixel which is having the greatest straight line distance from a designated pixel (for example, the green pixel). And the straight line connecting the two pixels (the red line) must not leave the group.
My solution is looping through the degrees and simulating the progress of the lines starting from the green pixel with the degree and see which line travelled the farthest distance.
longestDist = 0
bestDegree = -1
farthestX = -1
farthestY = -1
FOR EACH degree from 0 to 360
dx=longestDist * cos(degree);
dy=longestDist * sin(degree);
IF Point(x+dx , y+dy) does not belong to the group
Continue with next degree
//Because it must not be the longest line, so skip it
END IF
(farthestX , farthestY) = simulate(x,y,degree)
d = findDistance(x , y , farthestX , farthestY)
IF d > longestDist
longestDist = d
bestDegree = degree
END IF
END FOR
It is obviously not the best algorithm. Thus I am asking for help here.
Thank you and sorry for my poor English.
I wouldn't work with angles. But I'm pretty sure the largest distance will always be between two pixels at the edge of the set, thus I'd trace the outline: From any pixel in the set go to any direction until you reach the edge of the set. Then move (couter)clockwise along the edge. Do this with any pixel as starting point and you'll be able to find the largest distance. It's still pretty greedy, but I thought it might give you an alternative starting point to improve upon.
Edit: What just came to my mind: When you have a start pixel s and the end pixel e. In the first iteration using s the corresponding e will be adjacent (the next one along the edge in clockwise direction). As you iterate along the edge the case might occur, that there is no straight line through the set between s and e. In that case the line will hit another part of the set-edge (the pixel p) though. You can continue iteration of the edge at that pixel (e = p)
Edit2: And if you hit a p you'll know that there can be no longer distance between s and e so in the next iteration of s you can skip that whole part of the edge (between s and p) and start at p again.
Edit3: Use the above method to find the first p. Take that p as next s and continue. Repeat until you reach your first p again. The max distance will be between two of those p unless the edge of the set is convex in which case you wont find a p.
Disclaimer: This is untested and are just ideas from the top of my head, no drawings have been made to substantiate my claims and everything might be wrong (i.e. think about it for yourself before you implement it ;D)
First, note that the angle discretization in your algorithm may depend on the size of the grid. If the step is too large, you can miss certain cells, if it is too small, you will end up visiting the same cell again and again.
I would suggest that you enumerate the cells in the region and test the condition for each one individually instead. The enumeration can be done using breadth-first or depth-first search (I think the latter would be preferable, since it will allow one to establish a lower bound quickly and do some pruning).
One can maintain the farthest point X found so far and for each new point in the region, check whether (a) the point is further away than the one found so far and (b) it's connected to the origin by a straight line passing through the cells of the region only. If both conditions are satisfied, update the X, else go on with the search. If condition (a) is not satisfied, condition (b) doesn't have to be checked.
The complexity of this solution would be O(N*M), where N is the number of cells in the region and M is the larger dimension of the region (max(width,height)). If performance is of essence, more sophisticated heuristics can be applied, but for a reasonably sized grid this should work fine.
Search for pixel, not for slope. Pseudocode.
bestLength = 0
for each pixel in pixels
currentLength = findDistance(x, y, pixel.x, pixel.y)
if currentLength > bestLength
if goodLine(x, y, pixel.x, pixel.y)
bestLength = currentLength
bestX = pixel.x
bestY = pixel.y
end
end
end
You might want to sort pixels descending by |dx| + |dy| before that.
Use a double data-structure:
One that contains the pixels sorted by angle.
The second one sorted by distance (for fast access, this should also contain "pointers" for the first data structure).
Walk through the angle sorted one, and check for each pixel that the line is within the region. Some pixels will have the same angle, so you can walk from the origin along the line, and go till you go out from the region. You can eliminate all the pixels which are beyond that point. Also, if the maximum distance increased, remove all pixels which have a shorter distance.
Treat your region as a polygon instead of a collection of pixels. From this you can get a list of line segments (the edges of your polygon).
Draw a line from your start pixel to each pixel you are checking. The longest line that does not intersect any of the line segments of your polygon indicates your most distant pixel that is reachable by a straight line from your pixel.
There are various optimizations you can make to this and a few edges cases to check, but let me know if you understand the idea before i post those... in particular, do you understand what I mean by treating as a polygon instead of a collection of pixels?
To add, this approach will be significantly faster than any angle based approach or approach that requires "walking" for all but the smallest collections of pixels. You can further optimize because your problem is equivalent to finding the most distant endpoint of a polygon edge that can be reached via an unintersected straight line from your start point. This can be done in O(N^2), where N is the number of edges. Note that N will be much much smaller than the number of pixels, and many of the algorithms proposed that use angles an/or pixel iteration are be going to instead depend on the number of pixels.
Input: a set of rectangles within the area (0, 0) to (1600, 1200).
Output: a point which none of the rectangles contains.
What's an efficient algorithm for this? The only two I can currently think of are:
Create a 1600x1200 array of booleans. Iterate through the area of each rectangle, marking those bits as True. Iterate at the end and find a False bit. Problem is that it wastes memory and can be slow.
Iterate randomly through points. For each point, iterate through the rectangles and see if any of them contain the point. Return the first point that none of the rectangles contain. Problem is that it is really slow for densely populated problem instances.
Why am I doing this? It's not for homework or for a programming competition, although I think that a more complicated version of this question was asked at one (each rectangle had a 'color', and you had to output the color of a few points they gave you). I'm just trying to programmatically disable the second monitor on Windows, and I'm running into problems with a more sane approach. So my goal is to find an unoccupied spot on the desktop, then simulate a right-click, then simulate all the clicks necessary to disable it from the display properties window.
For each rectangle, create a list of runs along the horizontal direction. For example a rectangle of 100x50 will generate 50 runs of 100. Write these with their left-most X coordinate and Y coordinate to a list or map.
Sort the list, Y first then X.
Go through the list. Overlapping runs should be adjacent, so you can merge them.
When you find the first run that doesn't stretch across the whole screen, you're done.
I would allocate an image with my favorite graphics library, and let it do rectangle drawing.
You can try a low res version first (scale down a factor 8), that will work if there is at least a 15x15 area. If it fails, you can try a high res.
Use Windows HRGNs (Region in .net). They were kind of invented for this. But that's not language agnostic no.
Finally you can do rectangle subtraction. Only problem is that you can get up to 4 rectangles each time you subtract one rect from another. If there are lots of small ones, this can get out of hand.
P.S.: Consider optimizing for maximized windows. Then you can tell there are no pixels visible without hit testing.
Sort all X-coordinates (start and ends of rectangles), plus 0 & 1600, remove duplicates. Denote this Xi (0 <= i <= n).
Sort all Y-coordinates (start and ends of rectangles), plus 0 & 1200, remove duplicates. Denote this Yj (0 <= j <= m).
Make a n * m grid with the given Xi and Yj from the previous points, this should be much smaller than the original 1600x1200 one (unless you have a thousand rectangles, in which case this idea doesn't apply). Each point in this grid maps to a rectangle in the original 1600 x 1200 image.
Paint rectangles in this grid: find the coordinates of the rectangles in the sets from the first steps, paint in the grid. Each rectangle will be on the form (Xi1, Yj1, Xi2, Yj2), so you paint in the small grid all points (x, y) such that i1 <= x < i2 && j1 <= y < j2.
Find the first unpainted cell in the grid, take any point from it, the center for example.
Note: Rectangles are assumed to be on the form: (x1, y1, x2, y2), representing all points (x, y) such that x1 <= x < x2 && y1 <= y < y2.
Nore2: The sets of Xi & Yj may be stored in a sorted array or tree for O(log n) access. If the number of rectangles is big.
If you know the minimum x and y dimensions of the rectangles, you can use the first approach (a 2D array of booleans) using fewer pixels.
Take into account that 1600x1200 is less than 2M pixels. Is that really so much memory? If you use a bitvector, you only need 235k.
You first idea is not so bad... you should just change the representation of the data.
You may be interessed in a sparse array of booleans.
A language dependant solution is to use the Area (Java).
If I had to do this myself, I'd probably go for the 2d array of booleans (particularly downscaled as jdv suggests, or using accelerated graphics routines) or the random point approach.
If you really wanted to do a more clever approach, though, you can just consider rectangles. Start with a rectangle with corners (0,0),(1600,1200) = (lx,ly),(rx,ry) and "subtract" the first window (wx1,wy1)(wx2,wy2).
This can generate at most 4 new "still available" rectangles if it is completely contained within the original free rectangle: (eg, all 4 corners of the new window are contained within the old one) they are (lx,ly)-(rx,wy1), (lx,wy1)-(wx1,wy2), (wx2,wy1)-(rx,wy2), and (lx,wy2)-(rx,ry). If just a corner of the window overlaps (only 1 corner is inside the free rectangle), it breaks it into two new rectangles; if a side (2 corners) juts in it breaks it into 3; and if there's no overlap, nothing changes. (If they're all axes aligned, you can't have 3 corners inside).
So then keep looping through the windows, testing for intersection and sub-dividing rectangles, until you have a list (if any) of all remaining free space in terms of rectangles.
This is probably going to be slower than any of the graphics-library powered approaches above, but it'd be more fun to write :)
Keep a list of rectangles that represent uncovered space. Initialize it to the entire area.
For each of the given rectangles
For each rectangle in uncovered space
If they intersect, divide the uncovered space into smaller rectangles around the covering rectangle, and add the smaller rectangles (if any) to your list of uncovered ones.
If your list of uncovered space still has any entries, they contain all points not covered by the given rectangles.
This doesn't depend on the number of pixels in your area, so it will work for large (or infinite) resolution. Each new rectangle in the uncovered list will have corners at unique intersections of pairs of other rectangles, so there will be at most O(n^2) in the list, giving a total runtime of O(n^3). You can make it more efficient by keeping your list of uncovered rectangles an a better structure to check each covering rectangle against.
This is a simple solution with a 1600+1200 space complexity only, it is similar in concept to creating a 1600x1200 matrix but without using a whole matrix:
Start with two boolean arrays W[1600] and H[1200] set to true.
Then for each visible window rectangle with coordinate ranges w1..w2 and h1..h2, mark W[w1..w2] and H[h1..h2] to false.
To check if a point with coordinates (w, h) falls in an empty space just check that
(W[w] && H[h]) == true
If I tile squares, and the squares can be defined by their coordinates, how can I simplify shapes made of multiple squares into vectors that define each edge of the entire shape? Pseudo-code or general terms are fine.
The first thing I can think of is (probably not the most efficient way) :
1) Get the bounding box of your entire tiling - which is min(x), min(y) to max(x), max(y) for all x and y of your tiles
2) For every row, start with STATE==EMPTY, iterate over each column : STATE changes to FULL when you hit a square, and EMPTY when you find a hole. Every time STATE goes from EMPTY to FULL, save the left hand line segment of that square and every time STATE goes from FULL to EMPTY, save the right hand line segment of that square.
3) Repeat above in the Y axis
Now you have a set containing only the outermost line segments, you can combine those that are co-linear etc and get the overall shape.
This will work for non-convex shapes and also if you have holes in your tiling.
For a right triangle specified by an equation aX + bY <= c on integers
I want to plot each pixel(*) in the triangle once and only once, in a pseudo-random order, and without storing a list of previously hit points.
I know how to do this with a line segment between 0 and x
pick a random point'o' along the line,
pick 'p' that is relatively prime to x
repeat for up to x times: Onext = (Ocur + P) MOD x
To do this for a triangle, I would
1. Need to count the number of pixels in the triangle sans lists
2. Map an integer 0..points into a x,y pair that is a valid pixel inside the triangle
I hope any solution could be generalized to pyramids and higher dimensional shapes.
(*) I use the CG term pixel for the pair of integer points X,Y such that the equation is satisfied.
Since you want to guarantee visiting each pixel once and only once, it's probably better to think in terms of pixels rather than the real triangles.
You can slice the triangles horizontally and get bunch of horizontal scan lines. Connect the scan lines together and you have converted your "triangle" into a long line. Apply your point visiting algorithm to your long chain of scan lines.
By the way, this mapping only needs to happen on paper, all you need is a function that can return (x, y) given (t) along the virtual scan line.
Edit:
To convert two points to a line segment, you can look for Bresenham's scan conversion. Once you get the 3 line segments converted into series of points, you can put all points into a bucket and group all points by y. Within the same y-value, sort points by x. The smallest x within a y-value is the begin point of the scan line and the largest x within the y-value is the end point of the scan line. This is called "scan converting triangle". You can find more info if you Google.
Here's a solution for Triangle Point Picking.
What you have to do is choose two vectors (sides) of your triangle, multiply each with a random number in [0,1] and add them up. This will provide a uniform distribution in the quadrilateral defined by the vectors. You'll have to check whether the result lies inside the original triangle; if it doesn't either transform it back in or simply discard it and try again.
One method is to put all of the pixels into an array and then shuffle the array (this is O(n)), then visit the pixels in the order in the shuffled array. This could require quite a lot of memory though.
Here's a method which wastes some CPU time but probably doesn't waste as much as a more complicated method would do.
Compute a rectangle that circumscribes the triangle. It will be easy to "linearize" that rectangle, each scan line followed by the next. Use the algorithm that you already know in order to traverse the pixels of the rectangle. When you hit each pixel, check if the pixel is in the triangle, and if not then skip it.
I would consider the lines of the triangle as single line, which is cut into segments. The segments would be stored in an array where the length of the segment also stored as well as the offset in the total length of the lines. Then depending on the value of O, you can select which array element contains the pixel you want to draw at that moment based on this information and paint the pixel based on the values in the element.