This commit is contained in:
unknown
2025-12-21 18:25:23 +08:00
parent 184ea736f4
commit 6920072072
5 changed files with 211 additions and 5 deletions
+6 -1
View File
@@ -19,12 +19,17 @@ def main():
# 向量场: VRAW, VNORMAL, VSHEAR: 原始,法向,切向 # 向量场: VRAW, VNORMAL, VSHEAR: 原始,法向,切向
# 帧率,时间戳: FPS, TIMESTAMP # 帧率,时间戳: FPS, TIMESTAMP
# 变形量总和: FNORMAL , FSHEARX, FSHEARY : 法向,切向(X),切向(Y) # 变形量总和: FNORMAL , FSHEARX, FSHEARY : 法向,切向(X),切向(Y)
fps, fn, fx, fy, flow = sensor1.read_info(sensor1.info.FPS, sensor1.info.FNORMAL, sensor1.info.FSHEARX, sensor1.info.FSHEARY, sensor1.info.VRAW) # 深度图: DEPTH
fps, fn, fx, fy, flow, depth = sensor1.read_info(sensor1.info.FPS, sensor1.info.FNORMAL, sensor1.info.FSHEARX, sensor1.info.FSHEARY, sensor1.info.VRAW, sensor1.info.DEPTH)
print(fps,fn,fx,fy) print(fps,fn,fx,fy)
# 显示向量场 # 显示向量场
arrows = sensor1.draw_arrows(sensor1.info.VRAW, threshold=5, grid_spacing=40, arrow_scale=1.0) arrows = sensor1.draw_arrows(sensor1.info.VRAW, threshold=5, grid_spacing=40, arrow_scale=1.0)
cv2.imshow("Deformation", arrows) cv2.imshow("Deformation", arrows)
depth_img = cv2.applyColorMap((depth*1* 255.0).astype('uint8'), cv2.COLORMAP_HOT)
cv2.imshow('depth', depth_img)
key = cv2.waitKey(1) key = cv2.waitKey(1)
if key & 0xFF == ord("q"): if key & 0xFF == ord("q"):
print("\n 停止程序") print("\n 停止程序")
+1 -1
View File
@@ -3,7 +3,7 @@ Name: orisys
Version: 0.1.0 Version: 0.1.0
Summary: Orisys - Optical Tactile Sensor SDK Summary: Orisys - Optical Tactile Sensor SDK
Author: Your Name Author: Your Name
Requires-Python: >=3.7 Requires-Python: >=3.8
Requires-Dist: numpy Requires-Dist: numpy
Requires-Dist: opencv-python Requires-Dist: opencv-python
Requires-Dist: scipy Requires-Dist: scipy
+1
View File
@@ -3,6 +3,7 @@ src/orisys/Stitcher.py
src/orisys/StructuredGrid.py src/orisys/StructuredGrid.py
src/orisys/UnstructuredGrid.py src/orisys/UnstructuredGrid.py
src/orisys/__init__.py src/orisys/__init__.py
src/orisys/getDensity.py
src/orisys/nHHD.py src/orisys/nHHD.py
src/orisys/nPoisson.py src/orisys/nPoisson.py
src/orisys/sensor.py src/orisys/sensor.py
+195
View File
@@ -0,0 +1,195 @@
import cupy as cp
import cv2
import numpy as np
zero_level = None
def getFilteredDensity(flow, use_cuda):
sigma = 3.0
r_max = 9.0
# tmp = time.time()
if use_cuda:
density = getDensityCuda(flow, sigma, r_max)
else:
density = getDensity(flow, sigma, r_max)
# print("Density frequency: ", float(1.0 / (time.time() - tmp)))
# tmp = time.time()
density = correctInvalidArea(density)
# print("Correct frequency: ", float(1.0 / (time.time() - tmp)))
# return density[15:-15, 15:-15]
return density
def correctInvalidArea(density):
# density = guided_filter(density, density, 5, 0.001, s=4)
# invalid_ind = np.zeros_like(density, dtype='uint8')
global zero_level
if zero_level is None:
zero_level = np.mean(density[60:-60, 60:-60])
# threshold = zero_level - (density.max() - zero_level) / 120
threshold = zero_level
invalid_ind = twoClustering(density, threshold)
# density = cv2.inpaint(density * 1e4, invalid_ind, 20,
# cv2.INPAINT_TELEA) / 1e4
density[np.where(invalid_ind > 0)] = zero_level ## type 1 repair
# density = guided_filter(density, density, 7, 0.005, s=4)
density = cv2.ximgproc.guidedFilter(density, density, 7, 0.005)
return density
# return invalid_ind
def twoClustering(density, threshold):
cluster = np.zeros_like(density, dtype='uint8')
cluster[np.where(density < threshold)] = 1
# kernel = np.ones((3, 3), np.uint8)
# cluster = cv2.dilate(cluster, kernel, iterations=4)
return cluster
def getDensity(flow, sigma, r_max):
"""
Compute Gaussian density map from optical flow vectors.
Pure NumPy implementation without freud dependency.
Vectorized for better performance.
Args:
flow: Optical flow field with shape (height, width, 2)
sigma: Gaussian kernel standard deviation
r_max: Maximum radius for Gaussian contribution
Returns:
Negative density map with same shape as flow field (height, width)
"""
# Pre-compute constants
two_sigma2 = 2.0 * sigma * sigma
gaussian_norm = 1.0 / (two_sigma2 * np.pi)
# Get flow dimensions
height, width = flow.shape[:2]
flow_x = flow[:, :, 0].astype(np.float32)
flow_y = flow[:, :, 1].astype(np.float32)
# Create coordinate grids
x_coords = np.arange(width, dtype=np.float32)
y_coords = np.arange(height, dtype=np.float32)
grid_x, grid_y = np.meshgrid(x_coords, y_coords)
# Compute destination positions after flow displacement
dest_x = grid_x + flow_x
dest_y = grid_y + flow_y
# Initialize result array
result = np.zeros((height, width), dtype=np.float32)
# Vectorized computation: for each source pixel, compute contributions to nearby grid points
for y in range(height):
for x in range(width):
dest_x_val = dest_x[y, x]
dest_y_val = dest_y[y, x]
# Determine the bounding box of affected grid points
min_x = max(0, int(np.floor(dest_x_val - r_max)))
max_x = min(width, int(np.ceil(dest_x_val + r_max)) + 1)
min_y = max(0, int(np.floor(dest_y_val - r_max)))
max_y = min(height, int(np.ceil(dest_y_val + r_max)) + 1)
if min_x >= max_x or min_y >= max_y:
continue
# Create local grid for this window
local_x = np.arange(min_x, max_x, dtype=np.float32)
local_y = np.arange(min_y, max_y, dtype=np.float32)
local_grid_x, local_grid_y = np.meshgrid(local_x, local_y)
# Compute distances squared
dx = local_grid_x - dest_x_val
dy = local_grid_y - dest_y_val
distance_sq = dx * dx + dy * dy
# Filter by r_max (only include points within radius)
mask = distance_sq <= (r_max * r_max)
# Compute Gaussian contributions
gaussian_vals = np.exp(-distance_sq / two_sigma2) * gaussian_norm
gaussian_vals[~mask] = 0
# Accumulate negative density
result[min_y:max_y, min_x:max_x] -= gaussian_vals
return result
class CudaArrayInterface:
def __init__(self, gpu_mat):
w, h = gpu_mat.size()
type_map = {
cv2.CV_8U: "u1",
cv2.CV_8S: "i1",
cv2.CV_16U: "u2",
cv2.CV_16S: "i2",
cv2.CV_32S: "i4",
cv2.CV_32F: "f4",
cv2.CV_64F: "f8",
}
self.__cuda_array_interface__ = {
"version": 2,
"shape": (h, w),
"data": (gpu_mat.cudaPtr(), False),
"typestr": type_map[gpu_mat.type()],
"strides": (gpu_mat.step, gpu_mat.elemSize()),
}
func_string = r"""
extern "C"{
__device__ float gaussian(float twoSigma2, float dx, float dy)
{
float pi = 3.1415926535897932384626;
float distance = dx*dx+dy*dy;
float result = expf(-distance/twoSigma2);
result = result/(twoSigma2*pi);
return result;
}
__global__ void density(const float *flowX, const float *flowY, float *result, int x_size, int y_size, float twoSigma2, float r_max)
{
int x = threadIdx.x;
int y = blockIdx.x;
float dest_x = float(x)+flowX[y*x_size+x];
float dest_y = float(y) + flowY[y*x_size+x];
for(int ind_x=ceilf(dest_x-r_max);ind_x<ceilf(dest_x+r_max); ++ind_x)
for(int ind_y=ceilf(dest_y-r_max);ind_y<ceilf(dest_y+r_max); ++ind_y)
{
if(ind_x >= x_size || ind_x<0 || ind_y >= y_size || ind_y < 0)
{
continue;
}
float dx = float(ind_x)-dest_x;
float dy = float(ind_y)-dest_y;
atomicAdd(result+ind_y*x_size+ind_x, -gaussian(twoSigma2, dx,dy));
}
}
}
"""
funcupy = cp.RawModule(code=func_string).get_function("density")
def getDensityCuda(flow, sigma, r_max):
twoSigma2 = cp.float32(2.0 * sigma**2)
r_max = cp.float32(r_max)
if type(flow).__module__ == np.__name__:
flowx = cp.array(flow[:, :, 0], dtype=cp.float32)
flowy = cp.array(flow[:, :, 1], dtype=cp.float32)
else:
flowx, flowy = cv2.cuda.split(flow)
flowx = cp.array(CudaArrayInterface(flowx),
dtype=cp.float32,
copy=True)
flowy = cp.array(CudaArrayInterface(flowy),
dtype=cp.float32,
copy=True)
result = cp.zeros((flowx.shape[0], flowx.shape[1]), dtype=cp.float32)
block_dim = (flowx.shape[1], )
grid = (flowx.shape[0], )
funcupy(grid, block_dim, (flowx, flowy, result, cp.int32(
flowx.shape[1]), cp.int32(flowx.shape[0]), twoSigma2, r_max))
return result.get()
+8 -3
View File
@@ -12,6 +12,7 @@ import time
from scipy.interpolate import griddata from scipy.interpolate import griddata
from enum import Enum, auto from enum import Enum, auto
from typing import Optional, Tuple, Union, Any from typing import Optional, Tuple, Union, Any
from .getDensity import getFilteredDensity
class Sensor: class Sensor:
""" """
@@ -83,7 +84,7 @@ class Sensor:
self.stitch_valid = False self.stitch_valid = False
self.n_boxes = None self.n_boxes = None
self.stitch_calibration = [] self.stitch_calibration = []
self.img = self.flow = self.normal = self.shear = self.force = None self.img = self.flow = self.normal = self.shear = self.force = self.depth = None
self.fnormal=self.fshearx=self.fsheary=self.ftor=0.0 self.fnormal=self.fshearx=self.fsheary=self.ftor=0.0
self.imgupdate = self.vupdate = False self.imgupdate = self.vupdate = False
self.pos_default = [(260, 56), (577, 62), (897, 69), (1214, 75), (1530, 81), (256, 391), (570, 397), (889, 403), (1208, 409), (1523, 416), (248, 724), (563, 730), (882, 738), (1201, 743), (1516, 751)] self.pos_default = [(260, 56), (577, 62), (897, 69), (1214, 75), (1530, 81), (256, 391), (570, 397), (889, 403), (1208, 409), (1523, 416), (248, 724), (563, 730), (882, 738), (1201, 743), (1516, 751)]
@@ -109,6 +110,7 @@ class Sensor:
FNORMAL = auto() FNORMAL = auto()
FSHEARX = auto() FSHEARX = auto()
FSHEARY = auto() FSHEARY = auto()
DEPTH = auto()
def get_img(self): def get_img(self):
@@ -161,9 +163,10 @@ class Sensor:
self.normal = self.hhd.get_normal() self.normal = self.hhd.get_normal()
self.shear = self.hhd.get_shear() self.shear = self.hhd.get_shear()
flag, [self.fnormal,self.fshearx,self.fsheary,self.ftor] = self.hhd.get_force(flow) flag, [self.fnormal,self.fshearx,self.fsheary,self.ftor] = self.hhd.get_force(flow)
self.depth = getFilteredDensity(self.flow, use_cuda=self.cuda)
self.fps = 1/(time.time() - self.last_log_time) self.fps = 1/(time.time() - self.last_log_time)
self.last_log_time = time.time() self.last_log_time = time.time()
return self.flow return self.flow
@@ -183,6 +186,7 @@ class Sensor:
- FSHEAR: Shear force magnitude (float) - FSHEAR: Shear force magnitude (float)
- FPS: Current frames per second (float) - FPS: Current frames per second (float)
- TIMESTAMP: Current timestamp string (str) - TIMESTAMP: Current timestamp string (str)
- DEPTH: Depth image (np.ndarray)
Example: Example:
normal, shear, fps = sensor.read_info(sensor.info.VNORMAL, sensor.info.VSHEAR, sensor.info.FPS) normal, shear, fps = sensor.read_info(sensor.info.VNORMAL, sensor.info.VSHEAR, sensor.info.FPS)
@@ -215,7 +219,8 @@ class Sensor:
results.append(self.fps) results.append(self.fps)
elif arg == self.info.TIMESTAMP: elif arg == self.info.TIMESTAMP:
results.append(time.strftime('%H:%M:%S')) results.append(time.strftime('%H:%M:%S'))
elif arg == self.info.DEPTH:
results.append(self.depth if self.depth is not None else np.array([]))
return tuple(results) if results else () return tuple(results) if results else ()
def disconnect(self): def disconnect(self):