agd.Eikonal.HFM_CUDA.ShapeFromShading
This module solves the shape from shading PDE, with a non-vertical light source. The PDE reads (alpha u_x + beta u_y + gamma) / sqrt(1+u_x^2+u_y^2) = rhs where alpha, beta, gamma are parameters related to the sun direction.
1# Copyright 2021 Jean-Marie Mirebeau, University Paris-Sud, CNRS, University Paris-Saclay 2# Distributed WITHOUT ANY WARRANTY. Licensed under the Apache License, Version 2.0, see http://www.apache.org/licenses/LICENSE-2.0 3 4""" 5This module solves the shape from shading PDE, with a non-vertical light source. 6The PDE reads 7(alpha u_x + beta u_y + gamma) / sqrt(1+u_x^2+u_y^2) = rhs 8where alpha, beta, gamma are parameters related to the sun direction. 9""" 10 11import os 12import numpy as np 13import cupy as cp 14from . import cupy_module_helper 15from ... import FiniteDifferences as fd 16 17def EvalScheme(cp,u,params,uc=None,mask=None): 18 """ 19 Evaluates the (piecewise) quadratic equation defining the numerical scheme. 20 Inputs : 21 - uc : plays the role of λ 22 - params : alpha,beta,gamma,h (grid scale) 23 """ 24 alpha,beta,gamma,h = params 25 if uc is None: uc=u 26 27 sa,alpha=int(np.sign(alpha)),np.abs(alpha) 28 sb,beta =int(np.sign(beta)), np.abs(beta) 29 30 wx = np.roll(u,-sa,axis=0) 31 wy = np.roll(u,-sb, axis=1) 32 vx = np.minimum(wx,np.roll(u,sa,axis=0)) 33 vy = np.minimum(wy,np.roll(u,sb,axis=1)) 34 35 residue = (cp*np.sqrt(1+(np.maximum(0,uc-vx)**2+np.maximum(0,uc-vy)**2)/h**2) 36 + alpha*(uc-wx)/h+beta*(uc-wy)/h-gamma) 37 return residue if mask is None else np.where(mask,residue,0.) 38 39 40def Solve(rhs,mask,u0,params,niter=300,traits=None): 41 """ 42 Iterative solver for the shape from shading equation. 43 """ 44 float_t = np.float32 45 int_t = np.int32 46 boolatom_t = np.uint8 47 assert len(params)==4 48 49 # Reshape data 50 rhs = cp.asarray(rhs,dtype=float_t) 51 mask = cp.asarray(mask,dtype=boolatom_t) 52 u0 = cp.asarray(u0,dtype=float_t) 53 shape = rhs.shape 54 assert mask.shape==shape and u0.shape==shape 55 56 traits_default = {'side_i':8,'niter_i':8} 57 if traits is None: traits = traits_default 58 else: traits = {**traits_default,**traits} 59 60 shape_i = (traits['side_i'],)*2 61 rhs,mask,u0 = [fd.block_expand(e,shape_i,constant_values=v) 62 for e,v in [(rhs,np.nan),(mask,False),(u0,0.)] ] 63 64 # Find active blocks 65 shape_o = rhs.shape[:2] 66 update_o = np.flatnonzero(np.any(mask,axis=(-2,-1))).astype(int_t) 67 68 # Setup the cuda module 69 cuda_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"cuda") 70 date_modified = cupy_module_helper.getmtime_max(cuda_path) 71 source = cupy_module_helper.traits_header(traits) 72 73 source += ['#include "Kernel_ShapeFromShading.h"', 74 f"// Date cuda code last modified : {date_modified}"] 75 cuoptions = ("-default-device", f"-I {cuda_path}") 76 source = "\n".join(source) 77 module = cupy_module_helper.GetModule(source,cuoptions) 78 79 def SetCst(name,var,dtype):cupy_module_helper.SetModuleConstant(module,name,var,dtype) 80 SetCst('params',params,float_t) 81 SetCst('shape_o',shape_o,int_t) 82 SetCst('shape_tot', np.array(shape_o)*np.array(shape_i), int_t) 83 84 sfs = module.get_function('JacobiUpdate') 85 86 # Call the kernel 87 rhs,mask,u,update_o = [cp.ascontiguousarray(e) for e in (rhs,mask,u0,update_o)] 88 for i in range(niter): 89 sfs((update_o.size,),shape_i,(u,rhs,mask,update_o)) 90 91 return fd.block_squeeze(u,shape) 92 93
def
EvalScheme(cp, u, params, uc=None, mask=None):
18def EvalScheme(cp,u,params,uc=None,mask=None): 19 """ 20 Evaluates the (piecewise) quadratic equation defining the numerical scheme. 21 Inputs : 22 - uc : plays the role of λ 23 - params : alpha,beta,gamma,h (grid scale) 24 """ 25 alpha,beta,gamma,h = params 26 if uc is None: uc=u 27 28 sa,alpha=int(np.sign(alpha)),np.abs(alpha) 29 sb,beta =int(np.sign(beta)), np.abs(beta) 30 31 wx = np.roll(u,-sa,axis=0) 32 wy = np.roll(u,-sb, axis=1) 33 vx = np.minimum(wx,np.roll(u,sa,axis=0)) 34 vy = np.minimum(wy,np.roll(u,sb,axis=1)) 35 36 residue = (cp*np.sqrt(1+(np.maximum(0,uc-vx)**2+np.maximum(0,uc-vy)**2)/h**2) 37 + alpha*(uc-wx)/h+beta*(uc-wy)/h-gamma) 38 return residue if mask is None else np.where(mask,residue,0.)
Evaluates the (piecewise) quadratic equation defining the numerical scheme. Inputs :
- uc : plays the role of λ
- params : alpha,beta,gamma,h (grid scale)
def
Solve(rhs, mask, u0, params, niter=300, traits=None):
41def Solve(rhs,mask,u0,params,niter=300,traits=None): 42 """ 43 Iterative solver for the shape from shading equation. 44 """ 45 float_t = np.float32 46 int_t = np.int32 47 boolatom_t = np.uint8 48 assert len(params)==4 49 50 # Reshape data 51 rhs = cp.asarray(rhs,dtype=float_t) 52 mask = cp.asarray(mask,dtype=boolatom_t) 53 u0 = cp.asarray(u0,dtype=float_t) 54 shape = rhs.shape 55 assert mask.shape==shape and u0.shape==shape 56 57 traits_default = {'side_i':8,'niter_i':8} 58 if traits is None: traits = traits_default 59 else: traits = {**traits_default,**traits} 60 61 shape_i = (traits['side_i'],)*2 62 rhs,mask,u0 = [fd.block_expand(e,shape_i,constant_values=v) 63 for e,v in [(rhs,np.nan),(mask,False),(u0,0.)] ] 64 65 # Find active blocks 66 shape_o = rhs.shape[:2] 67 update_o = np.flatnonzero(np.any(mask,axis=(-2,-1))).astype(int_t) 68 69 # Setup the cuda module 70 cuda_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"cuda") 71 date_modified = cupy_module_helper.getmtime_max(cuda_path) 72 source = cupy_module_helper.traits_header(traits) 73 74 source += ['#include "Kernel_ShapeFromShading.h"', 75 f"// Date cuda code last modified : {date_modified}"] 76 cuoptions = ("-default-device", f"-I {cuda_path}") 77 source = "\n".join(source) 78 module = cupy_module_helper.GetModule(source,cuoptions) 79 80 def SetCst(name,var,dtype):cupy_module_helper.SetModuleConstant(module,name,var,dtype) 81 SetCst('params',params,float_t) 82 SetCst('shape_o',shape_o,int_t) 83 SetCst('shape_tot', np.array(shape_o)*np.array(shape_i), int_t) 84 85 sfs = module.get_function('JacobiUpdate') 86 87 # Call the kernel 88 rhs,mask,u,update_o = [cp.ascontiguousarray(e) for e in (rhs,mask,u0,update_o)] 89 for i in range(niter): 90 sfs((update_o.size,),shape_i,(u,rhs,mask,update_o)) 91 92 return fd.block_squeeze(u,shape)
Iterative solver for the shape from shading equation.