Filtering pointcloud - python

I wish to filter a pointcloud, loaded with opend3d, as efficiently as possible.
Currently, I perform a downsampling of the points before making a mesh out of them and using .contains on an inclusion volume mesh I did manually. Something like this:
def load_pointcloud(self, pointcloud_path):
# Load Pointcloud
print('target_pointcloud', pointcloud_path)
self.pointcloud_path = pointcloud_path
pcd = o3d.io.read_point_cloud(pointcloud_path)
downpcd = pcd.voxel_down_sample(voxel_size=0.02)
cl, ind = downpcd.remove_statistical_outlier(nb_neighbors=20,
std_ratio=2.0)
downpcd = downpcd.select_by_index(ind)
pcd_points = np.asarray(downpcd.points, dtype=np.float32)
self.verts = torch.from_numpy(pcd_points)
self.verts = self.verts.to(device)
# We construct a Meshes structure for the target mesh
self.pointcloud_points = Pointclouds(points=[self.verts])
self.points = pcd_points
self.inclusion_pointcloud()
def inclusion_pointcloud(self):
vetices_in_mesh_states = self.mesh_inclusion.contains(self.points)
vetices_in_mesh = self.points[vetices_in_mesh_states == True]
# Creating cropped point cloud
cropped_pc = o3d.geometry.PointCloud()
cropped_pc.points = o3d.utility.Vector3dVector(vetices_in_mesh)
cropped_pc.paint_uniform_color([0,0,0])
self.points = np.asarray(cropped_pc.points, dtype=np.float32)
self.verts = torch.from_numpy(self.points)
self.verts = self.verts.to(device)
self.pointcloud_points = Pointclouds(points=[self.verts])
self.pc_mesh = trimesh.Trimesh(vertices=self.points)
What I was thinking in doing was to, after the downsampling, mask away points on X, Y, and Z, and then making a mesh to use .contains again in the same inclusion volume. I thought that this would reduce the .contains computation and run faster, and it kind of does, but is a marginal reduction, like 10 or 15ms, sometimes less. Something like this:
def new_load_pointcloud(self, pointcloud_path):
# Load Pointcloud
print('target_pointcloud', pointcloud_path)
self.pointcloud_path = pointcloud_path
pcd = self.trim_cloud(pointcloud_path)
downpcd = pcd.voxel_down_sample(voxel_size=0.02)
cl, ind = downpcd.remove_statistical_outlier(nb_neighbors=20,
std_ratio=2.0)
downpcd = downpcd.select_by_index(ind)
pcd_points = np.asarray(downpcd.points, dtype=np.float32)
self.verts = torch.from_numpy(pcd_points)
self.verts = self.verts.to(device)
# We construct a Meshes structure for the target mesh
self.pointcloud_points = Pointclouds(points=[self.verts])
self.points = pcd_points
self.inclusion_pointcloud()
def trim_cloud(self, pointcloud_path):
# pcd = o3d.io.read_point_cloud(pointcloud_path)
pcd_clean = o3d.io.read_point_cloud(pointcloud_path)
# X Axis
points = np.asarray(pcd_clean.points)
mask_x_1 = points[:,0] > -0.4
mask_x_2 = points[:,0] < 0.4
# Y Axis
mask_y_1 = points[:,1] > -1.3
mask_y_2 = points[:,1] < 0.9
# Z Axis
mask_z_1 = points[:,2] < 0.3 # Closer to floor
mask_z_2 = points[:,2] > -0.1 # Clooser to ceiling
mask_x = np.logical_and(mask_x_1, mask_x_2) # Along table's wide
mask_y = np.logical_and(mask_y_1, mask_y_2) # Along table's longitude
mask_z = np.logical_and(mask_z_1, mask_z_2) # Along table's height
mask = np.logical_and(mask_x, mask_y, mask_z)
pcd_clean.points = o3d.utility.Vector3dVector(points[mask])
return pcd_clean
def inclusion_pointcloud(self):
vetices_in_mesh_states = self.mesh_inclusion.contains(self.points)
vetices_in_mesh = self.points[vetices_in_mesh_states == True]
# Creating cropped point cloud
cropped_pc = o3d.geometry.PointCloud()
cropped_pc.points = o3d.utility.Vector3dVector(vetices_in_mesh)
cropped_pc.paint_uniform_color([0,0,0])
self.points = np.asarray(cropped_pc.points, dtype=np.float32)
self.verts = torch.from_numpy(self.points)
self.verts = self.verts.to(device)
self.pointcloud_points = Pointclouds(points=[self.verts])
self.pc_mesh = trimesh.Trimesh(vertices=self.points)

