Assign point to closest polygon - geopandas

I have this situation in which I want to detect elements that ought to be contained on the boundary of a geometrical feature, but because of a variety of reason these point-wise objects can be "seen" within or outside the geometry. The within part is not an issue since I wish to use "contains" as a method. So, what I do is that I buffer the geometries I have in order to "catch" elements that are just outside the boundary. But this is kind of an issue as well. Indeed, buffering might imply that an element belongs to two geometries when they actually can only be in one.
Here is an example (albeit very naïve, it still illustrate the problem).
import geopandas
import pandas as pd
%matplotlib inline
import matplotlib.pyplot as plt
from shapely.geometry import Point
from geopandas import datasets, GeoDataFrame, read_file
from geopandas.tools import overlay
from shapely.geometry import Polygon, LineString, Point
s = geopandas.GeoSeries(
[
Point(1.1, 1.1),
Point(0.1, 1.1),
],
)
s2 = geopandas.GeoSeries(
[
Polygon([(0, 0), (1, 1), (0, 1)]),
Polygon([(1.25, 1), (2, 2), (1.25, 2)]),
],
index=range(1, 3),
)
envgdf1 = geopandas.GeoDataFrame(geometry=gpd.GeoSeries(s2))
envgdf2 = geopandas.GeoDataFrame(geometry=gpd.GeoSeries(s))
envgdf1 = envgdf1.rename_geometry('Object')
envgdf2 = envgdf2.rename_geometry('Point')
Picture the triangle as my objects and the black points as these object that actually ought to be on either one of these triangle. As I explained above, I buffer the triangle in order to ingulf these points:
envgdf1['buffered_object'] = envgdf1['Object'].buffer(0.3)
envgdf1 = envgdf1.set_geometry('buffered_object')
Which results in
Seen as a dataframe:
df = gpd.sjoin(envgdf1,envgdf2, how="inner", op='contains')
Object \
1 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
1 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
2 POLYGON ((1.25000 1.00000, 2.00000 2.00000, 1....
buffered_object index_right
1 POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ... 1
1 POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ... 0
2 POLYGON ((0.95000 1.00000, 0.95000 2.00000, 0.... 0
you can notice that there are two rows for the same object index_right = 0, meaning that the point is in both polygons.
My question is thus, is there a way to deal with this in a good way? That is:
ignoring anything where the inclusion is ambiguous
Even better: "If the point is closer to one of the geometries, then it belong to that one"
Any other method?
Grateful for any insight on that one!

So, I found a way to answer my question. There might be something better than that and I would be grateful for an answer that makes mine seem cumbersome.
The idea is to create a buffer zone around the polygons in such a way that points will be absorded by the buffered poygon, then sjoin BUT keeping the points. A usual sjoin will disregard the geometry which one wants contained. So here we go:
Instead of
df = gpd.sjoin(envgdf1,envgdf2, how="inner", op='contains')
we'll ensure keeping the points by using savedgeom:
envgdf2['savedgeom'] = envgdf2.geometry
df = gpd.sjoin(envgdf1,envgdf2, how="inner", op='contains')
which results in:
Object \
1 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
1 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
2 POLYGON ((1.25000 1.00000, 2.00000 2.00000, 1....
buffered_object index_right \
1 POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ... 1
1 POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ... 0
2 POLYGON ((0.95000 1.00000, 0.95000 2.00000, 0.... 0
savedgeom
1 POINT (0.10000 1.10000)
1 POINT (1.10000 1.10000)
2 POINT (1.10000 1.10000)
Now, we can determine the distance of each point to the different polygons:
df.crs = "EPSG:4326"
df['dist'] = gpd.GeoSeries(df['Object']).distance(gpd.GeoSeries(df['savedgeom']))
which gives:
Object \
1 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
1 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
2 POLYGON ((1.25000 1.00000, 2.00000 2.00000, 1....
buffered_object index_right \
1 POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ... 1
1 POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ... 0
2 POLYGON ((0.95000 1.00000, 0.95000 2.00000, 0.... 0
savedgeom dist
1 POINT (0.10000 1.10000) 0.100000
1 POINT (1.10000 1.10000) 0.141421
2 POINT (1.10000 1.10000) 0.150000
Since the goal was to match a point to the closest polygon we can simply do
df = df.sort_values("dist", ascending=True).groupby(["index_right"]).first().reset_index()
which gives:
index_right Object \
0 0 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
1 1 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
buffered_object savedgeom \
0 POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ... POINT (1.10000 1.10000)
1 POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ... POINT (0.10000 1.10000)
dist
0 0.141421
1 0.100000

Related

Calculating center of polygon having matrix with it's points

I have a matrix in matlab contains x, y of points of a polygon
I want to find the center of the polygon defined by this points
e.g. :
[ 0 0 ; 0 1 ; 1 1 ; 1 0 ]
I need to find its center.

Transformed Primitives - Compute the inverse of a matrix without using any function

Let's say if I need to transform a cylinder, first I need to use a scaling matrix (sx, sy, sz) and multiply it with a translation matrix (tx, ty, tz) to form a new matrix that combined by these two matrix. => M = T*S.
Then I want to compute the inverse of a matrix M^-1 without using any function, I know that the inverse of a scaling matrix has a scale factors (1/sx, 1/sy, 1/sz) and a inverse of a translation matrix has (-tx, -ty, -tz), but how can I get M^-1 without any function in C++ ?
Suppose you want to scale a vector by some factors Sx, Sy, and Sz. The transformation matrix for this looks like:
Sx 0 0 0
0 Sy 0 0
0 0 Sz 0
0 0 0 1
Then, you want to translate the vector by some factors Tx, Ty, and Tz. The transformation matrix for this now looks like:
Sx 0 0 Tx
0 Sy 0 Ty
0 0 Sz Tz
0 0 0 1
The inverse of this matrix specifically is
1/Sx 0 0 -Tx/Sx
0 1/Sy 0 -Ty/Sy
0 0 1/Sz -Tz/Sz
0 0 0 1
.. as long as Sx, Sy, and Sz are all != 0.
Depending on your application, you may be better off writing a general purpose matrix inversion method. Note that there are cases in which a transformation (or any) matrix is not invertible... like if your scaling factor in one or more of the dimensions is 0. More generally, a matrix is invertible if and only if its determinant is nonzero.

Converting points into another coordinate system

There are 3 points in 3D space. There are 2 orthogonal coordinate systems with the same origin. I know coordinates of those 3 points in both coordinate systems. Given a new point with its coordinates in the first coordinate system, how can I find its coordinates in the second coordinate system?
I think it's possible to get a rotation matrix using given points which does this, but I did not succeed doing this.
You can do it using matrix inverses. Three matrix-vector multiplications (e.g. transforming three 3D vectors by a 3x3 matrix) is equivalent to multiplying two 3x3 matrices together.
So, you can put your first set of points in one matrix, call it A:
0 0 1 < vector 1
0 1 0 < vector 2
2 0 0 < vector 3
Then put your second set of points in a second matrix, call it C. As an example, imagine a transform that scales by a factor of 2 around the origin and flips the Y and Z axes:
0 2 0 < vector 1
0 0 2 < vector 2
4 0 0 < vector 3
So, if A x B = C, we need to find the matrix B, which we can find by finding the A-1:
Inverse of A:
0 0 0.5
0 1 0
1 0 0
The multiply A-1 x C (in that order):
2 0 0
0 0 2
0 2 0
This is a transform matrix B that you can apply to new points. Dot-product multiply the vector by the first column to get the transformed X, second column to get the transformed Y, etc.

Image analysis through GLCM Matrix

I have a image for which I have to calculate the GLCM texture of a selected region. How can I calculate this? I have to calculate the GLCM only for gray area.
To create a Grey-Level Co-occurrence Matrix you simply count how often certain grey Values are Neighbours.
An Example:
Image
1 1 0 2
1 2 2 2
2 2 1 0
Now we define our GLCM as:
GLCM
0 1 2
------------------
0 | (0,0) (0,1) (0,2)
|
1 | (1,0) (1,1) (1,2)
|
2 | (2,0) (2,1) (2,2)
Where (x,y) denotes that how often is the Value y right of the Value x
For our Example we get:
GLCM
0 1 2
------------------
0 | 0 0 1
|
1 | 2 1 1
|
2 | 0 1 3
You can extend this to get more than only the next neighbour or adjust the direction (North, East, South-East etc.) you look for a neighbour if this gives any benefits to your application. You can even create GLCM for every Pixel direction.
After that you can achieve a symmetricall GLCM by counting again but interchanging the position of x and y to get (y,x).
After you have a symmetrical GLCM you can normalize it to get your GLCM Texture.
There is an excellent Paper from Haralick et.al. that you can read: Textural Features for Image Classification.

how do I apply a wieght to a bone?

If I were to assign every vertex to a bone/matrix, how would I edit the transformation matrix so some of the vertexes are transformed less?
For example, if I have the matrix
cos sin 0 0
-sin cos 0 2
0 0 1 0
0 0 0 1
What do i do to it to make the vertex rotate less?
Quoting paddy
"Those sin and cos terms are all supposed to be supplied with an angle. eg sin(theta). So, since you are most likely in control of that, just reduce the angle."
So change the angle by multiplying by a value -1 to 1 and that will change the direction/amount it changes.

Resources