Get list of coordinates contained in Polygon #1823
-
I'm a very happy user of Shapely within our video analysis tool. This tool offers the user a possibility to analyze certain parts of a video stream. Our users can draw polygonal shapes with the video screen to define their regions of interest. We use Shapely to store these regions and to perform some basic math on them. Works like a charm! But, we've stumbled upon an interesting issue. We use Nvidia's Optical Flow technology to look for motion. For every video frame, we get a 3-dimensional array with X and Y movement vertices. These are simpel floats that define how much this block of 4x4 pixels has moved compared to the previous videoframe. Very elegant, very simple. But, we are only interested in the blocks (of 4x4 pixels) that fall within the RIO('s) the user has specified. So for every video frame we need to select these exact elements from the 3D array before we do any more calculations on them (thresholds, etc.). For a 1920x1080 video the array has a shape of 480:270:2. We need the indexes of the first two dimensions that (times 4) match the coordinates of the Polygon the user defined (because the coordinates of the Polygon match video resolution, not OF array resolution). I've solved this simply by (once) looping through all OF vertices, and constructing a new Polygon out of the indexes and then using the contains() method to verify whether or not this exact block of optical flow vertices falls within the user's ROI. Like so:
where vector_coords now contains a list of x/y coordinates we can later use to "cut" all movement information from every 3d array. We can cut these in mere milliseconds by simply intersecting the lists so that works fine. But... the algorithm we use above is VERY slow. Understandably, because we create a Polygon, check if this new polygon is contained within an existing one and we do this 480 x 270 = 129600 times! On our machine it takes ~ 22 seconds which is unacceptable. Question is: is there a faster way to get a list of all (integer) coordinate pairs of all points within a Polygon? Without having to create a new "candidate" Polygon and checking whether it fits inside? It works but its very, very inefficient. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
The A few suggestions, not sure if they'll help in this case (sorry, no time to write code example):
If you can transform your inputs that you use to create individual Also see contains_xy which is a point-in-polygon method that may or may not be faster if you query it 4 times (e.g., once with array of Note: contains_properly is able to use prepared geometries under the hood (both in STRtree |
Beta Was this translation helpful? Give feedback.
-
Thank you for the excellent guidance, brendan-ward! I did not fully understand everything you said - the spatial index STRTree part is hard to follow for me as non-math major ;), but I did manage to shave off 90% of the calculation time by avoiding the nested for loops and using list comprehensions and vectorized operations to calculate everything. What I do now is:
We've gone from ~22 seconds to ~2 seconds which is WAY more acceptable.
But I'm still wondering if I can optimize this even more. It seems like I'm doing too many operations, still. |
Beta Was this translation helpful? Give feedback.
-
You should be able to use the spatial index query method, after constructing your boxes (it will also prepare your input geoms automatically): from shapely import STRtree
tree = STRtree(vector_boxes)
indices = tree.query(detection_area.polygon, predicate="contains_properly")
vector_boxes_in_detection_area = vector_boxes[indices]
bounds = shapely.bounds(vector_boxes_in_detection_area) # returns array: [[xmin1, ymin1, xmax1, xmax1], [xmin2, ymin2, xmax2, ymax2]]
vector_coors = bounds[:,:2] // crop_factor # this should be equivalent to what you were doing before The spatial index should make this faster because it does a fast check for overlap between the bounding box of the |
Beta Was this translation helpful? Give feedback.
You should be able to use the spatial index query method, after constructing your boxes (it will also prepare your input geoms automatically):
The spatial index should make this faster because it does a fast check for overlap between the bounding box of the
detection_a…