I think you are using too much nb_neighbors for the filter. Try less points , like 6 or 10, and a better threshold, like 1.0 or even 0.5. Here is the same filter on MATLAB documentation https://www.mathworks.com/help/vision/ref/pcdenoise.html, standard value for the threshold is 1.0 and for the knn is 6. You can also try the Radius Outlier Removal or the median filter: https://www.mathworks.com/help/lidar/ref/pcmedian.html

Related

Is it possible to fill in a circular graph with a solid colour and save it as svg in matplotlib?

I wrote some code that creates randomised patches from graphs in matplotlib. Basically how it works is that you create a graph from nodes taken from a circle using the parametric equation for a circle and then you randomly displace the nodes along the vector of (0,0) to the node point on the circumference of the circle. That way you can be certain to avoid lines from crossing each other once the circle is drawn. In the end you just append the first (x,y) coordinate to the list of coordinates to close the circle.
What I want to do next is to find a way to fill that circular graph with a solid colour so that I can create a "stamp" that can be used to make randomised patches on a canvas that hopefully will not create crossing edges. I want to use this to make procedural risk maps in svg format, because a lot of those are uploaded with terrible edges using raster image formats using jpeg.
I am pretty sure that my information of the nodes should be sufficient to make that happen but I have no idea how to implement that. Can anyone help?
import numpy as np
import matplotlib.pyplot as plt
def node_circle(r=0.5,res=100):
# Create arrays (x and y coordinates) for the nodes on the circumference of a circle. Use parametric equation.
# x = r cos(t) y = r sin(t)
t = np.linspace(0,2*np.pi,res)
x = r*np.cos(t)
y = r*np.sin(t)
return t,x,y
def sgn(x,x_shift=-0.5,y_shift=1):
# A shifted sign function to use as a switching function
# in order to avoid shifts lower than -0.5 which is
# the radius of the circle.
return -0.5*(np.abs(x -x_shift)/(x -x_shift)) +y_shift
def displacer(x,y,low=-0.5,high=0.5,maxrad=0.5):
# Displaces the node points of the circle
shift = 0
shift_increment = 0
for i in range(len(x)):
shift_increment = np.random.uniform(low,high)
shift += shift_increment*sgn(maxrad)
x[i] += x[i]*shift
y[i] += y[i]*shift
x = np.append(x,x[0])
y = np.append(y,y[0])
return x,y
def plot():
# Actually visualises everything
fig, ax = plt.subplots(figsize=(4,4))
# np.random.seed(1)
ax.axis('off')
t,x,y = node_circle(res=100)
a = 0
x,y = displacer(x,y,low=-0.15,high=0.15)
ax.plot(x,y,'r-')
# ax.scatter(x,y,)
plt.show()
plot()
got it: the answer is to use matplotlib.Patches.Polygon
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
def node_circle(r=0.5,res=100):
# Create arrays (x and y coordinates) for the nodes on the circumference of a circle. Use parametric equation.
# x = r cos(t) y = r sin(t)
t = np.linspace(0,2*np.pi,res)
x = r*np.cos(t)
y = r*np.sin(t)
return x,y
def sgn(x,x_shift=-0.5,y_shift=1):
# A shifted sign function to use as a switching function
# in order to avoid shifts lower than -0.5 which is
# the radius of the circle.
return -0.5*(np.abs(x -x_shift)/(x -x_shift)) +y_shift
def displacer(x,y,low=-0.5,high=0.5,maxrad=0.5):
# Displaces the node points of the circle
shift = 0
shift_increment = 0
for i in range(len(x)):
shift_increment = np.random.uniform(low,high)
shift += shift_increment*sgn(maxrad)
x[i] += x[i]*shift
y[i] += y[i]*shift
x = np.append(x,x[0])
y = np.append(y,y[0])
return x,y
def patch_distributor(M,N,res,grid='square'):
# Distribute Patches based on a specified pattern/grid.
if grid == 'square':
data = np.zeros(shape=(M,N,2,res+1))
for i in range(M):
for j in range(N):
x,y = displacer(*node_circle(res=res),low=-0.2,high=0.2)
data[i,j,0,:] = x
data[i,j,1,:] = y
return data
def plot(res):
# Actually visualises everything
fig, ax = plt.subplots(figsize=(4,4))
# np.random.seed(1)
ax.axis('off')
# x,y = node_circle(res=res)
# x,y = displacer(x,y,low=-0.15,high=0.15)
# xy = np.zeros((len(x),2))
# xy[:,0] = x
# xy[:,1] = y
patch_data = patch_distributor(10,10,res)
for i in range(patch_data.shape[0]):
for j in range(patch_data.shape[1]):
x,y = patch_data[i,j]
x += i*0.5
y += j*0.5
xy = np.zeros((len(x),2))
xy[:,0] = x
xy[:,1] = y
patch = Polygon(xy,fc='w',ec='k',lw=2,zorder=np.random.randint(2),antialiased=False)
ax.add_patch(patch)
ax.autoscale_view()
# ax.plot(x,y,'r-')
# ax.scatter(x,y,)
plt.savefig('lol.png')
plot(res=40)
# Displace circle along the line of (0,0) -> (cos(t),sin(t))
# Make the previous step influence the next to avoid jaggedness
# limit displacement level to an acceptable amount
# Random displaced cubic grid as placing points for stamps.

