diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5a80a12 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*_marker_genes.txt +*_scaled.csv \ No newline at end of file diff --git a/embryo-backend/Data/CS11.h5ad b/embryo-backend/Data/CS11.h5ad index 90e1410..b8cb597 100644 --- a/embryo-backend/Data/CS11.h5ad +++ b/embryo-backend/Data/CS11.h5ad @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:303f6b9a97c5b7e57bdd47eb286ff7d0c4eb5b1a416973c4e64b5d18bbb7d52c +oid sha256:7e1d1d9f21d310f47aed5762fa553025be93895a7c4e39c9c14dddeacfdd5a87 size 122218584 diff --git a/embryo-backend/Data/CS12.h5ad b/embryo-backend/Data/CS12.h5ad index 1d4b3ac..b04e33b 100644 --- a/embryo-backend/Data/CS12.h5ad +++ b/embryo-backend/Data/CS12.h5ad @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f93a286fdd164aff6b1311f78c0238bc1d97135f0124ad24d8918c1c69fcaeb4 +oid sha256:1925467fd995d5022e62bd4c37131aa037414e0b96f87451f331f20b964eb41e size 122242830 diff --git a/embryo-backend/Data/CS13.h5ad b/embryo-backend/Data/CS13.h5ad index 188a18d..6eea13e 100644 --- a/embryo-backend/Data/CS13.h5ad +++ b/embryo-backend/Data/CS13.h5ad @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eb96b812a21fb935cb9867e53e879278eaeda2400a6cbf78ad60095403c49d8b +oid sha256:4e9ff035e370b4f3a6f1869eacc9e1c5f1d1526720448514faaa96786cc65587 size 122238789 diff --git a/embryo-backend/Data/CS14.h5ad b/embryo-backend/Data/CS14.h5ad index 1d0f10a..871728a 100644 --- a/embryo-backend/Data/CS14.h5ad +++ b/embryo-backend/Data/CS14.h5ad @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4e707a18d729bd2895bb8879e7086ca423dae16a963360fbd6ccba9727b93569 +oid sha256:f56aeae91a58d706e4a9d113a7f841b724b8bf8fba20e5953bc6d0d9a168a51d size 122234748 diff --git a/embryo-backend/Data/CS15.h5ad b/embryo-backend/Data/CS15.h5ad index bb3a465..8c439a8 100644 --- a/embryo-backend/Data/CS15.h5ad +++ b/embryo-backend/Data/CS15.h5ad @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:981024ffaf294fb77031b6e19abd518d1c59aeae103570b98070d7b5d05ccef1 +oid sha256:c4af174517e35fc0b1deff0944a8edbcc29f84bdbeef23d8454e2ef148908a84 size 122230707 diff --git a/embryo-backend/Data/CS16.h5ad b/embryo-backend/Data/CS16.h5ad index be14795..791f9a0 100644 --- a/embryo-backend/Data/CS16.h5ad +++ b/embryo-backend/Data/CS16.h5ad @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:62b1e342f1fea9d8da09f13c8922cea958c3c7777e57e4f11f7deb69d9f85728 +oid sha256:50f9103ab6878710b21568dd444d238f7002b56c3a8f87fb9be7c0c943f09edc size 122234748 diff --git a/embryo-backend/Data/CS17.h5ad b/embryo-backend/Data/CS17.h5ad index 94ede02..7b767f9 100644 --- a/embryo-backend/Data/CS17.h5ad +++ b/embryo-backend/Data/CS17.h5ad @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1b4ce4f6eda6afed749f2a6bb9dfb101dab1915a5d113d1a59131db31dc9eb7c +oid sha256:2082571dd7c820cb7a27de92fbd654faa583f1ae3b46b08c0bc3a9a76b5a3bca size 122194338 diff --git a/embryo-backend/Data/CS18.h5ad b/embryo-backend/Data/CS18.h5ad index 6f21f05..2f34d8b 100644 --- a/embryo-backend/Data/CS18.h5ad +++ b/embryo-backend/Data/CS18.h5ad @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:649b6bc1efb5551a61e48e7713d9794e9ba34943d0a6d1b56c3b7e6ebf184eba +oid sha256:539c90285fc65f0a89a1063786bc9b8abb5438d06c8fb55230fc8c8c95782d86 size 122234748 diff --git a/embryo-backend/Data/CS20.h5ad b/embryo-backend/Data/CS20.h5ad index 130fb09..0284f4a 100644 --- a/embryo-backend/Data/CS20.h5ad +++ b/embryo-backend/Data/CS20.h5ad @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ebf6b3d364f028a53e427b49d80a7e1915539b3b2f4704e220ce3d5d22347128 +oid sha256:f99d32becb5e5a1eed2019ebbe3df49f2a536da9e149963056c1c720510f67c9 size 122234748 diff --git a/embryo-backend/Data/CS21.h5ad b/embryo-backend/Data/CS21.h5ad index baeda0c..9fbd636 100644 --- a/embryo-backend/Data/CS21.h5ad +++ b/embryo-backend/Data/CS21.h5ad @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:77e17b07fd16c2920eb15791c8d7408b77f38a5c1db2cbd1409639079a31fc23 +oid sha256:25e8015befb49ad0b229e54f0c31d8c9fe84139440043d8b6d98a89e8e6b51ab size 122238789 diff --git a/embryo-backend/Data/CS22.h5ad b/embryo-backend/Data/CS22.h5ad index b921468..481325f 100644 --- a/embryo-backend/Data/CS22.h5ad +++ b/embryo-backend/Data/CS22.h5ad @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b612b8ac80fbf646bee3eb5564a23723d4cb4bfd68af3380dee18c5267ae1271 +oid sha256:e71107729c29080ab49a70ecd9dd2526067cdbec2011506a3a284b887abea062 size 122226666 diff --git a/embryo-backend/Data/CS23.h5ad b/embryo-backend/Data/CS23.h5ad index f4f060a..625742f 100644 --- a/embryo-backend/Data/CS23.h5ad +++ b/embryo-backend/Data/CS23.h5ad @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:61e95ee79253a15c22a86530fb36f639fd65a4d840d3d61c8eab2086b9f518af +oid sha256:59c845b30b64ca8a489d00cffd617b256c4ab79769ce698719a48e5351e74ac2 size 122222625 diff --git a/embryo-backend/Data/glbTrans.py b/embryo-backend/Data/glbTrans.py index 386ef8f..07198ff 100644 --- a/embryo-backend/Data/glbTrans.py +++ b/embryo-backend/Data/glbTrans.py @@ -19,7 +19,7 @@ assert os.path.exists(gene_list_file), f"❌ 缺少基因名文件 {gene_list_fi all_gene_names = pd.read_csv(gene_list_file, header=None)[0].tolist() gene_names = all_gene_names[:n_genes] -# ==== 真实 marker 基因 ==== +# ==== marker 基因 ==== true_markers = { "Ectoderm": ["SOX2", "PAX6", "NES", "TUBB3", "OTX2"], "Mesoderm": ["TBXT", "MESP1", "HAND1", "GATA4", "PDGFRA"], @@ -30,6 +30,7 @@ true_markers = { # ==== 采样函数 ==== def sample_mesh(mesh, label, n_samples): + """采样点云 + 颜色 + 标签""" if use_surface_sampling: points, face_idx = trimesh.sample.sample_surface(mesh, n_samples) if hasattr(mesh.visual, "vertex_colors") and len(mesh.visual.vertex_colors) == len(mesh.vertices): @@ -63,7 +64,7 @@ for glb_name in glb_files: scene = trimesh.load(glb_path) if isinstance(scene, trimesh.Scene): for geom in scene.geometry.values(): - all_bounds.append(geom.bounds) # (min,max) + all_bounds.append(geom.bounds) else: all_bounds.append(scene.bounds) @@ -73,7 +74,7 @@ global_max = np.max(all_bounds[:,1,:], axis=0) global_size = np.max(global_max - global_min) print(f"🌍 统一缩放基准: global_size={global_size}") -# ==== Step 2: 处理单个 GLB ==== +# ==== Step 2: 处理单个 GLB(应用全局变换) ==== def process_glb(glb_path, sample_name): scene = trimesh.load(glb_path) all_points, all_colors, all_labels = [], [], [] @@ -83,7 +84,21 @@ def process_glb(glb_path, sample_name): for name, geom in scene.geometry.items(): ratio = len(geom.vertices) / total_points n_samples = max(1, int(N_total * ratio)) - p, c, l = sample_mesh(geom, name, n_samples) + + # ✅ 保护性获取变换矩阵 + try: + transform = scene.graph.get(name)[0] + except Exception: + print(f"⚠️ {sample_name}: 子网格 {name} 没有变换路径,使用单位矩阵") + transform = np.eye(4) + + # ✅ 应用全局变换 + verts_world = trimesh.transform_points(geom.vertices, transform) + + # ✅ 生成全局 mesh 进行采样 + mesh_world = trimesh.Trimesh(vertices=verts_world, faces=geom.faces, process=False) + p, c, l = sample_mesh(mesh_world, name, n_samples) + all_points.append(p) all_colors.append(c) all_labels.append(l) @@ -101,26 +116,21 @@ def process_glb(glb_path, sample_name): idx = np.random.choice(len(points), N_total, replace=False) points, colors, labels = points[idx], colors[idx], labels[idx] - # ✅ 平移到中心点 + # ✅ 一次性中心化 + 统一缩放 center = points.mean(axis=0) points_centered = points - center - - # ✅ 统一缩放(保持原始比例) points_scaled = points_centered / global_size - # ✅ 如需修正坐标系方向,可启用以下行(示例:交换Y和Z) - # points_scaled = points_scaled[:, [0, 2, 1]] - # points_scaled[:, 1] *= -1 - df = pd.DataFrame(points_scaled, columns=["x","y","z"]) df["r"], df["g"], df["b"] = colors[:,0], colors[:,1], colors[:,2] df["label"] = labels csv_file = os.path.join(script_dir, f"{sample_name}_point_cloud_30000_centered_scaled.csv") df.to_csv(csv_file, index=False) - print(f"✅ 已导出 {csv_file} (中心化 & 统一大小, 保持比例)") + print(f"✅ 已导出 {csv_file} (修正组织错位, 中心化 & 统一比例)") return df + # ==== Step 3: 生成 h5ad ==== def create_h5ad(df, sample_name): points = df[['x','y','z']].to_numpy() diff --git a/pyproject.toml b/pyproject.toml index 27c2fdb..6c5f84a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,4 +9,5 @@ dependencies = [ "flask>=3.1.1", "flask-cors>=6.0.1", "pandas>=2.3.1", + "trimesh>=4.7.1", ] diff --git a/uv.lock b/uv.lock index 7c01d4d..48c7dc4 100644 --- a/uv.lock +++ b/uv.lock @@ -100,6 +100,7 @@ dependencies = [ { name = "flask" }, { name = "flask-cors" }, { name = "pandas" }, + { name = "trimesh" }, ] [package.metadata] @@ -108,6 +109,7 @@ requires-dist = [ { name = "flask", specifier = ">=3.1.1" }, { name = "flask-cors", specifier = ">=6.0.1" }, { name = "pandas", specifier = ">=2.3.1" }, + { name = "trimesh", specifier = ">=4.7.1" }, ] [[package]] @@ -421,6 +423,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] +[[package]] +name = "trimesh" +version = "4.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/95/05/50656189ebd0563b2130ddd9b609b1db99eb241687dac0d2585882c35c33/trimesh-4.7.1.tar.gz", hash = "sha256:3863c2b2281fc7a99bf0b5de4a0011229bde4663babc0c1b53a1f855149ec898", size = 800778, upload-time = "2025-07-16T20:24:50.248Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/64/99e785dd4bb5796881b5686b0869a6ebf75b1b7d00932af577eb343c4f72/trimesh-4.7.1-py3-none-any.whl", hash = "sha256:338c938ae78ad5b4d08dd6ceaa739498a47627bf0073147ee9a384ddd7435267", size = 709034, upload-time = "2025-07-16T20:24:47.256Z" }, +] + [[package]] name = "typing-extensions" version = "4.14.1"