Python实现的一个简单的基于双边滤波的三角形网格平滑程序

这是傅孝明老师的数字几何处理课程的第三次作业…
具体见这里

import numpy as np
import math

v = []
f = []
n = []
c = []
S = []
v_f = {}

# 读取obj
obj = open("noise.obj")
line = obj.readline()
while line:
    if line.startswith("v"):
        v.append(line[1:].split())
    elif line.startswith("f"):
        f.append(line[1:].split())
    # print(line, end = '')   
    line = obj.readline()

obj.close()
# list转numpy
vv = np.array(v, float)
ff = np.array(f, int)

# 计算法向量、重心、面积
for i in range(len(ff)):
    normal = np.cross(vv[ff[i][1] - 1] - vv[ff[i][0] - 1], vv[ff[i][2] - 1] - vv[ff[i][1] - 1])
    # 利用叉乘以求面积
    Area = np.linalg.norm(normal)/2
    normal /= np.linalg.norm(normal)
    n.append(normal)
    S.append(Area)
    center = (vv[ff[i][0] - 1] + vv[ff[i][1] - 1] + vv[ff[i][2] - 1])/3
    c.append(center)
nn = np.array(n)
SS = np.array(S)
cc = np.array(c)


# 计算点的相关面(为后续获得每个面的1-ring面做准备)
for i in range(len(vv)):
    v_f[i+1] = []
for i in range(len(ff)):
    # print(ff[i][0])
    v_f[ff[i][0]].append(i)
    v_f[ff[i][1]].append(i)
    v_f[ff[i][2]].append(i)

def get_one_ring(fi):
    # 获得每个面的1-ring面
    v1 = ff[fi][0]
    v2 = ff[fi][1]
    v3 = ff[fi][2]
    res = list(set(v_f[v1] + v_f[v2] + v_f[v3]))
    return res

# 计算相邻面之间的平均距离和平均法向量差值
e_num = 0
total_distance = 0.0
n_distance = 0.0
for i in range(len(ff)):
    near = get_one_ring(i)
    e_num += len(near)
    for j in near:
        total_distance += np.linalg.norm(cc[i]-cc[j])
        n_distance += np.linalg.norm(nn[i]-nn[j])
avg_distance = total_distance/e_num
avg_n_distance = n_distance/e_num
avg_distance **= 2
avg_n_distance **= 2


def weight_s(ci, cj):
    global vv, nn, cc, SS
    distance = np.linalg.norm(cc[ci] - cc[cj])
    distance **= 2
    return math.exp(-0.5 * distance/avg_distance)

def weight_r(ni, nj):
    global vv, nn, cc, SS
    n_distance = np.linalg.norm(nn[ni] - nn[nj])
    n_distance **= 2
    return math.exp(-0.5 * n_distance/avg_n_distance)

def update_normal():
    global vv, nn, cc, SS
    new_n = []
    for x in range(len(ff)):
        Kp = 0.0
        total = 0.0
        one_ring = get_one_ring(x)
        for y in range(len(one_ring)):
            Kp += SS[one_ring[y]]*weight_s(x, one_ring[y])*weight_r(x, one_ring[y])
            total += SS[one_ring[y]]*weight_s(x, one_ring[y])*weight_r(x, one_ring[y])*nn[one_ring[y]]
        new_n.append(total/Kp)
    nn = np.array(new_n)

def update_point():
    global vv, nn, cc, SS
    new_v = []
    for x in range(len(vv)):
        total = np.array([0.0, 0.0, 0.0])
        near_f = v_f[x+1]
        for y in range(len(near_f)):
            total += nn[near_f[y]]*(np.dot(nn[near_f[y]], (cc[near_f[y]] - vv[x])))
        new_v.append(vv[x] + total/len(near_f))
    # 更新点
    vv = np.array(new_v)

    # 点更新后重新计算每个面的重心
    temp_c = []
    for x in range(len(ff)):
        center = (vv[ff[x][0] - 1] + vv[ff[x][1] - 1] + vv[ff[x][2] - 1]) / 3
        temp_c.append(center)
    cc = np.array(temp_c)


if __name__ == '__main__':
    for i in range(5):
        update_normal()
    for i in range(10):
        update_point()
        output_obj = open("output_" + str(i+1)+".obj", "w")
        for i in range(len(vv)):
            output_obj.write('v ' + str(vv[i])[1:-1] + '\n')
        for i in range(len(ff)):
            output_obj.write('f ' + str(ff[i])[1:-1] + '\n')
        output_obj.close()

Python实现的一个简单的基于双边滤波的三角形网格平滑程序_第1张图片
Python实现的一个简单的基于双边滤波的三角形网格平滑程序_第2张图片

代码写得很丑,轻喷…

你可能感兴趣的:(python)