When creating a 3D surface in Python using Mayavi or PyVista how do I avoid filling holes/openings? [duplicate]

Issue with PyVista filling opening that shouldn't be filled
import math
import numpy as np
import matplotlib as mpl
import pyvista as pv
mpl.use("Qt5Agg")
mpl.rcParams["toolbar"] = "None" # Get rid of toolbar
def xy_waveguide_contour(throat, x_waveguide, ellipse_x):
x_initial = (throat + (x_waveguide * (ellipse_x - throat))) / 2
return x_initial
def xy_waveguide_contour_x2(throat, x_waveguide, ellipse_x):
x_initial = (throat + (x_waveguide * (ellipse_x - throat)))
return x_initial
def z_waveguide_contour(x_array, depth_factor, angle_factor, throat):
angle_factor = angle_factor / 10000
x_prime = x_array - (throat / 2)
z = (x_prime / angle_factor) ** (1 / depth_factor)
return z
def ellipse_contour(a, b):
a = a / 2
b = b / 2
ellipse_steps = np.linspace(0, 0.5 * math.pi, 100)
x_ellipse_array = np.array([])
y_ellipse_array = np.array([])
for h in range(100):
x_ellipse_array = np.append(x_ellipse_array, a * np.cos(ellipse_steps[h]))
y_ellipse_array = np.append(y_ellipse_array, b * np.sin(ellipse_steps[h]))
return x_ellipse_array, y_ellipse_array
def circle_contour(throat):
throat = (throat / 2)
circle_steps = np.linspace(0, 0.5 * math.pi, 100)
x_circle_array = np.array([])
y_circle_array = np.array([])
for j in range(100):
x_circle_array = np.append(x_circle_array, throat * np.cos(circle_steps[j]))
y_circle_array = np.append(y_circle_array, throat * np.sin(circle_steps[j]))
return x_circle_array, y_circle_array
waveguide_throat = 30
ellipse_x = 250
ellipse_y = 150
depth_fact = 4
angle_fact = 40
# Total steps = 100
array_length = 100
xy_steps = np.linspace(0, 1, array_length)
# initialize x, y, z, and zero array
x_array = np.array([])
y_array = np.array([])
z_array = np.array([])
xsub_array = np.array([])
ysub_array = np.array([])
zero_array = np.zeros([array_length])
# calculate hor(x), ver(y), and height(z) contour data and add into array
for i in range(array_length):
x_array = np.append(x_array, xy_waveguide_contour(waveguide_throat, xy_steps[i], ellipse_x))
y_array = np.append(y_array, xy_waveguide_contour(waveguide_throat, xy_steps[i], ellipse_y))
z_array = np.append(z_array, z_waveguide_contour(x_array[i], depth_fact, angle_fact, waveguide_throat))
# calculate data for ellipse
x_ellipse_data, y_ellipse_data = ellipse_contour(ellipse_x, ellipse_y)
# grab last point from z_array and make entire array same value to define height of ellipse/waveguide
ellipse_height = z_array[array_length - 1]
ellipse_z = np.full(shape=array_length, fill_value=ellipse_height)
# Calculate data for throat
circle_x, circle_y = circle_contour(waveguide_throat)
for j in range(0, array_length, 20):
for i in range(array_length):
xsub_array = np.append(xsub_array, xy_waveguide_contour_x2(circle_x[j], xy_steps[i], x_ellipse_data[j]))
ysub_array = np.append(ysub_array, xy_waveguide_contour_x2(circle_y[j], xy_steps[i], y_ellipse_data[j]))
# X = np.concatenate((circle_x, x_ellipse_data, x_array, zero_array))
# Y = np.concatenate((circle_y, y_ellipse_data, zero_array, y_array))
# Z = np.concatenate((zero_array, ellipse_z, z_array, z_array))
# Reshape arrays into 1 column, multiple rows
x_array = x_array.reshape(-1, 1)
y_array = y_array.reshape(-1, 1)
z_array = z_array.reshape(-1, 1)
ellipse_z = ellipse_z.reshape(-1, 1)
x_ellipse_data = x_ellipse_data.reshape(-1, 1)
y_ellipse_data = y_ellipse_data.reshape(-1, 1)
circle_x = circle_x.reshape(-1, 1)
circle_y = circle_y.reshape(-1, 1)
zero_array = zero_array.reshape(-1, 1)
xsub_array = xsub_array.reshape(-1, 1)
ysub_array = ysub_array.reshape(-1, 1)
# save arrays to text
X = np.concatenate((circle_x, x_ellipse_data, x_array, zero_array, xsub_array), axis=0)
Y = np.concatenate((circle_y, y_ellipse_data, zero_array, y_array, ysub_array), axis=0)
Z = np.concatenate((zero_array, ellipse_z, z_array, z_array, z_array, z_array, z_array, z_array, z_array), axis=0)
xyz = np.concatenate((X, Y, Z), axis=1)
cloud = pv.PolyData(xyz)
surf = cloud.delaunay_2d()
surf.plot()
I am trying to create a 3D surface using pyvista (Have also tried Mayavi), whenever I perform a delaunay_2D mesh to create the surface, it closes the "mouth" opening of this surface that should still be open. I have included an image showing what part needs to be fixed and also a copy of my code that generates the data and reproduces the current issue. I would really appreciate anyone's help regarding this issue.
As I noted in a comment under a previous version of your question, I can't find an easy way to fix your current approach.
You could pass alpha=cloud.length/10 to delaunay_2d() which would be close enough, but this would still leave spurious fringes at the edge of your waveguide.
It would be nice to be able to create your waveguide using extrusion, but I don't see how that would be applicable here.
So the only thing I can think of is to change your whole approach: create your waveguide as a 2d structured grid, by parametrising your surface. This is actually possible, and not too difficult:
In 2d you have a circle and an ellipse, and linear interpolation between the two. This means taking points in the form of (r*cos(phi), r*sin(phi)) and interpolating to points at (a*cos(phi), b*sin(phi)). This is straightforward.
In the z direction you have a root function, which depends on the "radial" coordinate of your 2d grid.
Here's how you can do this:
import numpy as np
import pyvista as pv
# parameters for the waveguide
# diameter of the inner circle
waveguide_throat = 30
# axes of the outer ellipse
ellipse_x = 250
ellipse_y = 150
# shape parameters for the z profile
depth_factor = 4
angle_factor = 40
# number of grid points in radial and angular direction
array_length = 100
# now create the actual structured grid
# 2d circular grid
r, phi = np.mgrid[0:1:array_length*1j, 0:np.pi/2:array_length*1j]
# transform to ellipse on the outside, circle on the inside
x = (ellipse_x/2 * r + waveguide_throat/2 * (1 - r))*np.cos(phi)
y = (ellipse_y/2 * r + waveguide_throat/2 * (1 - r))*np.sin(phi)
# compute z profile
angle_factor = angle_factor / 10000
z = (ellipse_x / 2 * r / angle_factor) ** (1 / depth_factor)
waveguide = pv.StructuredGrid(x, y, z)
waveguide.plot(show_edges=True)
This gives you a dense 2d grid forming your waveguide. Whatever you need to do with this surface, you can do with the structured grid.
Here's the structured grid, with your point cloud laid over it to show they are the same:

