[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-79809":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":10,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":24,"readmeContent":25,"aiSummary":26,"trendingCount":16,"starSnapshotCount":16,"syncStatus":27,"lastSyncTime":28,"discoverSource":29},79809,"PhenoPixel","ikeda042\u002FPhenoPixel","ikeda042","PhenoPixel: A web-based bioimage analysis platform for bacterial single-cell microscopy analytics.","",null,"TypeScript",298,4,151,1,0,3,191,50.6,false,"main",true,[],"2026-06-12 04:01:25","# PhenoPixel\n\nPhenoPixel is a FastAPI + React application for microscopy single-cell\nextraction, annotation, visualization, and batch phenotype analysis. It is\ndesigned around ND2 microscopy workflows: upload an ND2 file, extract cell\ncontours, clean labels, inspect individual cells, and export population-level\nshape and fluorescence descriptors.\n\nThe montage below shows a label-1 cell population from `microscope_data.db`.\nThe overlay renders `fluo1` as magenta and `fluo2` as green without scale bars,\nwith display intensity balanced per cell while avoiding saturation.\n\n![Manual Label 1 Overlay Fluo montage](docs\u002Fimages\u002Fmanual-label1-overlay-fluo-montage.png)\n\n![Manual Label 1 Replot montage](docs\u002Fimages\u002Fmanual-label1-replot-montage.png)\n\n![Cell extraction preview](docs\u002Fscreen-records\u002Fcell-extraction.preview.gif)\n\n## Key Features\n\n| Area | What PhenoPixel provides |\n| --- | --- |\n| ND2 management | Upload, list, inspect metadata, download, delete, and parse `.nd2` files. |\n| Cell extraction | Generate cropped cell images, contours, preview frames, and SQLite databases. |\n| Annotation | Review auto-detected cells and relabel single cells or debris in bulk. |\n| Cell viewer | Inspect phase, fluorescence, overlays, replot views, heatmaps, map views, distributions, and raw images per cell. |\n| Bulk analysis | Export and visualize cell length, area, fluorescence intensity summaries, heatmap vectors, contours, Map256 strips, raw intensities, and JSON\u002FCSV data. |\n| Research reporting | Keep database files, exports, screenshots, and method formulas close to the analysis code for reproducible reporting. |\n\n## Requirements\n\n| Component | Notes |\n| --- | --- |\n| Python | Local launch examples use `python3.14`; the Docker backend image uses Python 3.11. |\n| Node.js \u002F npm | Required for the React frontend, Docusaurus docs build, and Storybook screenshots. Dependency versions are locked in `frontend\u002Fpackage-lock.json`. |\n| SQLite | Used for extracted cell databases through SQLAlchemy. |\n| OpenCV system libraries | Local installs use `opencv-python`; Docker also installs `libgl1` and `libglib2.0-0`. |\n\n## Quick Start\n\nRun the backend and frontend from the repository root in separate terminals.\nThe local quick-start path uses `python3.14`; the Docker backend image uses\nPython 3.11.\n\n### Backend\n\n```sh\npython3.14 -m venv venv\nsource .\u002Fvenv\u002Fbin\u002Factivate\ncd backend\npip install -r requirements.txt\npython main.py\n```\n\n### Frontend\n\n```sh\ncd frontend\nnpm install\nnpm run dev\n```\n\nIf npm reports peer dependency conflicts around Vite and Storybook, use:\n\n```sh\nnpm install --legacy-peer-deps\n```\n\n### Local URLs\n\n| Service | URL |\n| --- | --- |\n| Backend | http:\u002F\u002Flocalhost:3000 |\n| Frontend dev server | http:\u002F\u002Flocalhost:3001 |\n| API base | http:\u002F\u002Flocalhost:3000\u002Fapi\u002Fv1 |\n| Swagger UI | http:\u002F\u002Flocalhost:3000\u002Fapi\u002Fv1\u002Fdocs |\n| OpenAPI JSON | http:\u002F\u002Flocalhost:3000\u002Fapi\u002Fv1\u002Fopenapi.json |\n| Health check | http:\u002F\u002Flocalhost:3000\u002Fapi\u002Fv1\u002Fhealth |\n\n## Input Data\n\n| Item | Notes |\n| --- | --- |\n| Primary input | `.nd2` files. Upload through the UI or place them under `backend\u002Fapp\u002Fnd2files\u002F`. |\n| Filename rules | Only `.nd2` is accepted; path components are stripped and dots in stems are normalized during processing. |\n| Channel\u002Flayer modes | `single`, `dual`, `dual(reversed)`, `triple`, and `quad` are supported by the extraction UI\u002FAPI. |\n| Metadata | ND2 metadata can be viewed from the ND2 Manager. Channel count may be inferred when the metadata exposes it. |\n| Time\u002FZ data | The parser can expose ND2 frame metadata, but cell extraction expects the selected layer mode to match the frame\u002Fchannel organization. Validate previews before running large jobs. |\n\n## Workflow\n\n### 1. ND2 Manager\n\nManage ND2 files: upload datasets, inspect metadata, delete old files, and open\na selected ND2 file in Cell Extraction.\n\n![ND2 manager](docs\u002Fscreenshots\u002Fnd2manager1.png)\n\n### 2. Cell Extraction\n\nChoose the layer mode, objective scale, Canny threshold (`param1`), crop size,\nand Auto Annotation setting, then start extraction. The backend creates contour\npreviews and one or more SQLite databases for downstream analysis.\n\n![Cell extraction setup](docs\u002Fscreenshots\u002Fcell_extraction1.png)\n\nWhen extraction finishes, review the preview frames. If contours are poor,\nadjust parameters and re-extract.\n\n![Auto annotation processing](docs\u002Fscreenshots\u002Fcell_extraction2.png)\n\n![Extraction results and next actions](docs\u002Fscreenshots\u002Fcell_extraction3.png)\n\n### 3. Database Manager\n\nCell databases generated by extraction can be uploaded, downloaded, renamed,\ndeleted, and opened for cell-level review.\n\n![Database manager](docs\u002Fscreenshots\u002Fdatabase_manager1.png)\n\n![Database access](docs\u002Fscreenshots\u002Fdatabase_manager2.png)\n\nThe cell viewer function panel provides these modes:\n\n| Mode | Description |\n| --- | --- |\n| `Contour` | Show extracted contour coordinates. |\n| `Replot` | Replot a cell in its aligned coordinate system. |\n| `Overlay` | Overlay the contour on the default cell image. |\n| `Overlay Raw` | Overlay fluorescence without contour masking on the raw view. |\n| `Overlay Fluo` | Compose fluorescence channels with selectable colors. |\n| `Heatmap` | Visualize centerline-projected fluorescence intensity. |\n| `Map 256` | Render a 256-level mapped fluorescence view. |\n| `Map Raw` | Render the mapped view at native pixel scale. |\n| `Distribution` | Plot the intensity distribution for the selected cell\u002Fchannel. |\n\n![Function panel modes](docs\u002Fscreenshots\u002Fdatabase_manager3.png)\n\n`Overlay Raw` places fluorescence-channel signal on top of the PH image, making\nit possible to check fluorescence localization against the original cell\nmorphology.\n\n![PH image with fluorescence overlay](docs\u002Fscreenshots\u002Fdatabase_manager4.png)\n\n`Overlay Fluo` shows the fluorescence channels as an overlay without the PH\nbackground, which is useful for inspecting signal overlap and channel-specific\npatterns.\n\n![Fluorescence channel overlay](docs\u002Fscreenshots\u002Fdatabase_manager5.png)\n\n`Heatmap` projects fluorescence intensity along the selected cell's long axis.\nThe target fluorescence channel can be selected before plotting, so the same\ncell can be compared across channels.\n\n![Single-cell fluorescence heatmap](docs\u002Fscreenshots\u002Fdatabase_manager6.png)\n\n`Map 256` renders fluorescence information as a 256-level intensity map. This\nview preserves the spatial pattern inside each cell and is useful for examining\nsubcellular localization, such as Nucleoid positioning.\n\n![Single-cell Map256 view](docs\u002Fscreenshots\u002Fdatabase_manager7.png)\n\nThe same Map256 representation can also be used at population scale. The\nexample below arranges Map256 views from the `Label 1` population in\n`microscope_data.db`, summarizing Nucleoid localization across the selected cell\ngroup.\n\n![Population Map256 nucleoid localization](docs\u002Fscreenshots\u002FMap256.png)\n\n`Distribution` shows a histogram of intracellular fluorescence intensities for\nthe selected cell\u002Fchannel.\n\n![Single-cell fluorescence intensity distribution](docs\u002Fscreenshots\u002Fdatabase_manager8.png)\n\n### 4. Annotation\n\nAuto-detected contours may include debris or merged cells. Use Annotation to\nmove cells between `N\u002FA` and analysis labels such as `Label 1`. Click cells\nindividually or use Shift-drag to select multiple cells before applying a label.\n\n![Annotation cleanup](docs\u002Fscreenshots\u002Fannotation1.png)\n\n![Annotation labeling](docs\u002Fscreenshots\u002Fannotation2.png)\n\n![Annotation labeling multiple](docs\u002Fscreenshots\u002Fannotation3.png)\n\n### 5. Bulk Engine\n\nAfter annotation, use Bulk Engine to run population-level analysis on a selected\nlabel. Return to Annotation if non-single cells remain in the selected group.\n\n![Bulk engine selection](docs\u002Fscreenshots\u002Fbulk1.png)\n\n![Bulk engine analysis](docs\u002Fscreenshots\u002Fbulk2.png)\n\nBulk Engine modes:\n\n| Mode | Description |\n| --- | --- |\n| `Cell length` | Measure cell length in micrometers from contour geometry and stored pixel size. |\n| `Cell area` | Export cell area in pixels squared. |\n| `Normalized median` | Compute cellwise median intensity after max normalization. |\n| `FITC aggregation ratio` | Report the fraction of cells below the configured normalized-median threshold. |\n| `Entropy` | Quantify fluorescence distribution with entropy \u002F sparsity-style metrics. |\n| `Heatmap` | Generate centerline heatmap vectors and absolute\u002Frelative heatmap plots. |\n| `Contours` | Visualize aligned contours and export transformed contour coordinates. |\n| `Map256` | Render population-level Map256 strips or contour maps. |\n| `Raw data` | Export raw pixel intensities inside each contour. |\n\nJSON and CSV exports are available for downstream analysis.\n\n![Bulk engine analysis modes](docs\u002Fscreenshots\u002Fbulk3.png)\n\nFor example, `Heatmap` aggregates and visualizes fluorescence localization for\nall cells in the selected label.\n\n![Bulk engine heatmap example](docs\u002Fscreenshots\u002Fbulk4.png)\n\n`Contours` mode focuses on contour geometry only. It exports aligned contour\ncoordinates as JSON or CSV, making it easier to prototype and validate\nalgorithms that use cell outline information without carrying fluorescence\nimages or raw intensity data through the analysis pipeline.\n\n![Bulk engine contour export](docs\u002Fscreenshots\u002Fbulk5.png)\n\n## Output Data\n\n| Output | Location \u002F format |\n| --- | --- |\n| Uploaded ND2 files | `backend\u002Fapp\u002Fnd2files\u002F` |\n| Cell databases | `backend\u002Fapp\u002Fdatabases\u002F\u003Cnd2_stem>.db` |\n| Extracted contour previews | `backend\u002Fapp\u002Fextracted_data\u002F\u003Cnd2_stem>\u002F\u003Cframe>.png` |\n| Cell table | SQLite table `cells`, including `cell_id`, `manual_label`, `perimeter`, `area`, `img_ph`, `img_fluo1`, `img_fluo2`, `contour`, center coordinates, objective, and pixel size. |\n| Bulk exports | JSON\u002FCSV\u002FPNG responses from Bulk Engine endpoints or browser downloads. |\n| Frontend production build | `frontend\u002Fdist\u002F`; the backend serves this folder when it exists. |\n\n## Default Parameters\n\n| Parameter | Default \u002F current behavior |\n| --- | --- |\n| Extraction threshold `param1` | `130` |\n| Cell crop size | `200` px |\n| Default layer mode | `dual` in the UI |\n| Auto Annotation | On by default in the UI |\n| Auto Annotation width screen | second PCA variance `lambda_2 \u003C= 120` |\n| Auto Annotation convexity screen | `hull_perimeter \u002F perimeter > 0.85` |\n| Extraction concurrency | `CELLEXTRACTION_MAX_CONCURRENCY`, default `2` |\n| Objective presets | `100x = 0.065 um\u002Fpx`, `60x = 0.108 um\u002Fpx` |\n| Heatmap vector bins | `35` |\n| Centerline polynomial degree | `4` unless a request overrides it |\n| FITC aggregation cutoff | `0.7414` |\n\n## Methods\n\nThe quantitative routines in PhenoPixel follow a common single-cell analysis\npipeline: detect a contour from the phase-contrast image, re-parameterize the\ncell in its intrinsic coordinate system, and compute shape or fluorescence\ndescriptors that are directly comparable across cells. Let\n$C = \\{(x_i, y_i)\\}_{i=1}^n$ be the contour points of one cell and let\n$\\Omega_C$ be the set of pixels inside that contour.\n\n### Auto Annotation Contour Screen\n\nWhen Auto Annotation is `On`, an additional post-processing step runs after\nextraction to automatically separate cells from debris.\n\nThe current implementation is a contour-only heuristic. After a contour\n$C = \\{(x_i, y_i)\\}_{i=1}^N$ is extracted, the backend computes two geometric\nscores and assigns `Label 1` only when both pass their thresholds.\n\nFirst, it measures how thick the contour is in the direction orthogonal to the\nmajor axis. Let\n\n$$\n\\Sigma_C =\n\\frac{1}{N-1}\n\\sum_{i=1}^{N}\n(\\mathbf{p}_i - \\bar{\\mathbf{p}})\n(\\mathbf{p}_i - \\bar{\\mathbf{p}})^{\\mathsf{T}},\n\\qquad\n\\mathbf{p}_i = (x_i, y_i)^{\\mathsf{T}}.\n$$\n\nIf the eigenvalues of $\\Sigma_C$ are $\\lambda_1 \\ge \\lambda_2$, Auto Annotation\nuses the smaller one, $\\lambda_2$, as a width \u002F lateral-spread proxy and accepts\nonly contours satisfying\n\n$$\n\\lambda_2 \\le 120.\n$$\n\nSecond, it measures contour convexity from perimeter ratios. If $P(C)$ is the\ncontour perimeter and $P(\\mathrm{Hull}(C))$ is the perimeter of its convex hull,\nthe code defines\n\n$$\n\\kappa(C) = \\frac{P(\\mathrm{Hull}(C))}{P(C)}.\n$$\n\nBecause irregular debris or merged objects tend to have a perimeter much longer\nthan their convex hull, they produce smaller $\\kappa$. The contour is accepted\nonly when\n\n$$\n\\kappa(C) > 0.85.\n$$\n\nThe final Auto Annotation score can be written as\n\n$$\ns(C) = \\mathbf{1}[\\lambda_2 \\le 120] \\, \\mathbf{1}[\\kappa(C) > 0.85].\n$$\n\nAuto Annotation assigns `Label 1` when $s(C) = 1$ and `N\u002FA` otherwise. In other\nwords, it keeps contours that are both laterally compact and close to convex,\nand it filters out broad, jagged, or debris-like shapes before manual review.\n\n### 1. Contour Extraction, Principal Axis, and Basis Transform\n\nContours are extracted from phase-contrast images with a Canny-based pipeline.\nThe major elongation axis is estimated from the covariance of contour\ncoordinates,\n\n$$\n\\Sigma =\n\\begin{pmatrix}\n\\mathrm{Var}[X_1] & \\mathrm{Cov}[X_1, X_2] \\\\\n\\mathrm{Cov}[X_1, X_2] & \\mathrm{Var}[X_2]\n\\end{pmatrix},\n$$\n\nand the principal direction is the solution of\n\n$$\n\\mathbf{w}^* = \\underset{\\|\\mathbf{w}\\| = 1}{\\mathrm{arg\\,max}} \\mathbf{w}^{\\mathsf{T}} \\Sigma \\mathbf{w},\n\\qquad\n\\Sigma \\mathbf{w} = \\lambda \\mathbf{w}.\n$$\n\nIf $Q = (\\mathbf{v}_1\\ \\mathbf{v}_2)$ is the orthonormal eigenvector basis,\ncoordinates are transformed to the cell-aligned frame by\n\n$$\n\\mathbf{u} = Q^{\\mathsf{T}} \\mathbf{x},\n\\qquad\n\\mathbf{x} = Q \\mathbf{u}.\n$$\n\nThis removes arbitrary image rotation and makes bent or filamentous cells easier\nto model analytically.\n\nBecause $Q$ is orthonormal, this basis conversion also preserves Euclidean\nlength. For any vector $\\mathbf{x}$ and its transformed coordinate\n$\\mathbf{u} = Q^{\\mathsf{T}}\\mathbf{x}$,\n\n$$\n\\|\\mathbf{u}\\|^2\n= \\mathbf{u}^{\\mathsf{T}}\\mathbf{u}\n= (Q^{\\mathsf{T}}\\mathbf{x})^{\\mathsf{T}} (Q^{\\mathsf{T}}\\mathbf{x})\n= \\mathbf{x}^{\\mathsf{T}} Q Q^{\\mathsf{T}} \\mathbf{x}\n= \\mathbf{x}^{\\mathsf{T}} \\mathbf{x}\n= \\|\\mathbf{x}\\|^2,\n$$\n\nsince $Q^{\\mathsf{T}}Q = QQ^{\\mathsf{T}} = I$. Therefore distances measured\nbefore and after the basis transform are identical.\n\n### 2. Centerline Fitting and Cell Length\n\nIn the aligned frame, the cell centerline is approximated by a $k$-th order\npolynomial\n\n$$\n\\hat{f}(u_1) = \\theta^{\\mathsf{T}} \\phi(u_1),\n\\qquad\n\\theta = (W^{\\mathsf{T}} W)^{-1} W^{\\mathsf{T}} f.\n$$\n\nFor a curved cell, the thesis formulation defines cell length as the arc length\nbetween the two contour-centerline intersection points:\n\n$$\nL = \\int_{u_{1,a}}^{u_{1,b}}\n\\sqrt{1 + (\\frac{d\\hat{f}}{du_1})^2}\\,du_1.\n$$\n\n![Centerline fitting](docs\u002Fimages\u002Fmethod-centerline-fit.png)\n\nIn the current backend implementation, `Cell length` is returned as a robust PCA\nmajor-axis extent of pixels inside the contour and converted with the stored\npixel size. For the 100x preset, this is:\n\n$$\nL_{\\mathrm{API}} \\approx (\\max_i \\pi_i - \\min_i \\pi_i) \\times 0.065.\n$$\n\n### 3. Cell Area and Raw Pixel Export\n\nCell area is the area enclosed by the contour,\n\n$$\nA(C) = \\iint_{\\Omega_C} 1\\,dA,\n$$\n\nwhich is stored during extraction and reported by `Cell area`. `Raw data`\nexports the unaggregated intensity set\n\n$$\n\\{ I(p) \\mid p \\in \\Omega_C \\}\n$$\n\nfor the selected channel.\n\n### 4. Fluorescence Vectorization Along the Centerline\n\nFor each intracellular pixel $(p_i, q_i)$ with intensity $G(p_i, q_i)$, the\nnearest point on the fitted centerline is found by\n\n$$\nu_{1,i}^* = \\underset{u_1 \\in [u_{1,a}, u_{1,b}]}{\\mathrm{arg\\,min}}\n[(u_1 - p_i)^2 + (\\hat{f}(u_1) - q_i)^2].\n$$\n\nThis position is converted to arc length,\n\n$$\n\\ell(u_1) = \\int_{u_{1,a}}^{u_1} \\sqrt{1 + (\\hat{f}'(t))^2}\\,dt,\n\\qquad\n\\ell_i^* = \\ell(u_{1,i}^*).\n$$\n\nTo obtain a fixed-dimensional descriptor, the arc-length interval $[0, L]$ is\ndivided into $n$ bins and max-pooled:\n\n$$\ng_j = \\max \\{ G(p_i, q_i) \\mid \\ell_i^* \\in I_j \\}.\n$$\n\nIf no projected pixel falls into $I_j$, we set $g_j = 0$. The resulting\nfixed-length localization vector is\n\n$$\n\\mathbf{g} = (g_1, \\dots, g_n)^{\\mathsf{T}}.\n$$\n\nThe current implementation uses $n = 35$ and a default polynomial degree of\n$k = 4$. `Heatmap` visualizes these peak vectors either in absolute-length\ncoordinates or in relative-position coordinates.\n\n![Peak-vector heatmap construction](docs\u002Fimages\u002Fmethod-peak-vectorization.png)\n\n### 5. Map256 Spatial Intensity Mapping\n\n`Map 256` keeps more spatial information than the 35-bin heatmap vector. It uses\nthe same cell-aligned coordinate system and polynomial centerline, but instead\nof reducing each longitudinal bin to a single peak value, it remaps every\nintracellular fluorescence pixel onto a two-dimensional long-axis \u002F lateral-axis\nimage.\n\nBefore mapping, the selected fluorescence image is converted to grayscale and\nbackground-subtracted with a morphological opening:\n\n$$\nI_{\\mathrm{bg}} = I - \\mathrm{open}_{21 \\times 21}(I).\n$$\n\nFor each pixel $\\mathbf{u}_i = (u_{1,i}, u_{2,i})$ inside the contour, the\nnearest point on the fitted centerline $\\hat{f}$ is found as\n\n$$\nt_i^{\\star} =\n\\underset{t \\in [u_{1,a}, u_{1,b}]}{\\mathrm{arg\\,min}}\n\\left[(t - u_{1,i})^2 + (\\hat{f}(t) - u_{2,i})^2\\right].\n$$\n\nThe projected long-axis coordinate is the centerline arc length,\n\n$$\np_i =\n\\int_{u_{1,a}}^{t_i^{\\star}}\n\\sqrt{1 + (\\hat{f}'(t))^2}\\,dt,\n$$\n\nand the signed lateral coordinate is\n\n$$\nd_i =\n\\mathrm{sign}(u_{2,i} - \\hat{f}(t_i^{\\star}))\n\\sqrt{(t_i^{\\star} - u_{1,i})^2 + (\\hat{f}(t_i^{\\star}) - u_{2,i})^2}.\n$$\n\nThese coordinates define a high-resolution map\n$H \\in \\mathbb{R}^{h \\times w}$, where\n\n$$\nw = \\lceil \\max_i p_i - \\min_i p_i \\rceil + 1,\n\\qquad\nh = \\lceil \\max_i d_i - \\min_i d_i \\rceil + 1.\n$$\n\nEach intracellular pixel is assigned to integer map coordinates\n\n$$\nx_i = \\lfloor p_i - \\min_j p_j \\rfloor,\n\\qquad\ny_i = \\lfloor d_i - \\min_j d_j \\rfloor,\n$$\n\nand intensities are max-pooled into the mapped image:\n\n$$\nH(y_i, x_i) =\n\\max\\left(H(y_i, x_i), I_{\\mathrm{bg}}(\\mathbf{u}_i)\\right).\n$$\n\nThe implementation also writes the same value to the four direct neighbors\n$(y_i \\pm 1, x_i)$ and $(y_i, x_i \\pm 1)$ when they are inside the map. This\nsmall local expansion reduces holes caused by integer projection.\n\nFor `Map 256`, the high-resolution map is resized by nearest-neighbor\ninterpolation to a fixed display size:\n\n$$\nM_c \\in \\mathbb{R}^{256 \\times 1024}\n= \\mathrm{resize}_{\\mathrm{nearest}}(H_c).\n$$\n\nThe display image is then converted to 8-bit intensity,\n\n$$\n\\tilde{M}_c =\n255 \\cdot\n\\frac{M_c - \\min(M_c)}\n{\\max(M_c) - \\min(M_c)},\n$$\n\nwith a zero image used when the map has no intensity range. `Map Raw` keeps the\nnative high-resolution map before the fixed-size resize. The Jet view applies a\npseudocolor map to the same normalized intensity image.\n\nFor population-level Map256 contour plots, the backend first builds one map per\ncell. To make the population summary less sensitive to arbitrary left\u002Fright or\ntop\u002Fbottom orientation, each cell contributes four symmetric variants: the\noriginal map, left-right flip, top-bottom flip, and both flips. The population\nmean map is\n\n$$\n\\bar{M} =\n\\frac{1}{4N}\n\\sum_{c=1}^{N}\n\\left[\nM_c + F_x(M_c) + F_y(M_c) + F_y(F_x(M_c))\n\\right],\n$$\n\nwhere $F_x$ and $F_y$ denote horizontal and vertical flips. In `relative` mode,\neach cell map is normalized before averaging; in `absolute` mode, the\nbackground-subtracted raw intensities are averaged. This makes Map256 useful for\nsummarizing subcellular localization patterns, such as Nucleoid positioning,\nacross a labeled cell population. The square montage below was generated from\nall `Label 1` cells in the current `microscope_data.db`.\n\n![Population Map256 nucleoid localization](docs\u002Fscreenshots\u002FMap256.png)\n\n### 6. Normalized Median and Aggregation-Style Scores\n\nFor any selected channel, intensities inside a cell are normalized by the\ncellwise maximum,\n\n$$\n\\tilde{I}_i = \\frac{I_i}{\\max_{p \\in \\Omega_C} I(p)},\n\\qquad\nm(C) = \\mathrm{median}(\\tilde{I}_i).\n$$\n\nThis scalar is reported by `Normalized median`. A population-level aggregation\nscore can then be written as\n\n$$\nR(\\tau) = \\frac{1}{N} \\sum_{c=1}^{N} \\mathbf{1}[m(C_c) \u003C \\tau].\n$$\n\nThe current `FITC aggregation ratio` plot uses this form with a default cutoff\n$\\tau = 0.7414$. In the thesis experiments, the same normalized-median idea was\nalso used for IbpA-GFP and TorA-GFP abnormal-localization calls, with an example\nthreshold of $m \\le 0.6$ for those datasets.\n\n### 7. Thesis-Specific Phenotype Calls\n\nFor HU-GFP compaction, a 35-bin peak vector is first computed and summarized as\n\n$$\ns(C) = \\sum_{j=1}^{35} g_j.\n$$\n\nUsing the control population, the abnormality threshold is defined by the 5th\npercentile,\n\n$$\n\\tau_{\\mathrm{HU}} = Q_{0.05}(\\{ s(C_c^{\\mathrm{ctrl}}) \\}),\n$$\n\nand the HU aggregation ratio is the fraction of cells with\n$s(C) \u003C \\tau_{\\mathrm{HU}}$.\n\nFor PI permeability, the mean intracellular PI intensity is\n\n$$\n\\mu(C) = \\frac{1}{|\\Omega_C|} \\sum_{p \\in \\Omega_C} I_{\\mathrm{PI}}(p),\n$$\n\nwith a control-derived positivity threshold\n\n$$\n\\tau_{\\mathrm{PI}} = Q_{0.95}(\\{ \\mu(C_c^{\\mathrm{ctrl}}) \\}).\n$$\n\nThe PI-positive fraction is then the proportion of cells satisfying\n$\\mu(C) > \\tau_{\\mathrm{PI}}$.\n\n## Research Use \u002F Citation\n\nThis repository is maintained to support reproducible reporting in research\npapers. If you cite this software in a manuscript, include:\n\n- **Software name**: PhenoPixel\n- **Author**: Yunosuke Ikeda\n- **Contact**: d263846@hiroshima-u.ac.jp\n- **Repository URL**: this repository URL\n- **Version evidence**: Git commit hash used in the analysis\n- **Access date**: date you accessed the repository\n\nRecommended citation:\n\n```text\nIkeda, Y. PhenoPixel: microscopy single-cell extraction and batch phenotype analysis software.\nGitHub repository. URL: \u003Crepository-url> (accessed \u003CYYYY-MM-DD>), commit \u003Ccommit-hash>.\n```\n\nFor reproducibility, report OS\u002FPython\u002FNode versions, dependency snapshots, ND2\nmetadata or acquisition conditions, extraction parameters, labeling criteria,\nBulk Engine modes, thresholds, export settings, and the exact commit hash.\n\n## Development And Quality Checks\n\nBackend checks:\n\n```sh\nsource .\u002Fvenv\u002Fbin\u002Factivate\nPYTHONPATH=backend python -m unittest discover backend\u002Ftests\n```\n\nFrontend checks:\n\n```sh\ncd frontend\nnpm run build\nnpm run lint\n```\n\nScreenshot\u002Fstorybook assets:\n\n```sh\n.\u002Fdocs\u002Fmake_screenshots.sh\n```\n\n## Production Build\n\nBuild the frontend before serving the app from the backend:\n\n```sh\ncd frontend\nnpm install --legacy-peer-deps\nnpm run build\ncd ..\u002Fbackend\nsource ..\u002Fvenv\u002Fbin\u002Factivate\npython main.py\n```\n\nWhen `frontend\u002Fdist\u002Findex.html` exists, `backend\u002Fmain.py` serves the SPA and\nstatic assets alongside the `\u002Fapi\u002Fv1` API.\n\n## Docker Deploy (Traefik)\n\n`docker\u002Fcompose.yaml` starts Traefik and the backend container. The current\ncompose file exposes the backend under `\u002Fapi\u002Fv1\u002F` and mounts persistent backend\ndata directories.\n\nCreate `backend\u002F.env` first:\n\n```sh\ncp backend\u002F.env.template backend\u002F.env\n```\n\nEnvironment variables used by local\u002FDocker deployment:\n\n| Variable | Used by | Meaning |\n| --- | --- | --- |\n| `SLACK_WEHBOOK_URL` | Backend | Optional Slack webhook URL for job notifications. The variable name intentionally matches the current code\u002Ftemplate spelling. |\n| `BASE_PATH` | Backend | Optional frontend base URL used in Slack notification links. |\n| `CELLEXTRACTION_MAX_CONCURRENCY` | Backend | Optional extraction job concurrency limit; defaults to `2`. |\n| `SERVER_HOST` | Docker compose \u002F Traefik | Hostname routed to the backend; compose defaults to `localhost` when unset. |\n| `TRAEFIK_ACME_EMAIL` | Docker compose \u002F Traefik | Email address for Let's Encrypt certificate registration. |\n\nStart the stack:\n\n```sh\ncd docker\ndocker compose -f compose.yaml up -d --build\n```\n\nTraefik uses ports `80` and `443`. Access the hostname set in `SERVER_HOST`;\nthe API is exposed under `\u002Fapi\u002Fv1`.\n\n## Troubleshooting\n\n| Symptom | What to try |\n| --- | --- |\n| Port already in use | Backend defaults to `3000`, frontend to `3001`, docs dev server to `3002`; stop the existing process or change the port. |\n| `eslint: command not found` | Install frontend dependencies with `npm install` or `npm install --legacy-peer-deps`. |\n| npm peer dependency conflict | Use `npm install --legacy-peer-deps`, matching `docs\u002Fmake_screenshots.sh`. |\n| ND2 upload is rejected | Confirm the file extension is `.nd2` and the filename does not rely on path components. |\n| No contours or poor contours | Check layer mode, `param1`, crop size, and preview frames before annotating. |\n| OpenCV import\u002Fruntime errors | Use the project venv and install `backend\u002Frequirements.txt`; Docker also installs `libgl1` and `libglib2.0-0`. |\n| SQLite permission errors | Ensure `backend\u002Fapp\u002Fdatabases\u002F`, `backend\u002Fapp\u002Fextracted_data\u002F`, `backend\u002Fapp\u002Fnd2files\u002F`, and `backend\u002Fapp\u002Ftempdata\u002F` are writable. |\n\n## Tech Stack\n\nBackend:\n\n\u003Cp align=\"left\">\n  \u003Ca href=\"https:\u002F\u002Ffastapi.tiangolo.com\u002F\" title=\"FastAPI\">\n    \u003Cimg src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fgh\u002Fdevicons\u002Fdevicon\u002Ficons\u002Ffastapi\u002Ffastapi-original.svg\" height=\"32\" alt=\"FastAPI\" \u002F>\n  \u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fwww.sqlalchemy.org\u002F\" title=\"SQLAlchemy\">\n    \u003Cimg src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fgh\u002Fdevicons\u002Fdevicon\u002Ficons\u002Fsqlalchemy\u002Fsqlalchemy-original.svg\" height=\"32\" alt=\"SQLAlchemy\" \u002F>\n  \u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fnumpy.org\u002F\" title=\"NumPy\">\n    \u003Cimg src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fgh\u002Fdevicons\u002Fdevicon\u002Ficons\u002Fnumpy\u002Fnumpy-original.svg\" height=\"32\" alt=\"NumPy\" \u002F>\n  \u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fopencv.org\u002F\" title=\"OpenCV\">\n    \u003Cimg src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fgh\u002Fdevicons\u002Fdevicon\u002Ficons\u002Fopencv\u002Fopencv-original.svg\" height=\"32\" alt=\"OpenCV\" \u002F>\n  \u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fmatplotlib.org\u002F\" title=\"Matplotlib\">\n    \u003Cimg src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fgh\u002Fdevicons\u002Fdevicon\u002Ficons\u002Fmatplotlib\u002Fmatplotlib-original.svg\" height=\"32\" alt=\"Matplotlib\" \u002F>\n  \u003C\u002Fa>\n\u003C\u002Fp>\n\n- FastAPI, Uvicorn, and Pydantic for the API layer\n- SQLAlchemy and SQLite for database access\n- NumPy, OpenCV, Pillow, and Matplotlib for image processing and plotting\n- FastMCP for repository\u002Fcontext tooling\n\nFrontend:\n\n\u003Cp align=\"left\">\n  \u003Ca href=\"https:\u002F\u002Freact.dev\u002F\" title=\"React\">\n    \u003Cimg src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fgh\u002Fdevicons\u002Fdevicon\u002Ficons\u002Freact\u002Freact-original.svg\" height=\"32\" alt=\"React\" \u002F>\n  \u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fvitejs.dev\u002F\" title=\"Vite\">\n    \u003Cimg src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fgh\u002Fdevicons\u002Fdevicon\u002Ficons\u002Fvite\u002Fvite-original.svg\" height=\"32\" alt=\"Vite\" \u002F>\n  \u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fwww.typescriptlang.org\u002F\" title=\"TypeScript\">\n    \u003Cimg src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fgh\u002Fdevicons\u002Fdevicon\u002Ficons\u002Ftypescript\u002Ftypescript-original.svg\" height=\"32\" alt=\"TypeScript\" \u002F>\n  \u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fchakra-ui.com\u002F\" title=\"Chakra UI\">\n    \u003Cimg src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fgh\u002Fdevicons\u002Fdevicon\u002Ficons\u002Fchakraui\u002Fchakraui-original.svg\" height=\"32\" alt=\"Chakra UI\" \u002F>\n  \u003C\u002Fa>\n\u003C\u002Fp>\n\n- React + React Router for the UI\n- Vite for dev\u002Fbuild tooling\n- Chakra UI and Framer Motion for styling and motion\n- Docusaurus docs build under `frontend\u002Fdocs-site`\n\n## Docs\n\n- [Cell Extraction API](backend\u002Fapp\u002Fcellextraction\u002FREADME.md)\n- [Database Manager API](backend\u002Fapp\u002Fdatabase_manager\u002FREADME.md)\n- [Bulk Engine API](backend\u002Fapp\u002Fbulk_engine\u002FREADME.md)\n- [Frontend](frontend\u002FREADME.md)\n- [Contributing](CONTRIBUTING.md)\n\n## License\n\nPhenoPixel is released under the MIT License. See [LICENSE](LICENSE) for\ndetails. Third-party dependencies remain under their respective licenses.\n","PhenoPixel 是一个基于OpenCV的图像分析Web应用程序，专为显微镜单细胞提取、注释、可视化和批量表型分析设计。其核心功能包括ND2文件管理、细胞轮廓提取与标注、细胞查看器以及批量数据分析等，能够支持从上传ND2格式的显微镜数据到导出细胞形态及荧光强度汇总等一系列操作。该应用采用FastAPI构建后端服务，React开发前端界面，并利用SQLite数据库存储处理后的信息。特别适合于需要对显微镜下的细胞图像进行深入研究与分析的生物医学领域使用，如细胞生物学实验的数据处理与结果展示。",2,"2026-06-11 03:58:17","CREATED_QUERY"]