Skip to content

Commit

Permalink
add shapenet
Browse files Browse the repository at this point in the history
  • Loading branch information
maitetsu committed Jun 14, 2021
1 parent 68e230c commit e7816f4
Show file tree
Hide file tree
Showing 33 changed files with 2,381 additions and 37 deletions.
2 changes: 1 addition & 1 deletion .idea/Minimal-Hand-pytorch.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ Offical project link:

* 2021/03/24 Fixed some errors in calculating AUC. Update the 3D PCK AUC Diffenence.


* 2021/06/14 A new method to estimate shape parameters by using fully connected neural network is added. Refer to [ShapeNet.md](./ShapeNet.md) for details. Thanks to kishan1823 and EEWenbinWu for pointing out the mistake. There are a little differences between the manopth I used and the official manopth. More details see [issues 11](https://github.com/MengHao666/Minimal-Hand-pytorch/issues/11)


## Usage

Expand Down Expand Up @@ -101,11 +102,10 @@ data/
CMU/
hand143_panopticdb/
imgs/
datasets/
...
hand_labels/
manual_test/
manual_train/
datasets/
...
RHD/
Expand Down Expand Up @@ -276,16 +276,16 @@ python plot.py --path my_results/out_loss_auc

\* means this project

| Dataset | DetNet(paper) | DetNet(*) | DetNet+IKNet(paper) | DetNet+LM+AIK(*) | DetNet+PSO+AIK(*) |
| :-----: | :-----------: | :-------: | :-----------------: | :--------------: | :-------------: |
| **RHD** | - | 0.9339 | 0.856 | 0.9301 | 0.9310 |
| **STB** | 0.891 | 0.8744 | 0.898 | 0.8647 | 0.8671 |
| **DO** | 0.923 | 0.9378 | 0.948 | 0.9392 | 0.9342 |
| **EO** | 0.804 | 0.9270 | 0.811 | 0.9288 | 0.9277 |
| Dataset | DetNet(paper) | DetNet(*) | DetNet+IKNet(paper) | DetNet+LM+AIK(*) | DetNet+PSO+AIK(*) | DetNet+DL+AIK(*) |
| :-----: | :-----------: | :-------: | :-----------------: | :--------------: | :-------------: | :-------------: |
| **RHD** | - | 0.9339 | 0.856 | 0.9301 | 0.9310 | 0.9272 |
| **STB** | 0.891 | 0.8744 | 0.898 | 0.8647 | 0.8671 | 0.8624 |
| **DO** | 0.923 | 0.9378 | 0.948 | 0.9392 | 0.9342 | 0.9400 |
| **EO** | 0.804 | 0.9270 | 0.811 | 0.9288 | 0.9277 | 0.9365 |



### Note
### Notev

- Adjusting training parameters carefully, longer training time, more complicated network or **[Biomechanical Constraint Losses](https://github.com/MengHao666/Hand-BMC-pytorch)** could further boost accuracy.
- As there is no official open source of original paper, above comparison is a little rough.
Expand Down
23 changes: 23 additions & 0 deletions ShapeNet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## ShapeNet

1. Shapenet is a model that uses fully connected neural network to estimate shape parameters. Code of ShapeNet are adapted from [bihand](https://github.com/lixiny/bihand).
2. The training set is generated by MANO.

1. First sample shape parameters from normal distribution N(0,3)

2. Calculate the relative bone length corresponding to the shape parameter.
3. The loss of ShapeNet consists of two parts, one is the error of relative bone length, the other is the regularization loss of shape parameters.

$$
L = \lambda_1 ||\hat{x} - x||_2^2 + \lambda_2 || \hat{y}||_2^2 \\
$$

​ $x$ is the input relative bone length.
​ $\hat{y}$ is the output shape parameters of ShapeNet.
​ $\hat{x}$ is the relative bone length corresponding to the shape parameter.

​ In my opinion, shape parameters include not only relative bone length information, but also absolute bone length information. It is impossible to guarantee that a relative bone length only corresponds to one shape parameter, which is necessary for neural networks. Therefore, the loss function does not directly calculate the error between the shape parameter and the label of it.

4. AUC of ShapeNet can refer [README.md](./README.md). You can get higher AUC, if you change " beta = torch.tanh(beta) " which is the line 85 of model/shape_net.py to "beta = 3*torch.tanh(beta) ". This will make the output range of ShapeNet bigger and get higher AUC. According to the experiment, the finger will be thinner.
5. I didn't adjust the parameters carefully. Maybe you can get better results if you adjust parameters.

9 changes: 5 additions & 4 deletions aik_pose.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@


def recon_eval(op_shapes, pre_j3ds, gt_j3ds, visual, key):
pose0 = torch.eye(3).repeat(1, 16, 1, 1).cuda()
pose0 = torch.eye(3).repeat(1, 16, 1, 1)
mano = manolayer.ManoLayer(flat_hand_mean=True,
side="right",
mano_root='D:/code/manopth/mano/models',
mano_root='mano/models',
use_pca=False,
root_rot_mode='rotmat',
joint_rot_mode='rotmat')
Expand Down Expand Up @@ -73,8 +73,9 @@ def main(args):
path = args.path
for key_i in args.dataset:
print("load {}'s joint 3D".format(key_i))
print('load {}'.format("{}/{}_pso.npy".format(path, key_i)))
op_shapes = np.load("{}/{}_pso.npy".format(path, key_i))
_path = "{}/{}_dl.npy".format(path, key_i)
print('load {}'.format(_path))
op_shapes = np.load(_path)
pre_j3ds = np.load("{}/{}_pre_joints.npy".format(path, key_i))
gt_j3ds = np.load("{}/{}_gt_joints.npy".format(path, key_i))
recon_eval(op_shapes, pre_j3ds, gt_j3ds, args.visualize, key_i)
Expand Down
98 changes: 98 additions & 0 deletions datasets/SIK1M.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import sys
import pickle
import torch
import os
from torch.utils import data
from termcolor import colored, cprint
import numpy as np

sik1m_inst = 0


class _SIK1M(data.Dataset):
"""
The Loader for joints so3 and quat
"""

def __init__(
self,
data_root="data",
data_source=None
):
print("Initialize _SIK1M instance")
bone_len_path = os.path.join(data_root, 'data_bone.npy')
shape_path = os.path.join(data_root, 'data_shape.npy')
self.bone_len = np.load(bone_len_path)
self.shape = np.load(shape_path)

def __len__(self):
return self.shape.shape[0]

def __getitem__(self, index):
temp_bone_len = self.bone_len[index]
temp_shape = self.shape[index]

metas = {
'rel_bone_len': temp_bone_len,
'shape': temp_shape
}
return metas


class SIK1M(data.Dataset):
def __init__(
self,
data_split="train",
data_root="data",
split_ratio=0.8
):
global sik1m_inst
if not sik1m_inst:
sik1m_inst = _SIK1M(data_root=data_root)
self.sik1m = sik1m_inst
self.permu = list(range(len(self.sik1m)))
self.alllen = len(self.sik1m)
self.data_split = data_split
# add the 0.1* the std of Relative bone length as noise, you can change it or not add
self.noise = np.array([0.02906406, 0.02663224, 0.01769793, 0.0274501, 0.02573783, 0.0222863,
0., 0.02855567, 0.02330295, 0.0253288, 0.0266308, 0.02495683, 0.03685857, 0.02430637,
0.02349446])
self.noise = self.noise / 10.0
if data_split == "train":
self.vislen = int(len(self.sik1m) * split_ratio)
self.sub_permu = self.permu[:self.vislen]
elif data_split in ["val", "test"]:
self.vislen = self.alllen - int(len(self.sik1m) * split_ratio)
self.sub_permu = self.permu[(self.alllen - self.vislen):]
else:
self.vislen = len(self.sik1m)
self.sub_permu = self.permu[:self.vislen]

def __len__(self):
return self.vislen

def __getitem__(self, index):
item = self.sik1m[self.sub_permu[index]]
temp = np.random.randn(15, )
temp = np.multiply(self.noise, temp)
item['rel_bone_len'] += temp
return item


def main():
sik1m_train = SIK1M(
data_split="train",
data_root="data"
)
sik1m_test = SIK1M(
data_split="test"
)

metas = sik1m_train[2]
print(metas)
metas = sik1m_train[2]
print(metas)


if __name__ == "__main__":
main()
14 changes: 5 additions & 9 deletions demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
from manopth import manolayer
from model.detnet import detnet
from utils import func, bone, AIK, smoother
from utils.LM_new import LM_Solver
import numpy as np
import matplotlib.pyplot as plt
from utils import vis
from op_pso import PSO
import open3d

device = torch.device('cuda:0')
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
_mano_root = 'mano/models'

module = detnet().to(device)
print('load model start')
check_point = torch.load('new_check_point/ckp_detnet_83.pth', map_location=device)
Expand All @@ -26,13 +27,11 @@
print('load model finished')
pose, shape = func.initiate("zero")
pre_useful_bone_len = np.zeros((1, 15))
solver = LM_Solver(num_Iter=500, th_beta=shape.cpu(), th_pose=pose.cpu(), lb_target=pre_useful_bone_len,
weight=1e-5)
pose0 = torch.eye(3).repeat(1, 16, 1, 1)

mano = manolayer.ManoLayer(flat_hand_mean=True,
side="right",
mano_root='D:/code/manopth-master/mano/models',
mano_root=_mano_root,
use_pca=False,
root_rot_mode='rotmat',
joint_rot_mode='rotmat')
Expand Down Expand Up @@ -101,19 +100,16 @@
filted_ax = vis.plot3d(flited_joints + new_tran, fliter_ax)
pre_useful_bone_len = bone.caculate_length(pre_joints, label="useful")



NGEN = 100
popsize = 100
low = np.zeros((1, 10)) - 3.0
up = np.zeros((1, 10)) + 3.0
parameters = [NGEN, popsize, low, up]
pso = PSO(parameters, pre_useful_bone_len.reshape((1, 15)))
pso = PSO(parameters, pre_useful_bone_len.reshape((1, 15)),_mano_root)
pso.main()
opt_shape = pso.ng_best
opt_shape = shape_fliter.process(opt_shape)


opt_tensor_shape = torch.tensor(opt_shape, dtype=torch.float)
_, j3d_p0_ops = mano(pose0, opt_tensor_shape)
template = j3d_p0_ops.cpu().numpy().squeeze(0) / 1000.0 # template, m 21*3
Expand Down
Loading

0 comments on commit e7816f4

Please sign in to comment.