Calculating mean value of a 2D array as a function of distance from the center in Python

I'm trying to calculate the mean value of a quantity(in the form of a 2D array) as a function of its distance from the center of a 2D grid. I understand that the idea is that I identify all the array elements that are at a distance R from the center, and then add them up and divide by the number of elements. However, I'm having trouble actually identifying an algorithm to go about doing this.
I have attached a working example of the code to generate the 2d array below. The code is for calculating some quantities that are resultant from gravitational lensing, so the way the array is made is irrelevant to this problem, but I have attached the entire code so that you could create the output array for testing.
import numpy as np
import multiprocessing
import matplotlib.pyplot as plt
n = 100 # grid size
c = 3e8
G = 6.67e-11
M_sun = 1.989e30
pc = 3.086e16 # parsec
Dds = 625e6*pc
Ds = 1726e6*pc #z=2
Dd = 1651e6*pc #z=1
FOV_arcsec = 0.0001
FOV_arcmin = FOV_arcsec/60.
pix2rad = ((FOV_arcmin/60.)/float(n))*np.pi/180.
rad2pix = 1./pix2rad
Renorm = (4*G*M_sun/c**2)*(Dds/(Dd*Ds))
#stretch = [10, 2]
# To create a random distribution of points
def randdist(PDF, x, n):
#Create a distribution following PDF(x). PDF and x
#must be of the same length. n is the number of samples
fp = np.random.rand(n,)
CDF = np.cumsum(PDF)
return np.interp(fp, CDF, x)
def get_alpha(args):
zeta_list_part, M_list_part, X, Y = args
alpha_x = 0
alpha_y = 0
for key in range(len(M_list_part)):
z_m_z_x = (X - zeta_list_part[key][0])*pix2rad
z_m_z_y = (Y - zeta_list_part[key][1])*pix2rad
alpha_x += M_list_part[key] * z_m_z_x / (z_m_z_x**2 + z_m_z_y**2)
alpha_y += M_list_part[key] * z_m_z_y / (z_m_z_x**2 + z_m_z_y**2)
return (alpha_x, alpha_y)
if __name__ == '__main__':
# number of processes, scale accordingly
num_processes = 1 # Number of CPUs to be used
pool = multiprocessing.Pool(processes=num_processes)
num = 100 # The number of points/microlenses
r = np.linspace(-n, n, n)
PDF = np.abs(1/r)
PDF = PDF/np.sum(PDF) # PDF should be normalized
R = randdist(PDF, r, num)
Theta = 2*np.pi*np.random.rand(num,)
x1= [R[k]*np.cos(Theta[k])*1 for k in range(num)]
y1 = [R[k]*np.sin(Theta[k])*1 for k in range(num)]
# Uniform distribution
#R = np.random.uniform(-n,n,num)
#x1= np.random.uniform(-n,n,num)
#y1 = np.random.uniform(-n,n,num)
zeta_list = np.column_stack((np.array(x1), np.array(y1))) # List of coordinates for the microlenses
x = np.linspace(-n,n,n)
y = np.linspace(-n,n,n)
X, Y = np.meshgrid(x,y)
M_list = np.array([0.1 for i in range(num)])
# split zeta_list, M_list, X, and Y
zeta_list_split = np.array_split(zeta_list, num_processes, axis=0)
M_list_split = np.array_split(M_list, num_processes)
X_list = [X for e in range(num_processes)]
Y_list = [Y for e in range(num_processes)]
alpha_list = pool.map(
get_alpha, zip(zeta_list_split, M_list_split, X_list, Y_list))
alpha_x = 0
alpha_y = 0
for e in alpha_list:
alpha_x += e[0]
alpha_y += e[1]
alpha_x_y = 0
alpha_x_x = 0
alpha_y_y = 0
alpha_y_x = 0
alpha_x_y, alpha_x_x = np.gradient(alpha_x*rad2pix*Renorm,edge_order=2)
alpha_y_y, alpha_y_x = np.gradient(alpha_y*rad2pix*Renorm,edge_order=2)
det_A = 1 - alpha_y_y - alpha_x_x + (alpha_x_x)*(alpha_y_y) - (alpha_x_y)*(alpha_y_x)
abs = np.absolute(det_A)
I = abs**(-1.)
O = np.log10(I+1)
plt.contourf(X,Y,O,100)
The array of interest is O, and I have attached a plot of how it should look like. It can be different based on the random distribution of points.
What I'm trying to do is to plot the mean values of O as a function of radius from the center of the grid. In the end, I want to be able to plot the average O as a function of distance from center in a 2d line graph. So I suppose the first step is to define circles of radius R, based on X and Y.
def circle(x,y):
r = np.sqrt(x**2 + y**2)
return r
Now I just have to figure out a way to find all the values of O, that have the same indices as equivalent values of R. Kinda confused on this part and would appreciate any help.
You can find the geometric coordinates of a circle with center (0,0) and radius R as such:
phi = np.linspace(0, 1, 50)
x = R*np.cos(2*np.pi*phi)
y = R*np.sin(2*np.pi*phi)
these values however will not fall on the regular pixel grid but in between.
In order to use them as sampling points you can either round the values and use them as indexes or interpolate the values from the near pixels.
Attention: The pixel indexes and the x, y are not the same. In your example (0,0) is at the picture location (50,50).

