factcircuit
FactCircuit는 불변 출처와 단계별 검증, 제한된 검색, 재현 가능한 평가를 제공하는 감사 가능한 주장·증거 검증 루프입니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
People Counter — Entry / Exit Detection Dashboard
A simple, real-world people counting system that uses a video (uploaded file or
recorded camera footage) to detect people, track them across frames, and count
how many crossed a virtual entry/exit line — all displayed live on a React
dashboard.
Built to be beginner-friendly and easy to explain in a technical interview:
no deep-learning frameworks, no database, no C++ — just OpenCV, Flask, and React.README 전문 보기 ↗A simple, real-world people counting system that uses a video (uploaded file or recorded camera footage) to detect people, track them across frames, and count how many crossed a virtual entry/exit line — all displayed live on a React dashboard.
Built to be beginner-friendly and easy to explain in a technical interview: no deep-learning frameworks, no database, no C++ — just OpenCV, Flask, and React.
You upload a video of people walking past a doorway, corridor, or gate. The backend processes the video frame by frame with OpenCV: it detects people, tracks each one across frames, and checks whether they crossed a horizontal "virtual line" drawn across the frame. Crossing the line one way counts as an Entry, crossing it the other way counts as an Exit. The frontend shows the live count and the final annotated video with bounding boxes, IDs, and the counting line burned in.
This is the same basic idea used in:
Ready → Processing → Completed / Error).Frontend
Backend
No database is used — all state (counts, job status) lives in memory in the Flask process, and video files are stored on disk. No C++ code is written; OpenCV's Python bindings are used throughout.
Camera / Uploaded Video
│
▼
Python + OpenCV (backend/video_processor.py)
│
▼
Person Detection (backend/detector.py — HOG + SVM)
│
▼
Person Tracking (backend/tracker.py — centroid tracker)
│
▼
Virtual Entry/Exit Line
│
▼
Entry / Exit Counting (backend/counter.py)
│
▼
Flask REST API (backend/app.py)
│
▼
React + TypeScript Dashboard (frontend/)
backend/detector.py uses OpenCV's built-in HOG (Histogram of Oriented
Gradients) + Linear SVM pedestrian detector — cv2.HOGDescriptor() with
cv2.HOGDescriptor_getDefaultPeopleDetector(). This ships with every OpenCV
install, so there's nothing extra to download or configure.
In plain terms: HOG looks at the pattern of edge directions in small blocks of the image (does the pattern of light/dark edges look like the outline of a walking person?). That pattern is fed into a linear SVM classifier that has already been trained to recognize the general shape of a standing or walking human. It's not a deep neural network — it's a classic, well-documented computer-vision technique that's easy to explain and reason about, which is why it fits the "keep it simple" requirement of this project.
Each detection returns a bounding box (x, y, w, h) around a detected person,
with a confidence weight; low-confidence boxes are filtered out to reduce
false positives.
backend/tracker.py implements a centroid tracker:
This is intentionally simple — no Kalman filters, no deep-learning re-ID — a nearest-neighbour match is enough to track a handful of people moving through a doorway.
backend/counter.py keeps a virtual horizontal line at the middle of the
frame (configurable). For every tracked person, it remembers which side of
the line they were on the last time they were seen:
Above line → Below line = Entry
Below line → Above line = Exit
People Inside = Entry Count − Exit Count
Each crossing is tagged with the tracked person's unique ID plus the direction of that specific crossing, so the same person is never counted twice for the same crossing event even if their centroid jitters near the line for a few frames.
people-counter/
├── frontend/
│ ├── src/
│ │ ├── components/
│ │ │ ├── VideoUploader.tsx
│ │ │ ├── VideoViewer.tsx
│ │ │ ├── PeopleStats.tsx
│ │ │ ├── ControlButtons.tsx
│ │ │ └── StatusIndicator.tsx
│ │ ├── services/
│ │ │ └── api.ts
│ │ ├── types.ts
│ │ ├── App.tsx
│ │ ├── App.css
│ │ ├── index.css
│ │ └── main.tsx
│ ├── index.html
│ ├── package.json
│ ├── tsconfig.json
│ ├── tsconfig.app.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
│
├── backend/
│ ├── app.py
│ ├── detector.py
│ ├── tracker.py
│ ├── counter.py
│ ├── video_processor.py
│ ├── uploads/ (uploaded videos land here; ignored by git)
│ ├── processed/ (annotated output videos; ignored by git)
│ └── requirements.txt
│
├── .gitignore
└── README.md
git clone https://github.com/<your-username>/people-counter.git
cd people-counter
cd backend
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txt
cd frontend
npm install
cd backend
source venv/bin/activate # if not already active
python3 app.py
The API starts on http://localhost:5000.
In a separate terminal:
cd frontend
npm run dev
The dashboard is available at http://localhost:5173. It talks to the
Flask API at http://localhost:5000 by default — set VITE_API_BASE_URL in a
frontend/.env file if you run the backend somewhere else.
Then in the browser:
.mp4, .avi, .mov,
.mkv, or .webm).Processing to Completed.| Method | Endpoint | Description |
|---|---|---|
| GET | /health | Simple health check. |
| POST | /upload | Upload a video file (multipart/form-data, field video). |
| POST | /process | Start processing an uploaded video ({ "filename": "..." }). |
| GET | /status | Poll current status, progress, and live counts. |
| GET | /processed/<file> | Stream/download the processed output video. |
| POST | /reset | Reset counts and job state back to ready. |
Example status response while processing:
{
"status": "processing",
"progress": 42,
"errorMessage": null,
"entryCount": 3,
"exitCount": 1,
"peopleInside": 2,
"processedVideoReady": false
}
The pipeline was verified end-to-end during development:
tracker.py + counter.py were exercised with synthetic
centroid paths moving across the line in both directions, confirming
correct entry/exit counting and no double-counting.video_processor.py was run against a generated test
video to confirm detection → tracking → counting → annotated video output
runs without errors and produces a valid .mp4./health, /upload, /process, /status,
/processed/<file>, /reset) was exercised with curl, including error
paths — empty upload, missing file, unsupported format, processing a video
that doesn't exist, and downloading a missing processed file.tsc -b type-checks cleanly and npm run build produces a
working production bundle with no errors.To reproduce the manual test flow yourself, run the backend and frontend as
described above and upload any short .mp4 clip of people walking through a
doorway or corridor — the more clearly a full body is visible, the more
reliably the HOG detector will pick it up.
(Add screenshots of the dashboard here once you have real footage —
e.g. docs/screenshot-dashboard.png, docs/screenshot-processing.png.)