def check_gradient(args): """ Compare the exact gradient to the result of the finite differences algorithm `optimize.approx_fprime` This is for debugging the gradient """ trimesh = TriMesh.FromOBJ_FileName(args.in_obj) trimesh = util.deduplicate_trimesh_vertices(trimesh) NUM_VERTS = len(trimesh.vs) energy_function = energy_lookup[args.energy] energy_only = lambda x: energy_function( x, trimesh, gradient_mode=0, NUM_VERTS=NUM_VERTS) grad_only = lambda x: energy_function( x, trimesh, gradient_mode=1, NUM_VERTS=NUM_VERTS) # the first guess at the solution is the object itself first_guess = trimesh.vs.reshape(NUM_VERTS * 3) approximate_gradient = \ optimize.approx_fprime(first_guess, energy_only, [0.01]) extact_gradient = grad_only(first_guess) print "The difference between exact and numerical grad is: {}".format( norm(approximate_gradient - extact_gradient))
def main(): if len(sys.argv) != 2: print >> sys.stderr, 'Usage:', sys.argv[0], 'mesh.obj' sys.exit(-1) mesh_path = sys.argv[1] pid = view_mesh(TriMesh.FromOBJ_FileName(mesh_path), mesh_path) print 'Background process id:', pid
def optimize_energy(args): print "loading {}".format(args.in_obj) trimesh = TriMesh.FromOBJ_FileName(args.in_obj) energy_function = energy_lookup[args.energy] # a lot of meshes have duplicate vertices associated # with adjacent faces, clean that up. trimesh = util.deduplicate_trimesh_vertices(trimesh) NUM_VERTS = len(trimesh.vs) # curry different versions of the energy function and the starting mesh # these are now functions of a single variable that can be optimized energy_only = lambda x: energy_function( x, trimesh, gradient_mode=0, NUM_VERTS=NUM_VERTS) energy_and_grad = lambda x: energy_function( x, trimesh, gradient_mode=2, NUM_VERTS=NUM_VERTS) # the first guess at the solution is the object itself first_guess = trimesh.vs.reshape(NUM_VERTS * 3) print "starting optimization for mesh with {} verts".format(NUM_VERTS) result = \ optimize.minimize( fun=energy_and_grad if args.exact_grad else energy_only, x0=first_guess, options={'disp': True}, method="L-BFGS-B", constraints=None, jac=args.exact_grad) final_mesh_verts = result.x.reshape(NUM_VERTS, 3) trimesh.vs = final_mesh_verts print "writing: {}".format(args.out_obj) trimesh.write_OBJ(args.out_obj)
import time start_time=time.clock() images=np.asfarray(Image.open(input_image_path).convert('RGB')).reshape((-1,3)) hull=ConvexHull(images) origin_hull=hull # visualize_hull(hull) write_convexhull_into_obj_file(hull, output_rawhull_obj_file) N=500 mesh=TriMesh.FromOBJ_FileName(output_rawhull_obj_file) print ('original vertices number:',len(mesh.vs)) for i in range(N): print ('loop:', i) old_num=len(mesh.vs) mesh=TriMesh.FromOBJ_FileName(output_rawhull_obj_file) mesh=remove_one_edge_by_finding_smallest_adding_volume_with_test_conditions(mesh,option=2) newhull=ConvexHull(mesh.vs) write_convexhull_into_obj_file(newhull, output_rawhull_obj_file) print ('current vertices number:', len(mesh.vs))
def compute_color(input_im, N): ######*********************************************************************************************** #### 3D case: use method in paper: "Progressive Hulls for Intersection Applications" #### also using trimesh.py interface from yotam gingold def visualize_hull(hull, groundtruth_hull=None): from matplotlib import pyplot as plt fig = plt.figure(figsize=(8, 8)) ax = fig.add_subplot(1, 1, 1, projection='3d') vertex = hull.points[hull.vertices] ax.scatter(vertex[:, 0], vertex[:, 1], vertex[:, 2], marker='*', color='red', s=40, label='class') # num=hull.simplices.shape[0] # points=[] # normals=[] # for i in range(num): # face=hull.points[hull.simplices[i]] # avg_point=(face[0]+face[1]+face[2])/3.0 # points.append(avg_point) # points=np.asarray(points) # ax.quiver(points[:,0],points[:,1],points[:,2],hull.equations[:,0],hull.equations[:,1],hull.equations[:,2],length=0.01) for simplex in hull.simplices: faces = hull.points[simplex] xs = list(faces[:, 0]) xs.append(faces[0, 0]) ys = list(faces[:, 1]) ys.append(faces[0, 1]) zs = list(faces[:, 2]) zs.append(faces[0, 2]) # print xs,ys,zs plt.plot(xs, ys, zs, 'k-') if groundtruth_hull != None: groundtruth_vertex = groundtruth_hull.points[ groundtruth_hull.vertices] ax.scatter(groundtruth_vertex[:, 0], groundtruth_vertex[:, 1], groundtruth_vertex[:, 2], marker='o', color='green', s=80, label='class') plt.title("3D Scatter Plot") plt.show() from trimesh import TriMesh def write_convexhull_into_obj_file(hull, output_rawhull_obj_file): hvertices = hull.points[hull.vertices] points_index = -1 * np.ones(hull.points.shape[0], dtype=int) points_index[hull.vertices] = np.arange(len(hull.vertices)) #### start from index 1 in obj files!!!!! hfaces = np.array([points_index[hface] for hface in hull.simplices]) + 1 #### to make sure each faces's points are countclockwise order. for index in range(len(hfaces)): face = hvertices[hfaces[index] - 1] normals = hull.equations[index, :3] p0 = face[0] p1 = face[1] p2 = face[2] n = np.cross(p1 - p0, p2 - p0) if np.dot(normals, n) < 0: hfaces[index][[1, 0]] = hfaces[index][[0, 1]] myfile = open(output_rawhull_obj_file, 'w') for index in range(hvertices.shape[0]): myfile.write('v ' + str(hvertices[index][0]) + ' ' + str(hvertices[index][1]) + ' ' + str(hvertices[index][2]) + '\n') for index in range(hfaces.shape[0]): myfile.write('f ' + str(hfaces[index][0]) + ' ' + str(hfaces[index][1]) + ' ' + str(hfaces[index][2]) + '\n') myfile.close() def edge_normal_test(vertices, faces, old_face_index_list, v0_ind, v1_ind): selected_old_face_list = [] central_two_face_list = [] for index in old_face_index_list: face = faces[index] face_temp = np.array(face).copy() face_temp = list(face_temp) if v0_ind in face_temp: face_temp.remove(v0_ind) if v1_ind in face_temp: face_temp.remove(v1_ind) if len( face_temp ) == 2: ### if left 2 points, then this face is what we need. selected_old_face = [ np.asarray(vertices[face[i]]) for i in range(len(face)) ] selected_old_face_list.append(np.asarray(selected_old_face)) if len( face_temp ) == 1: ##### if left 1 points, then this face is central face. central_two_face = [ np.asarray(vertices[face[i]]) for i in range(len(face)) ] central_two_face_list.append(np.asarray(central_two_face)) assert (len(central_two_face_list) == 2) if len(central_two_face_list) + len(selected_old_face_list) != len( old_face_index_list): print 'error!!!!!!' central_two_face_normal_list = [] neighbor_face_dot_normal_list = [] for face in central_two_face_list: n = np.cross(face[1] - face[0], face[2] - face[0]) n = n / np.sqrt(np.dot(n, n)) central_two_face_normal_list.append(n) avg_edge_normal = np.average(np.array(central_two_face_normal_list), axis=0) for face in selected_old_face_list: n = np.cross(face[1] - face[0], face[2] - face[0]) neighbor_face_dot_normal_list.append(np.dot(avg_edge_normal, n)) if (np.array(neighbor_face_dot_normal_list) >= 0.0 - 1e-5).all(): return 1 else: return 0 def compute_tetrahedron_volume(face, point): n = np.cross(face[1] - face[0], face[2] - face[0]) return abs(np.dot(n, point - face[0])) / 6.0 #### this is different from function: remove_one_edge_by_finding_smallest_adding_volume(mesh) #### add some test conditions to accept new vertex. #### if option ==1, return a new convexhull. #### if option ==2, return a new mesh (using trimesh.py) def remove_one_edge_by_finding_smallest_adding_volume_with_test_conditions( mesh, option): edges = mesh.get_edges() mesh.get_halfedges() faces = mesh.faces vertices = mesh.vs temp_list1 = [] temp_list2 = [] count = 0 for edge_index in range(len(edges)): edge = edges[edge_index] vertex1 = edge[0] vertex2 = edge[1] face_index1 = mesh.vertex_face_neighbors(vertex1) face_index2 = mesh.vertex_face_neighbors(vertex2) face_index = list(set(face_index1) | set(face_index2)) related_faces = [faces[index] for index in face_index] old_face_list = [] #### now find a point, so that for each face in related_faces will create a positive volume tetrahedron using this point. ### minimize c*x. w.r.t. A*x<=b c = np.zeros(3) A = [] b = [] for index in range(len(related_faces)): face = related_faces[index] p0 = vertices[face[0]] p1 = vertices[face[1]] p2 = vertices[face[2]] old_face_list.append(np.asarray([p0, p1, p2])) n = np.cross(p1 - p0, p2 - p0) #### Currently use this line. without this line, test_fourcolors results are not good. n = n / np.sqrt( np.dot(n, n) ) ##### use normalized face normals means distance, not volume A.append(n) b.append(np.dot(n, p0)) c += n ########### now use cvxopt.solvers.lp solver A = -np.asfarray(A) b = -np.asfarray(b) c = np.asfarray(c) cvxopt.solvers.options['show_progress'] = False #cvxopt.solvers.options['glpk'] = dict(msg_lev='GLP_MSG_OFF') #res = cvxopt.solvers.lp( cvxopt.matrix(c), cvxopt.matrix(A), cvxopt.matrix(b), solver='glpk' ) # After installing another version of lapacke.h, this one is goofed now!!! res = cvxopt.solvers.lp(cvxopt.matrix(c), cvxopt.matrix(A), cvxopt.matrix(b)) #res = linprog(-1*c, A_ub=A, b_ub=-1*b, method = 'simplex',options={'disp':False}) if res['status'] == 'optimal': newpoint = np.asfarray(res['x']).squeeze() ######## using objective function to calculate (volume) or (distance to face) as priority. # volume=res['primal objective']+b.sum() ####### manually compute volume as priority,so no relation with objective function tetra_volume_list = [] for each_face in old_face_list: tetra_volume_list.append( compute_tetrahedron_volume(each_face, newpoint)) volume = np.asarray(tetra_volume_list).sum() temp_list1.append((count, volume, vertex1, vertex2)) temp_list2.append(newpoint) count += 1 # else: # print 'cvxopt.solvers.lp is not optimal ', res['status'], np.asfarray( res['x'] ).squeeze() # if res['status']!='unknown': ### means solver failed # ##### check our test to see if the solver fails normally # if edge_normal_test(vertices,faces,face_index,vertex1,vertex2)==1: ### means all normal dot value are positive # print '!!!edge_normal_neighbor_normal_dotvalue all positive, but solver fails' if option == 1: if len(temp_list1) == 0: print 'all fails' hull = ConvexHull(mesh.vs) else: min_tuple = min(temp_list1, key=lambda x: x[1]) # print min_tuple final_index = min_tuple[0] final_point = temp_list2[final_index] # print 'final_point ', final_point new_total_points = mesh.vs new_total_points.append(final_point) hull = ConvexHull(np.array(new_total_points)) return hull if option == 2: if len(temp_list1) == 0: print 'all fails' else: min_tuple = min(temp_list1, key=lambda x: x[1]) # print min_tuple final_index = min_tuple[0] final_point = temp_list2[final_index] # print 'final_point ', final_point v1_ind = min_tuple[2] v2_ind = min_tuple[3] face_index1 = mesh.vertex_face_neighbors(v1_ind) face_index2 = mesh.vertex_face_neighbors(v2_ind) face_index = list(set(face_index1) | set(face_index2)) related_faces_vertex_ind = [ faces[index] for index in face_index ] old2new = mesh.remove_vertex_indices([v1_ind, v2_ind]) ### give the index to new vertex. new_vertex_index = current_vertices_num = len( old2new[old2new != -1]) ### create new face with new vertex index. new_faces_vertex_ind = [] for face in related_faces_vertex_ind: new_face = [ new_vertex_index if x == v1_ind or x == v2_ind else old2new[x] for x in face ] if len(list(set(new_face))) == len(new_face): new_faces_vertex_ind.append(new_face) ##### do not clip coordinates to[0,255]. when simplification done, clip. mesh.vs.append(final_point) ##### clip coordinates during simplification! # mesh.vs.append(final_point.clip(0.0,255.0)) for face in new_faces_vertex_ind: mesh.faces.append(face) mesh.topology_changed() return mesh # ************ compute ************ output_rawhull_obj_file = 'misc_param/temp' + "-rawconvexhull.obj" E_vertice_num = 4 import time start_time = time.clock() #images=np.asfarray(Image.open(input_image_path).convert('RGB')).reshape((-1,3)) all_colors = input_im.reshape((-1, 3)) ## insert a white and black pixel to make sure we got one [somtimes max-project does not have dark pixels] #all_colors[1,:] = np.asarray([0,0,0]) #all_colors[0,:] = np.asarray([191,191,191]) # white pixels are uninformative #hull=ConvexHull(images) hull = ConvexHull(all_colors) origin_hull = hull write_convexhull_into_obj_file(hull, output_rawhull_obj_file) mesh = TriMesh.FromOBJ_FileName(output_rawhull_obj_file) print '- Original hull vertices number:', len(mesh.vs) for i in range(500): old_num = len(mesh.vs) mesh = TriMesh.FromOBJ_FileName(output_rawhull_obj_file) #print len(mesh.vs) mesh = remove_one_edge_by_finding_smallest_adding_volume_with_test_conditions( mesh, option=2) newhull = ConvexHull(mesh.vs) write_convexhull_into_obj_file(newhull, output_rawhull_obj_file) pigments_colors = newhull.points[newhull.vertices].clip( 0, 255).round().astype(np.uint8) pigments_colors = pigments_colors.reshape( (pigments_colors.shape[0], 1, pigments_colors.shape[1])) #print pigments_colors.shape # add white to make sure (Not optimal, Heuristic) pigments_colors = np.vstack( (pigments_colors, np.asarray([191, 191, 191]).reshape(1, 1, 3))) white_index = [] black_index = [] #del_color = [] for i in range(pigments_colors.shape[0]): if pigments_colors[i, 0, 0] > 190.0 and pigments_colors[ i, 0, 1] > 190.0 and pigments_colors[i, 0, 2] > 190.0: #print '- White color detected and deleted' # dont wanna keep whie, not informative white_index.append(i) if pigments_colors[i, 0, 0] < 15.0 and pigments_colors[ i, 0, 1] < 15.0 and pigments_colors[i, 0, 2] < 15.0: black_index.append(i) #assert len(black_index) > 0 #assert len(white_index) < 2 # more than 1 white #if len(white_index) == 0: print '- No white pixels found, you got one extra layer, decrease number of colors (N)!' #print len(white_index) # make sure blck is the first color #print black_index, pigments_colors.shape #temp2 = pigments_colors[black_index,:] #pigments_colors[black_index,:] = pigments_colors[0,:] #pigments_colors[0,:] = temp2 #if 0 in set(white_index): # white_index[0] = black_index[0] # erase gray and white pigments_colors = np.delete(pigments_colors, white_index + black_index, axis=0) # insert [0, 0, 0] (Not optimal, Heuristic solution) pigments_colors = np.vstack( (np.asarray([0, 0, 0]).reshape(1, 1, 3), pigments_colors)) #print len(newhull.vertices) if pigments_colors.shape[ 0] == N + 1: # colors + black bakground + possible white #print 'FFFFF: ' #print pigments_colors color_vertices = np.asfarray( pigments_colors.reshape(pigments_colors.shape[0], 3)) break #if len(mesh.vs)==old_num or len(mesh.vs)<=E_vertice_num: #print '- Final vertices number', len(mesh.vs) #break #color_vertices = np.asfarray(pigments_colors.reshape(pigments_colors.shape[0],3)) newhull = ConvexHull(mesh.vs) write_convexhull_into_obj_file(newhull, output_rawhull_obj_file) end_time = time.clock() print 'time: ', end_time - start_time print '- Computed color vertices from the image:' print color_vertices print color_vertices.shape return color_vertices