Place points with variable density

Assume that you have an NxM matrix, with values ranging from [0,100]. What I'd like to do is place points with a density (inversely) relative to the values in that area.
For example, here's a 2D Gaussian field, inverted s.t. the centroid has a value of 0, and the perimeter is at 100:
I'd like to pack the points so that they appear somewhat similar to this image:
Note how there is a radial spread outwards.
My attempt looks a little different :( ...
What I attempt to do is (i) generate a boolean area, of the same shape and size, and (ii) move through the rows and columns. If the value of the boolean array at some point is True, then pass; otherwise, add a [row,col] point to a list and cover the boolean array with True in a radius proportional to the value in the Gaussian array.
The choice of Gaussian for this example isn't important, the fundamental idea is that: given a floating point matrix, how can one place points with a density proportional to those values?
Any help very much appreciated :)
import matplotlib.pyplot as plt
import numpy as np
from math import exp
def gaussian(x,y,x0,y0,A=10.0,sigma_x=10.0,sigma_y=10.0):
return A - A*exp(-((x-x0)**2/(2*sigma_x**2) + (y-y0)**2/(2*sigma_y**2)))
def generate_grid(width=100,height=100):
grid = np.empty((width,height))
for x in range(0,width):
for y in range(0,height):
grid[x][y] = gaussian(x,y,width/2,height/2,A=100.0)
return grid
def cover_array(a,row,col,radius):
nRows = np.shape(grid)[0]
nCols = np.shape(grid)[1]
mid = round(radius / 2)
half_radius = int(round(radius))
for x in range(-half_radius,half_radius):
for y in range(-half_radius,half_radius):
if row+x >= 0 and x+row < nRows and col+y >= 0 and y+col < nCols:
if (x-mid)**2 + (y-mid)**2 <= radius**2:
a[row+x][col+y] = True
def pack_points(grid):
points = []
nRows = np.shape(grid)[0]
nCols = np.shape(grid)[1]
maxDist = 50.0
minDist = 0.0
maxEdge = 10.0
minEdge = 5.0
grid_min = 0.0
grid_max = 100.0
row = 0
col = 0
arrayCovered = np.zeros((nRows,nCols))
while True:
if row >= nRows:
return np.array(points)
if arrayCovered[row][col] == False:
radius = maxEdge * ((grid[row][col] - grid_min) / (grid_max - grid_min))
cover_array(arrayCovered,row,col,radius)
points.append([row,col])
col += 1
if col >= nCols:
row += 1
col = 0
grid = generate_grid()
plt.imshow(grid)
plt.show()
points = pack_points(grid)
plt.scatter(points[:,0],points[:,1])
plt.show()
Here is a cheap and simple method, although it requires hand-setting an amount parameter:
import numpy as np
import matplotlib.pyplot as plt
def gaussian(x,y,x0,y0,A=10.0,sigma_x=10.0,sigma_y=10.0):
return A - A*np.exp(-((x-x0)**2/(2*sigma_x**2) + (y-y0)**2/(2*sigma_y**2)))
def distribute_points(data, amount=1):
p = amount * (1 / data)
r = np.random.random(p.shape)
return np.where(p > r)
ii, jj = np.mgrid[-10:10:.1, -10:10:.1]
data = gaussian(ii, jj, 0, 0)
px, py = distribute_points(data, amount=.03)
plt.imshow(data)
plt.scatter(px, py, marker='.', c='#ff000080')
plt.xticks([])
plt.yticks([])
plt.xlim([0, len(ii)])
plt.ylim([0, len(jj)])
Result:

