Spaces:
Running
Running
Upload 33 files
Browse files- README.md +31 -28
- VALIDATION_REPORT.txt +21 -57
- docs/ARCHITECTURE.md +25 -14
- docs/TEMPLATE_COORDINATES.md +25 -12
- docs/TESTING_GUIDE.md +10 -14
- docs/V3_1_CHANGELOG.md +8 -7
- docs/V3_CHANGELOG.md +9 -20
- docs/template_coordinate_overlay.jpg +2 -2
- marker_config.json +8 -76
- project_manifest.json +192 -129
- samples/sample_filled_clean.jpg +2 -2
- samples/sample_phone_detected.jpg +2 -2
- samples/sample_phone_missing_tl.jpg +2 -2
- samples/sample_phone_perspective.jpg +2 -2
- samples/sample_phone_shadow_rescue.jpg +2 -2
- samples/sample_phone_warped.jpg +2 -2
- samples/validation_missing_failed.jpg +2 -2
- samples/validation_shadow_detected.jpg +2 -2
- samples/validation_shadow_warped.jpg +2 -2
- template.jpg +2 -2
- template_A4_print.pdf +2 -2
- template_lossless.png +2 -2
- tools/add_markers_and_warp_colab.py +1 -10
- validate_project.py +3 -3
README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
---
|
| 2 |
-
title: DSE OMR V3.1
|
| 3 |
emoji: 📊
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: indigo
|
|
@@ -10,60 +10,63 @@ app_file: app.py
|
|
| 10 |
pinned: false
|
| 11 |
---
|
| 12 |
|
| 13 |
-
# DSE OMR V3.1
|
| 14 |
|
| 15 |
-
|
|
|
|
| 16 |
|
| 17 |
-
##
|
| 18 |
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
-
|
| 24 |
-
-
|
| 25 |
-
-
|
| 26 |
-
-
|
|
|
|
|
|
|
| 27 |
|
| 28 |
## Hugging Face 部署
|
| 29 |
|
| 30 |
1. 解壓本 ZIP。
|
| 31 |
-
2. 建立 Hugging Face
|
| 32 |
-
3. 將解壓後的
|
| 33 |
4. 等待 Build 完成。
|
| 34 |
-
5. 第一次掃描會下載 OMRChecker,因此需較長時間。
|
| 35 |
|
| 36 |
-
|
| 37 |
|
| 38 |
-
##
|
| 39 |
|
| 40 |
- `app.py`
|
| 41 |
- `README.md`
|
| 42 |
- `requirements.txt`
|
| 43 |
- `packages.txt`
|
| 44 |
- `template.jpg`
|
|
|
|
| 45 |
- `template.json`
|
| 46 |
- `marker_config.json`
|
| 47 |
- `marker_reference.png`
|
|
|
|
| 48 |
|
| 49 |
## 測試樣本
|
| 50 |
|
| 51 |
`samples/` 內包括:
|
| 52 |
|
| 53 |
-
- `
|
| 54 |
-
- `
|
| 55 |
-
- `
|
| 56 |
-
- `
|
| 57 |
-
- `
|
|
|
|
|
|
|
| 58 |
|
| 59 |
## 拍攝要求
|
| 60 |
|
| 61 |
- 四個大型定位標記必須完整入鏡。
|
| 62 |
-
-
|
| 63 |
- 避免嚴重反光、動態模糊及裁切。
|
| 64 |
- 相機不要太近,保留紙張四周少量背景。
|
| 65 |
-
- 系統拒絕圖片時應重新拍攝
|
| 66 |
-
|
| 67 |
-
## 執行流程
|
| 68 |
-
|
| 69 |
-
`手機相片 → V3 全頁嚴格偵測 →(必要時)V3.1 四角 ROI 局部補救 → 四點整組幾何驗證 → 3093×4374 透視校正 → OMRChecker 三輪掃描 → 成功輪次投票 → CSV/預覽/日誌`
|
|
|
|
| 1 |
---
|
| 2 |
+
title: DSE OMR V3.1 Four-Corner Scanner
|
| 3 |
emoji: 📊
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: indigo
|
|
|
|
| 10 |
pinned: false
|
| 11 |
---
|
| 12 |
|
| 13 |
+
# DSE OMR V3.1:只使用四個大型定位標記
|
| 14 |
|
| 15 |
+
本版本以學生手機拍攝 DSE 類型答題紙為目標。答題紙只保留答案區四周的四個
|
| 16 |
+
`144 × 144 px` 五層黑白大型定位標記,已移除所有每五題之間的小標記。
|
| 17 |
|
| 18 |
+
## 核心流程
|
| 19 |
|
| 20 |
+
`手機相片 → V3 嚴格四角偵測 → 必要時 V3.1 局部陰影補救 → 四點幾何安全檢查 → 3093×4374 透視校正 → OMRChecker 三輪掃描 → 成功輪次投票 → CSV/預覽/日誌`
|
| 21 |
+
|
| 22 |
+
## 本版本的設計
|
| 23 |
+
|
| 24 |
+
- 只使用四個大型定位標記。
|
| 25 |
+
- 沒有題目之間的小型定位符號。
|
| 26 |
+
- `template.json` 的 100 題答案座標保持不變。
|
| 27 |
+
- V3.1 局部補救可處理手機或手部陰影令一至兩個大型標記對比下降的情況。
|
| 28 |
+
- 補救角點仍須通過四邊形面積、跨度、比例及尺寸一致性檢查。
|
| 29 |
+
- `strictMarkerMode=true`:四角不可靠便拒絕,不把錯誤校正圖交給 OMRChecker。
|
| 30 |
|
| 31 |
## Hugging Face 部署
|
| 32 |
|
| 33 |
1. 解壓本 ZIP。
|
| 34 |
+
2. 建立 Hugging Face Gradio Space。
|
| 35 |
+
3. 將解壓後的所有檔案和資料夾上傳到 Space 根目錄。
|
| 36 |
4. 等待 Build 完成。
|
| 37 |
+
5. 第一次掃描會下載 OMRChecker 核心,因此需較長時間。
|
| 38 |
|
| 39 |
+
不要只把 ZIP 本身上傳為單一檔案;Space 需要 ZIP 解壓後的根目錄內容。
|
| 40 |
|
| 41 |
+
## 必要檔案
|
| 42 |
|
| 43 |
- `app.py`
|
| 44 |
- `README.md`
|
| 45 |
- `requirements.txt`
|
| 46 |
- `packages.txt`
|
| 47 |
- `template.jpg`
|
| 48 |
+
- `template_lossless.png`
|
| 49 |
- `template.json`
|
| 50 |
- `marker_config.json`
|
| 51 |
- `marker_reference.png`
|
| 52 |
+
- `template_A4_print.pdf`
|
| 53 |
|
| 54 |
## 測試樣本
|
| 55 |
|
| 56 |
`samples/` 內包括:
|
| 57 |
|
| 58 |
+
- `sample_filled_clean.jpg`:平整填答案樣本。
|
| 59 |
+
- `sample_phone_perspective.jpg`:正常手機透視樣本。
|
| 60 |
+
- `sample_phone_detected.jpg`:四角偵測預覽。
|
| 61 |
+
- `sample_phone_warped.jpg`:透視校正結果。
|
| 62 |
+
- `sample_phone_shadow_rescue.jpg`:大型標記附近手機陰影測試。
|
| 63 |
+
- `sample_phone_missing_tl.jpg`:真正缺失左上標記,應安全拒絕。
|
| 64 |
+
- `sample_answer_key.csv`:測試答案。
|
| 65 |
|
| 66 |
## 拍攝要求
|
| 67 |
|
| 68 |
- 四個大型定位標記必須完整入鏡。
|
| 69 |
+
- 不要讓手機本體或手指真正遮住定位標記。
|
| 70 |
- 避免嚴重反光、動態模糊及裁切。
|
| 71 |
- 相機不要太近,保留紙張四周少量背景。
|
| 72 |
+
- 系統拒絕圖片時應重新拍攝。
|
|
|
|
|
|
|
|
|
|
|
|
VALIDATION_REPORT.txt
CHANGED
|
@@ -1,59 +1,23 @@
|
|
| 1 |
-
DSE OMR
|
| 2 |
-
=====================================
|
| 3 |
|
| 4 |
-
Project version
|
| 5 |
-
---------------
|
| 6 |
-
DSE-OMR-v3.1-local-shadow-rescue
|
| 7 |
-
|
| 8 |
-
Static validation
|
| 9 |
-
-----------------
|
| 10 |
-
PASS Required root files present
|
| 11 |
-
PASS app.py Python syntax
|
| 12 |
-
PASS template.jpg = 3093 x 4374
|
| 13 |
-
PASS template_lossless.png = 3093 x 4374
|
| 14 |
-
PASS template.json pageDimensions = 3093 x 4374
|
| 15 |
-
PASS marker_config.json pageDimensions = 3093 x 4374
|
| 16 |
-
PASS largeMarkerOuterSize = 144
|
| 17 |
-
PASS strictMarkerMode = true
|
| 18 |
-
PASS localRescue.enabled = true
|
| 19 |
-
PASS minimumGlobalCandidates = 2
|
| 20 |
-
PASS maxRescueCorners = 2
|
| 21 |
-
PASS 16 small group markers retained
|
| 22 |
-
|
| 23 |
-
Functional marker tests
|
| 24 |
-
-----------------------
|
| 25 |
-
PASS sample_phone_perspective.jpg
|
| 26 |
-
Expected: V3 strict four-marker detection
|
| 27 |
-
Result: strict pass; no rescue used
|
| 28 |
-
|
| 29 |
-
PASS sample_phone_shadow_rescue.jpg
|
| 30 |
-
Expected: mobile-phone shadow breaks one strict contour hierarchy
|
| 31 |
-
Result: V3.1 local ROI rescue pass; geometry validation passed
|
| 32 |
-
|
| 33 |
-
PASS sample_phone_missing_tl.jpg
|
| 34 |
-
Expected: genuine missing TL marker must not be guessed
|
| 35 |
-
Result: safely rejected; image was not sent to OMRChecker
|
| 36 |
-
|
| 37 |
-
Additional stress observations
|
| 38 |
-
------------------------------
|
| 39 |
-
PASS even low light
|
| 40 |
-
PASS bright exposure
|
| 41 |
-
PASS warm/cool colour casts
|
| 42 |
-
PASS left-side shadow
|
| 43 |
-
PASS diagonal shadow via local rescue
|
| 44 |
-
PASS top-bright/bottom-dark via local rescue
|
| 45 |
-
PASS vignette via local rescue
|
| 46 |
-
PASS low-light sensor noise
|
| 47 |
-
REJECT low-light motion blur (intended safety rejection)
|
| 48 |
-
|
| 49 |
-
Limitations
|
| 50 |
-
-----------
|
| 51 |
-
- Full OMRChecker answer recognition is executed in Hugging Face after the
|
| 52 |
-
upstream OMRChecker repository is downloaded on first use.
|
| 53 |
-
- Local rescue corrects lighting-induced loss of marker hierarchy; it does not
|
| 54 |
-
invent a marker that is cropped out, physically covered, or severely blurred.
|
| 55 |
-
|
| 56 |
-
Final status
|
| 57 |
-
------------
|
| 58 |
PROJECT VALIDATION PASSED
|
| 59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
DSE OMR V3.1 Four Large Markers Only
|
| 2 |
+
=====================================
|
| 3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
PROJECT VALIDATION PASSED
|
| 5 |
+
|
| 6 |
+
Checks completed:
|
| 7 |
+
- app.py syntax: PASS
|
| 8 |
+
- validate_project.py syntax: PASS
|
| 9 |
+
- Colab marker tool syntax: PASS
|
| 10 |
+
- template.jpg size 3093 × 4374: PASS
|
| 11 |
+
- template_lossless.png size 3093 × 4374: PASS
|
| 12 |
+
- exactly four large markers in marker_config.json: PASS
|
| 13 |
+
- no smallGroupMarkers setting: PASS
|
| 14 |
+
- no smallMarkerOuterSize setting: PASS
|
| 15 |
+
- 16 former small-marker positions cleared from template: PASS
|
| 16 |
+
- normal phone-perspective four-corner detection: PASS
|
| 17 |
+
- perspective warp output: PASS
|
| 18 |
+
- missing-TL sample safely rejected: PASS
|
| 19 |
+
- template PDF regenerated: PASS
|
| 20 |
+
- Hugging Face required files present: PASS
|
| 21 |
+
|
| 22 |
+
Normal sample local rescue used: False
|
| 23 |
+
Shadow sample local rescue used: True
|
docs/ARCHITECTURE.md
CHANGED
|
@@ -1,14 +1,25 @@
|
|
| 1 |
-
#
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 系統架構
|
| 2 |
+
|
| 3 |
+
## 目前定位結構
|
| 4 |
+
|
| 5 |
+
本專案只使用四個大型五層黑白定位標記:
|
| 6 |
+
|
| 7 |
+
- top_left
|
| 8 |
+
- top_right
|
| 9 |
+
- bottom_left
|
| 10 |
+
- bottom_right
|
| 11 |
+
|
| 12 |
+
題目之間沒有小型定位標記,也沒有局部五題區塊校正。
|
| 13 |
+
|
| 14 |
+
## 處理層
|
| 15 |
+
|
| 16 |
+
1. 圖片載入與基本檢查
|
| 17 |
+
2. V3 全頁大型標記偵測
|
| 18 |
+
3. 必要時 V3.1 四角 ROI 局部陰影補救
|
| 19 |
+
4. 四點幾何安全驗證
|
| 20 |
+
5. `warpPerspective` 映射至 `3093 × 4374`
|
| 21 |
+
6. 按 `template.json` 執行 OMRChecker
|
| 22 |
+
7. 三輪靈敏度掃描及成功輪次投票
|
| 23 |
+
8. 輸出 CSV、定位預覽、校正預覽與日誌
|
| 24 |
+
|
| 25 |
+
四角校正成功後會停用第二次 `FeatureBasedAlignment`,避免雙重幾何變換。
|
docs/TEMPLATE_COORDINATES.md
CHANGED
|
@@ -1,12 +1,25 @@
|
|
| 1 |
-
#
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
-
|
| 6 |
-
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
-
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 模板及定位座標
|
| 2 |
+
|
| 3 |
+
## 頁面
|
| 4 |
+
|
| 5 |
+
- 寬:3093 px
|
| 6 |
+
- 高:4374 px
|
| 7 |
+
|
| 8 |
+
## 四個大型定位標記
|
| 9 |
+
|
| 10 |
+
- TL:[720, 1410]
|
| 11 |
+
- TR:[3015, 1410]
|
| 12 |
+
- BL:[720, 4285]
|
| 13 |
+
- BR:[3015, 4285]
|
| 14 |
+
- 外框尺寸:144 px
|
| 15 |
+
- 黑白巢狀層數:5
|
| 16 |
+
|
| 17 |
+
## 小標記
|
| 18 |
+
|
| 19 |
+
本版本沒有任何題目間小標記。`marker_config.json` 亦不包含
|
| 20 |
+
`smallGroupMarkers` 或 `smallMarkerOuterSize`。
|
| 21 |
+
|
| 22 |
+
## 答案座標
|
| 23 |
+
|
| 24 |
+
100 題答案座標繼續由 `template.json` 的 20 個五題 field block 定義。
|
| 25 |
+
移除小標記沒有移動任何答案格,因此不需要改動 field block 座標。
|
docs/TESTING_GUIDE.md
CHANGED
|
@@ -1,23 +1,19 @@
|
|
| 1 |
-
#
|
| 2 |
|
| 3 |
-
|
| 4 |
|
| 5 |
1. `sample_phone_perspective.jpg`
|
| 6 |
-
- 預期:V3 strict pass,四角全為綠色。
|
| 7 |
2. `sample_phone_shadow_rescue.jpg`
|
| 8 |
-
- 預期:V3.1 local rescue pass,至少一角為黃橙色並帶 `*`。
|
| 9 |
3. `sample_phone_missing_tl.jpg`
|
| 10 |
-
- 預期:安全拒絕,不進入 OMRChecker。
|
| 11 |
|
| 12 |
-
|
|
|
|
| 13 |
|
| 14 |
-
|
| 15 |
-
- `V3.1 局部補救成功`:陰影中的缺失角點已恢復且幾何檢查通過。
|
| 16 |
-
- `未通過 V3.1 安全檢查`:應重新拍攝。
|
| 17 |
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
-
|
| 21 |
-
- 嚴重動態模糊。
|
| 22 |
-
- 反光把黑白環帶完全洗白。
|
| 23 |
-
- 只找到 0–1 個全頁嚴格候選。
|
|
|
|
| 1 |
+
# 測試指引
|
| 2 |
|
| 3 |
+
建議依次上傳:
|
| 4 |
|
| 5 |
1. `sample_phone_perspective.jpg`
|
|
|
|
| 6 |
2. `sample_phone_shadow_rescue.jpg`
|
|
|
|
| 7 |
3. `sample_phone_missing_tl.jpg`
|
|
|
|
| 8 |
|
| 9 |
+
正常樣本應找到四個大型標記並完成透視校正。陰影樣本可由嚴格模式或
|
| 10 |
+
V3.1 局部補救通過。缺失 TL 的樣本必須拒絕。
|
| 11 |
|
| 12 |
+
檢查畫面:
|
|
|
|
|
|
|
| 13 |
|
| 14 |
+
- TL、TR、BR、BL 是否落在四個大型標記。
|
| 15 |
+
- 校正後紅色答案欄是否垂直。
|
| 16 |
+
- OMRChecker 是否成功返回 CSV。
|
| 17 |
+
- 執行摘要中是否沒有 config schema 錯誤。
|
| 18 |
|
| 19 |
+
本版本沒有小標記,因此不需要檢查題目間定位符號。
|
|
|
|
|
|
|
|
|
docs/V3_1_CHANGELOG.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
| 1 |
-
# V3.1
|
| 2 |
|
| 3 |
-
-
|
| 4 |
-
-
|
| 5 |
-
-
|
| 6 |
-
-
|
| 7 |
-
- 局部
|
| 8 |
-
-
|
|
|
|
|
|
| 1 |
+
# V3.1 Four-Large-Markers-Only 變更
|
| 2 |
|
| 3 |
+
- 保留四個 `144 × 144 px` 五層黑白大型定位標記。
|
| 4 |
+
- 移除 16 個每五題之間的小型定位標記。
|
| 5 |
+
- 從 `marker_config.json` 移除小標記座標及尺寸設定。
|
| 6 |
+
- Colab 產生工具只會加入四個大型標記。
|
| 7 |
+
- 保留 V3 嚴格偵測、V3.1 局部陰影補救及幾何安全檢查。
|
| 8 |
+
- 重新產生 template、PDF、座標圖及所有測試樣本。
|
| 9 |
+
- 答案格座標及 OMRChecker 三輪辨識流程不變。
|
docs/V3_CHANGELOG.md
CHANGED
|
@@ -1,20 +1,9 @@
|
|
| 1 |
-
# V3 更
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
-
|
| 6 |
-
-
|
| 7 |
-
-
|
| 8 |
-
-
|
| 9 |
-
|
| 10 |
-
## 偵測器
|
| 11 |
-
|
| 12 |
-
- 強制 hierarchy depth。
|
| 13 |
-
- 依頁面比例估計大型標記像素尺寸,排除小型標記。
|
| 14 |
-
- 四角候選整組組合及幾何驗證。
|
| 15 |
-
- 失敗圖會顯示所有通過初步篩選的候選框。
|
| 16 |
-
|
| 17 |
-
## 安全行為
|
| 18 |
-
|
| 19 |
-
- 預設 strict mode,不再把誤判 TL/TR/BL/BR 的圖片交給 OMRChecker。
|
| 20 |
-
- 可在 `marker_config.json` 將 `strictMarkerMode` 設為 `false` 才啟用舊回退模式。
|
|
|
|
| 1 |
+
# V3.1 Four-Large-Markers-Only 變更
|
| 2 |
+
|
| 3 |
+
- 保留四個 `144 × 144 px` 五層黑白大型定位標記。
|
| 4 |
+
- 移除 16 個每五題之間的小型定位標記。
|
| 5 |
+
- 從 `marker_config.json` 移除小標記座標及尺寸設定。
|
| 6 |
+
- Colab 產生工具只會加入四個大型標記。
|
| 7 |
+
- 保留 V3 嚴格偵測、V3.1 局部陰影補救及幾何安全檢查。
|
| 8 |
+
- 重新產生 template、PDF、座標圖及所有測試樣本。
|
| 9 |
+
- 答案格座標及 OMRChecker 三輪辨識流程不變。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/template_coordinate_overlay.jpg
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
marker_config.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
{
|
| 2 |
-
"templateVersion": "DSE-OMR-v3.1-
|
| 3 |
"pageDimensions": [
|
| 4 |
3093,
|
| 5 |
4374
|
|
@@ -31,73 +31,6 @@
|
|
| 31 |
},
|
| 32 |
"largeMarkerOuterSize": 144,
|
| 33 |
"largeMarkerNestedLevels": 5,
|
| 34 |
-
"smallGroupMarkers": [
|
| 35 |
-
[
|
| 36 |
-
1310,
|
| 37 |
-
2122
|
| 38 |
-
],
|
| 39 |
-
[
|
| 40 |
-
1310,
|
| 41 |
-
2637
|
| 42 |
-
],
|
| 43 |
-
[
|
| 44 |
-
1310,
|
| 45 |
-
3152
|
| 46 |
-
],
|
| 47 |
-
[
|
| 48 |
-
1310,
|
| 49 |
-
3667
|
| 50 |
-
],
|
| 51 |
-
[
|
| 52 |
-
1830,
|
| 53 |
-
2122
|
| 54 |
-
],
|
| 55 |
-
[
|
| 56 |
-
1830,
|
| 57 |
-
2637
|
| 58 |
-
],
|
| 59 |
-
[
|
| 60 |
-
1830,
|
| 61 |
-
3152
|
| 62 |
-
],
|
| 63 |
-
[
|
| 64 |
-
1830,
|
| 65 |
-
3667
|
| 66 |
-
],
|
| 67 |
-
[
|
| 68 |
-
2350,
|
| 69 |
-
2122
|
| 70 |
-
],
|
| 71 |
-
[
|
| 72 |
-
2350,
|
| 73 |
-
2637
|
| 74 |
-
],
|
| 75 |
-
[
|
| 76 |
-
2350,
|
| 77 |
-
3152
|
| 78 |
-
],
|
| 79 |
-
[
|
| 80 |
-
2350,
|
| 81 |
-
3667
|
| 82 |
-
],
|
| 83 |
-
[
|
| 84 |
-
2870,
|
| 85 |
-
2122
|
| 86 |
-
],
|
| 87 |
-
[
|
| 88 |
-
2870,
|
| 89 |
-
2637
|
| 90 |
-
],
|
| 91 |
-
[
|
| 92 |
-
2870,
|
| 93 |
-
3152
|
| 94 |
-
],
|
| 95 |
-
[
|
| 96 |
-
2870,
|
| 97 |
-
3667
|
| 98 |
-
]
|
| 99 |
-
],
|
| 100 |
-
"smallMarkerOuterSize": 34,
|
| 101 |
"detection": {
|
| 102 |
"minNestedDepth": 3,
|
| 103 |
"minQuadrilateralAreaRatio": 0.2,
|
|
@@ -123,13 +56,12 @@
|
|
| 123 |
]
|
| 124 |
},
|
| 125 |
"notes": [
|
| 126 |
-
"
|
| 127 |
-
"
|
| 128 |
-
"V3.1
|
| 129 |
-
"Local rescue
|
| 130 |
-
"
|
| 131 |
-
"
|
| 132 |
-
"Small group markers remain 34 px and are reserved for future local-warp checks."
|
| 133 |
],
|
| 134 |
"localRescue": {
|
| 135 |
"enabled": true,
|
|
@@ -155,4 +87,4 @@
|
|
| 155 |
"adaptiveBlockSize": 31,
|
| 156 |
"adaptiveC": 7
|
| 157 |
}
|
| 158 |
-
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"templateVersion": "DSE-OMR-v3.1-four-large-markers-only",
|
| 3 |
"pageDimensions": [
|
| 4 |
3093,
|
| 5 |
4374
|
|
|
|
| 31 |
},
|
| 32 |
"largeMarkerOuterSize": 144,
|
| 33 |
"largeMarkerNestedLevels": 5,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
"detection": {
|
| 35 |
"minNestedDepth": 3,
|
| 36 |
"minQuadrilateralAreaRatio": 0.2,
|
|
|
|
| 56 |
]
|
| 57 |
},
|
| 58 |
"notes": [
|
| 59 |
+
"This variant keeps only the four 144 px five-layer large corner markers.",
|
| 60 |
+
"All 16 small markers between five-question groups have been removed.",
|
| 61 |
+
"V3.1 strict full-page detection remains the first stage.",
|
| 62 |
+
"Local corner-ROI rescue remains available when phone or hand shadow degrades one or two large markers.",
|
| 63 |
+
"Recovered points must still pass full four-point geometry validation.",
|
| 64 |
+
"No local group-marker correction is performed or required in this project."
|
|
|
|
| 65 |
],
|
| 66 |
"localRescue": {
|
| 67 |
"enabled": true,
|
|
|
|
| 87 |
"adaptiveBlockSize": 31,
|
| 88 |
"adaptiveC": 7
|
| 89 |
}
|
| 90 |
+
}
|
project_manifest.json
CHANGED
|
@@ -1,130 +1,193 @@
|
|
| 1 |
{
|
| 2 |
-
"
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
"
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
{
|
| 2 |
+
"project": "DSE OMR V3.1 Four Large Markers Only",
|
| 3 |
+
"template_version": "DSE-OMR-v3.1-four-large-markers-only",
|
| 4 |
+
"large_marker_count": 4,
|
| 5 |
+
"small_marker_count": 0,
|
| 6 |
+
"files": [
|
| 7 |
+
{
|
| 8 |
+
"path": ".gitignore",
|
| 9 |
+
"size_bytes": 69,
|
| 10 |
+
"sha256": "220f22568b058b917b79feb609ec12fc63085941efafd3698cf4575c0f6ad05f"
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"path": "README.md",
|
| 14 |
+
"size_bytes": 2424,
|
| 15 |
+
"sha256": "0d885050aef4963afe8a90496322ea15102bbff3f9b75b7d72f559206ecc3a7a"
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"path": "VALIDATION_REPORT.txt",
|
| 19 |
+
"size_bytes": 779,
|
| 20 |
+
"sha256": "7f3a17271ca4636c3dea290e849f36bcdce3ec73454f5cddf612dcbb8ba02887"
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"path": "__pycache__/app.cpython-313.pyc",
|
| 24 |
+
"size_bytes": 68024,
|
| 25 |
+
"sha256": "5c99d35bc4003ea494844b88c5b3ba1bb589422fb3e47b4bd2bfd9c001738c05"
|
| 26 |
+
},
|
| 27 |
+
{
|
| 28 |
+
"path": "__pycache__/validate_project.cpython-313.pyc",
|
| 29 |
+
"size_bytes": 4362,
|
| 30 |
+
"sha256": "55c81cd08cc9e50693aba2a3cf2c9f831259bdb64bf209e015567ac68c183e4c"
|
| 31 |
+
},
|
| 32 |
+
{
|
| 33 |
+
"path": "app.py",
|
| 34 |
+
"size_bytes": 55081,
|
| 35 |
+
"sha256": "d96a6f4a48b071774d1dfcacbf787581260e4a9e301dd3232582716629c4c3e7"
|
| 36 |
+
},
|
| 37 |
+
{
|
| 38 |
+
"path": "docs/ARCHITECTURE.md",
|
| 39 |
+
"size_bytes": 661,
|
| 40 |
+
"sha256": "b4ab0a6766dc79e7c2fb273f690a8e83b02df883e031e5389ca2fdbaa4d9d191"
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"path": "docs/TEMPLATE_COORDINATES.md",
|
| 44 |
+
"size_bytes": 557,
|
| 45 |
+
"sha256": "10e43a06ea3e74f37ab9588da894fbb652c12de70563ca29251013118c4755f3"
|
| 46 |
+
},
|
| 47 |
+
{
|
| 48 |
+
"path": "docs/TESTING_GUIDE.md",
|
| 49 |
+
"size_bytes": 582,
|
| 50 |
+
"sha256": "1830a6284a1cfd09c9bcb13305b302e66436143f6f411bbaa97726e42f35ce46"
|
| 51 |
+
},
|
| 52 |
+
{
|
| 53 |
+
"path": "docs/V3_1_CHANGELOG.md",
|
| 54 |
+
"size_bytes": 481,
|
| 55 |
+
"sha256": "588aa9895b36abd22e30ef05a3dd7f8efd6bf8560180290ed203d058602cc230"
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"path": "docs/V3_CHANGELOG.md",
|
| 59 |
+
"size_bytes": 481,
|
| 60 |
+
"sha256": "588aa9895b36abd22e30ef05a3dd7f8efd6bf8560180290ed203d058602cc230"
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"path": "docs/template_coordinate_overlay.jpg",
|
| 64 |
+
"size_bytes": 1651047,
|
| 65 |
+
"sha256": "3db779e3a69622ecf047373df6882bf70c8d3a52f253acc496c28d1a046b433d"
|
| 66 |
+
},
|
| 67 |
+
{
|
| 68 |
+
"path": "marker_config.json",
|
| 69 |
+
"size_bytes": 1936,
|
| 70 |
+
"sha256": "6d12faf818e64a16dde6e6762cfcbd08b676a50a0de4b84ca36b2e9371b8a7b9"
|
| 71 |
+
},
|
| 72 |
+
{
|
| 73 |
+
"path": "marker_reference.png",
|
| 74 |
+
"size_bytes": 1497,
|
| 75 |
+
"sha256": "9b896e436e359df8a3bdba19013cce4d646ba9e2eb38ce590fa9ff5065a6eba3"
|
| 76 |
+
},
|
| 77 |
+
{
|
| 78 |
+
"path": "packages.txt",
|
| 79 |
+
"size_bytes": 32,
|
| 80 |
+
"sha256": "4de86580e7ebc03a7790808fa6655cac191045bd030c15d4cc07acf03e6706f1"
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"path": "project_manifest.json",
|
| 84 |
+
"size_bytes": 4580,
|
| 85 |
+
"sha256": "58d8f4e19bcd6e3fad305e09779bb63826c86938b2096b1e8f75f4fb4564bce6"
|
| 86 |
+
},
|
| 87 |
+
{
|
| 88 |
+
"path": "requirements.txt",
|
| 89 |
+
"size_bytes": 576,
|
| 90 |
+
"sha256": "b7411f9ebbf827d2272fb789c10c2d03ae27e7f3f908d0d0f4da5b4103497e22"
|
| 91 |
+
},
|
| 92 |
+
{
|
| 93 |
+
"path": "samples/sample_answer_key.csv",
|
| 94 |
+
"size_bytes": 597,
|
| 95 |
+
"sha256": "c61e0234c426ef58c6aa7d6a998e313c6223dc769b16df2fc7a4ec11ff024ec7"
|
| 96 |
+
},
|
| 97 |
+
{
|
| 98 |
+
"path": "samples/sample_filled_clean.jpg",
|
| 99 |
+
"size_bytes": 1647356,
|
| 100 |
+
"sha256": "0731fad2c9712cf8f02a3662286f92ac801e8632b116ead97d756b63e599473b"
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"path": "samples/sample_phone_detected.jpg",
|
| 104 |
+
"size_bytes": 624509,
|
| 105 |
+
"sha256": "f80183c0fb42961d9f889b2865236d369ad2c305160e64eb3c1142a7c01263a2"
|
| 106 |
+
},
|
| 107 |
+
{
|
| 108 |
+
"path": "samples/sample_phone_missing_tl.jpg",
|
| 109 |
+
"size_bytes": 608318,
|
| 110 |
+
"sha256": "963d897dbc2969b68bc5dd558c2c78f792863e4d2b55fbc50d669e1ab3a702d4"
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"path": "samples/sample_phone_perspective.jpg",
|
| 114 |
+
"size_bytes": 609664,
|
| 115 |
+
"sha256": "05ee2debd12a855ee8f999fbe3e0732c159b5718013ccebc97d76e8187ea971a"
|
| 116 |
+
},
|
| 117 |
+
{
|
| 118 |
+
"path": "samples/sample_phone_shadow_rescue.jpg",
|
| 119 |
+
"size_bytes": 611829,
|
| 120 |
+
"sha256": "ee14c40f1e9826766247cde4fb3e15134a81e0b0f1ac43383718d1aed462e109"
|
| 121 |
+
},
|
| 122 |
+
{
|
| 123 |
+
"path": "samples/sample_phone_warped.jpg",
|
| 124 |
+
"size_bytes": 1490520,
|
| 125 |
+
"sha256": "ecd740b282740f2fd4843b82cb979357328e0960596aa3807ab0b0032f5efaaa"
|
| 126 |
+
},
|
| 127 |
+
{
|
| 128 |
+
"path": "samples/validation_missing_failed.jpg",
|
| 129 |
+
"size_bytes": 629418,
|
| 130 |
+
"sha256": "20bed2ae0cfc3a5d9ea377570cf79c2cac4b974a6a28a8aebbc0ba53cad0bba5"
|
| 131 |
+
},
|
| 132 |
+
{
|
| 133 |
+
"path": "samples/validation_shadow_detected.jpg",
|
| 134 |
+
"size_bytes": 636319,
|
| 135 |
+
"sha256": "9bf985c6686f0c06a5f579d708c5a7859eb15e78d286349149011a364522f4cc"
|
| 136 |
+
},
|
| 137 |
+
{
|
| 138 |
+
"path": "samples/validation_shadow_warped.jpg",
|
| 139 |
+
"size_bytes": 1501053,
|
| 140 |
+
"sha256": "e79b1d775c0afb472b80a50f811b8c6883901a12641453ca8534d5f3f67297b4"
|
| 141 |
+
},
|
| 142 |
+
{
|
| 143 |
+
"path": "template.jpg",
|
| 144 |
+
"size_bytes": 1760828,
|
| 145 |
+
"sha256": "6b8ae7fcb30f1bd928015ec2ca1ddb6e7d4bd982b93fdf7f81778f7fcfe626e9"
|
| 146 |
+
},
|
| 147 |
+
{
|
| 148 |
+
"path": "template.json",
|
| 149 |
+
"size_bytes": 4723,
|
| 150 |
+
"sha256": "d49c9a881225afae81cae9521a85a68c044d5d86844b3774cc9130de1d484bd2"
|
| 151 |
+
},
|
| 152 |
+
{
|
| 153 |
+
"path": "template_A4_print.pdf",
|
| 154 |
+
"size_bytes": 716725,
|
| 155 |
+
"sha256": "ba117aa756a9c4cecc0b913563e91e2c8998d4f36688530afe0a677e685657db"
|
| 156 |
+
},
|
| 157 |
+
{
|
| 158 |
+
"path": "template_lossless.png",
|
| 159 |
+
"size_bytes": 6858945,
|
| 160 |
+
"sha256": "71c031b628adea74b435bda57e46eaa555d68f3aed0804ea69f95fa0fc60ad40"
|
| 161 |
+
},
|
| 162 |
+
{
|
| 163 |
+
"path": "tools/__pycache__/add_markers_and_warp_colab.cpython-313.pyc",
|
| 164 |
+
"size_bytes": 8417,
|
| 165 |
+
"sha256": "5f054c790adb40f5f578259472070b6ecec4632bab83b6e55d2126c6af776ca7"
|
| 166 |
+
},
|
| 167 |
+
{
|
| 168 |
+
"path": "tools/__pycache__/generate_filled_sample.cpython-313.pyc",
|
| 169 |
+
"size_bytes": 2083,
|
| 170 |
+
"sha256": "0f889cb32338dd181b1fa366f1394ea870fdfc80ab99ea316ac41093f7d01fc1"
|
| 171 |
+
},
|
| 172 |
+
{
|
| 173 |
+
"path": "tools/add_markers_and_warp_colab.py",
|
| 174 |
+
"size_bytes": 4775,
|
| 175 |
+
"sha256": "60342bae732564aee6b4671a648c8cafdfca53c38f891f4ba9c687acb466fbec"
|
| 176 |
+
},
|
| 177 |
+
{
|
| 178 |
+
"path": "tools/generate_filled_sample.py",
|
| 179 |
+
"size_bytes": 869,
|
| 180 |
+
"sha256": "9562dfe9a13aed8d8c13ff86b1415c399c5a629a10e1706b8fbc387729d53777"
|
| 181 |
+
},
|
| 182 |
+
{
|
| 183 |
+
"path": "tools/test_marker_v31.py",
|
| 184 |
+
"size_bytes": 1414,
|
| 185 |
+
"sha256": "28bddae2d69932cec4f6c871c91a24e1c9db82cc2612ae231cc330fa7b8566a7"
|
| 186 |
+
},
|
| 187 |
+
{
|
| 188 |
+
"path": "validate_project.py",
|
| 189 |
+
"size_bytes": 2805,
|
| 190 |
+
"sha256": "5732882b7ef24bd24c6b2712db042d124212c0b647f407be0bf8579814a8fabc"
|
| 191 |
+
}
|
| 192 |
+
]
|
| 193 |
+
}
|
samples/sample_filled_clean.jpg
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
samples/sample_phone_detected.jpg
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
samples/sample_phone_missing_tl.jpg
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
samples/sample_phone_perspective.jpg
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
samples/sample_phone_shadow_rescue.jpg
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
samples/sample_phone_warped.jpg
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
samples/validation_missing_failed.jpg
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
samples/validation_shadow_detected.jpg
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
samples/validation_shadow_warped.jpg
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
template.jpg
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
template_A4_print.pdf
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ba117aa756a9c4cecc0b913563e91e2c8998d4f36688530afe0a677e685657db
|
| 3 |
+
size 716725
|
template_lossless.png
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
tools/add_markers_and_warp_colab.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
"""Colab utility for the DSE OMR V3 large-marker template.
|
| 3 |
|
| 4 |
Functions:
|
| 5 |
-
- add_v3_markers(): add four 144px five-layer
|
| 6 |
- detect_and_warp(): detect the four large markers and perspective-correct a photo.
|
| 7 |
|
| 8 |
For the full production detector and OMR flow, use app.py in the Space project.
|
|
@@ -13,19 +13,12 @@ import numpy as np
|
|
| 13 |
|
| 14 |
PAGE_SIZE = (3093, 4374)
|
| 15 |
LARGE_SIZE = 144
|
| 16 |
-
SMALL_SIZE = 34
|
| 17 |
LARGE_MARKERS = {
|
| 18 |
'top_left': (720, 1410),
|
| 19 |
'top_right': (3015, 1410),
|
| 20 |
'bottom_left': (720, 4285),
|
| 21 |
'bottom_right': (3015, 4285),
|
| 22 |
}
|
| 23 |
-
SMALL_MARKERS = [
|
| 24 |
-
(1310, 2122), (1310, 2637), (1310, 3152), (1310, 3667),
|
| 25 |
-
(1830, 2122), (1830, 2637), (1830, 3152), (1830, 3667),
|
| 26 |
-
(2350, 2122), (2350, 2637), (2350, 3152), (2350, 3667),
|
| 27 |
-
(2870, 2122), (2870, 2637), (2870, 3152), (2870, 3667),
|
| 28 |
-
]
|
| 29 |
|
| 30 |
|
| 31 |
def _draw_nested_marker(img, center, size):
|
|
@@ -51,8 +44,6 @@ def add_v3_markers(input_path='template_original.jpg',
|
|
| 51 |
img = cv2.resize(img, PAGE_SIZE, interpolation=cv2.INTER_CUBIC)
|
| 52 |
for point in LARGE_MARKERS.values():
|
| 53 |
_draw_nested_marker(img, point, LARGE_SIZE)
|
| 54 |
-
for point in SMALL_MARKERS:
|
| 55 |
-
_draw_nested_marker(img, point, SMALL_SIZE)
|
| 56 |
cv2.imwrite(output_path, img, [int(cv2.IMWRITE_JPEG_QUALITY), 97])
|
| 57 |
return output_path
|
| 58 |
|
|
|
|
| 2 |
"""Colab utility for the DSE OMR V3 large-marker template.
|
| 3 |
|
| 4 |
Functions:
|
| 5 |
+
- add_v3_markers(): add only four 144px five-layer corner markers.
|
| 6 |
- detect_and_warp(): detect the four large markers and perspective-correct a photo.
|
| 7 |
|
| 8 |
For the full production detector and OMR flow, use app.py in the Space project.
|
|
|
|
| 13 |
|
| 14 |
PAGE_SIZE = (3093, 4374)
|
| 15 |
LARGE_SIZE = 144
|
|
|
|
| 16 |
LARGE_MARKERS = {
|
| 17 |
'top_left': (720, 1410),
|
| 18 |
'top_right': (3015, 1410),
|
| 19 |
'bottom_left': (720, 4285),
|
| 20 |
'bottom_right': (3015, 4285),
|
| 21 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
|
| 24 |
def _draw_nested_marker(img, center, size):
|
|
|
|
| 44 |
img = cv2.resize(img, PAGE_SIZE, interpolation=cv2.INTER_CUBIC)
|
| 45 |
for point in LARGE_MARKERS.values():
|
| 46 |
_draw_nested_marker(img, point, LARGE_SIZE)
|
|
|
|
|
|
|
| 47 |
cv2.imwrite(output_path, img, [int(cv2.IMWRITE_JPEG_QUALITY), 97])
|
| 48 |
return output_path
|
| 49 |
|
validate_project.py
CHANGED
|
@@ -43,8 +43,8 @@ try:
|
|
| 43 |
errors.append('V3.1 largeMarkerOuterSize must remain 144')
|
| 44 |
if markers.get('strictMarkerMode') is not True:
|
| 45 |
errors.append('strictMarkerMode must default to true')
|
| 46 |
-
if
|
| 47 |
-
errors.append('
|
| 48 |
rescue = markers.get('localRescue') or {}
|
| 49 |
if rescue.get('enabled') is not True:
|
| 50 |
errors.append('V3.1 localRescue.enabled must be true')
|
|
@@ -65,4 +65,4 @@ if errors:
|
|
| 65 |
sys.exit(1)
|
| 66 |
|
| 67 |
print('PROJECT VALIDATION PASSED')
|
| 68 |
-
print('V3.1 template, local-shadow rescue settings and required files are present.')
|
|
|
|
| 43 |
errors.append('V3.1 largeMarkerOuterSize must remain 144')
|
| 44 |
if markers.get('strictMarkerMode') is not True:
|
| 45 |
errors.append('strictMarkerMode must default to true')
|
| 46 |
+
if 'smallGroupMarkers' in markers or 'smallMarkerOuterSize' in markers:
|
| 47 |
+
errors.append('Small group marker settings must not exist in this variant')
|
| 48 |
rescue = markers.get('localRescue') or {}
|
| 49 |
if rescue.get('enabled') is not True:
|
| 50 |
errors.append('V3.1 localRescue.enabled must be true')
|
|
|
|
| 65 |
sys.exit(1)
|
| 66 |
|
| 67 |
print('PROJECT VALIDATION PASSED')
|
| 68 |
+
print('V3.1 four-large-marker-only template, local-shadow rescue settings and required files are present.')
|