displaying the ridge orientation as a flow chart

I am trying to view my local ridge orientation of a fingerprint as a flowchart. But I seem to fail miserably at doing so. My method consists of the following steps:
use the lro function
find the most dominant angle in a 16x16 block
create a line segment and rotate it by the dominant angle to display it
The problem is that while the angles that the lro produces are good, the display of these in the flowchart does not work at all. There I just get a lot of random angles going in all kind of directions. Can anyone help me solve this problem?
Here is the code I'm using:
def lro(im_np):
eps = 2**(-52)
orientsmoothsigma = 4
# original
Gxx = cv2.Sobel(im_np, -1, 2, 0)
Gxy = cv2.Sobel(im_np, -1, 1, 1)
Gyy = cv2.Sobel(im_np, -1, 0, 2)
Gxx = scipy.ndimage.filters.gaussian_filter(Gxx, orientsmoothsigma)
Gxy = scipy.ndimage.filters.gaussian_filter(Gxy, orientsmoothsigma)
Gyy = scipy.ndimage.filters.gaussian_filter(Gyy, orientsmoothsigma)
angle = math.pi/2. + numpy.divide(numpy.arctan2(numpy.multiply(Gxy,2), numpy.subtract(Gxx,Gyy)),2)
return angle
def createLine(im_np):
#Assumes it is 17x17
#Takes in the block-direction
#returns a block-direction image as a numpy array
angle = numpy.max(im_np)
# print im_np.shape
im = Image.new('L', (im_np.shape[0], im_np.shape[1]), (0))
draw = ImageDraw.Draw(im)
draw.line([(0,im_np.shape[0]/2), (im_np.shape[0],im_np.shape[0]/2)], fill=255)
im = im.rotate(angle)
img_np2 = numpy.asarray(im)
# print img_np2
return img_np2
def findDomAngle(im_np):
mask = numpy.zeros((180,2))
for i in range(180):
mask[i][0] = i+1
for i in range(im_np.shape[0]):
for j in range(im_np.shape[0]):
mask[im_np[i][j]-1][1] += 1
max = 0
bestdir = 0
for i in range(180):
if mask[i][1] > max:
bestdir = i + 1
max = mask[i][1]
# print mask
# print max
return bestdir
def blkdir(angle_mat):
x = angle_mat.shape[0]
y = angle_mat.shape[1]
# print angle_mat
domAngle = findDomAngle(angle_mat)
# print domAngle
blkAngle = angle_mat
blkAngle.setflags(write=True)
for i in range(x):
for j in range(y):
blkAngle[i][j] = domAngle
return blkAngle
I am applying another function to process the image block by block, but this method has proven to work so I don't find it relevant to include.

Categories