AswinMathew commited on
Commit
b8548e4
·
verified ·
1 Parent(s): 5fb7148

Deploy OCR/OMR backend to HF Spaces

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .dockerignore +6 -0
  2. .env.example +10 -0
  3. .gitattributes +44 -35
  4. .gitignore +188 -0
  5. Dockerfile +30 -0
  6. Images/GK_Question_Paper_A4.pdf +0 -0
  7. Images/OCR2.jpg +0 -0
  8. Images/OCRSheet.jpg +3 -0
  9. Images/OCRTest.pdf +0 -0
  10. Images/OMRSheet.jpg +3 -0
  11. Images/OMRSheet2.jpg +3 -0
  12. Images/OMRSheet3.jpg +3 -0
  13. Images/OMRTest.jpg +3 -0
  14. Images/OcrSheetMarked.jpg +3 -0
  15. Images/omr_answer_key.pdf +3 -0
  16. Images/omr_answer_key.png +3 -0
  17. Images/question.png +0 -0
  18. Images/question_paper.pdf +0 -0
  19. Images/question_paper.png +3 -0
  20. Images/test.jpg +3 -0
  21. OMRChecker/.pre-commit-config.yaml +59 -0
  22. OMRChecker/.pylintrc +43 -0
  23. OMRChecker/CODE_OF_CONDUCT.md +133 -0
  24. OMRChecker/CONTRIBUTING.md +32 -0
  25. OMRChecker/Contributors.md +22 -0
  26. OMRChecker/LICENSE +22 -0
  27. OMRChecker/README.md +359 -0
  28. OMRChecker/docs/assets/colored_output.jpg +0 -0
  29. OMRChecker/inputs/OMRImage.jpg +3 -0
  30. OMRChecker/inputs/template.json +37 -0
  31. OMRChecker/main.py +99 -0
  32. OMRChecker/outputs/AdrianSample/Manual/ErrorFiles.csv +1 -0
  33. OMRChecker/outputs/AdrianSample/Manual/MultiMarkedFiles.csv +1 -0
  34. OMRChecker/outputs/AdrianSample/Results/Results_07PM.csv +1 -0
  35. OMRChecker/outputs/CheckedOMRs/OMRImage.jpg +3 -0
  36. OMRChecker/outputs/CheckedOMRs/OMRSheet.jpg +3 -0
  37. OMRChecker/outputs/CheckedOMRs/OcrSheetMarked.jpg +3 -0
  38. OMRChecker/outputs/Images/CheckedOMRs/OMRSheet.jpg +3 -0
  39. OMRChecker/outputs/Images/Manual/ErrorFiles.csv +1 -0
  40. OMRChecker/outputs/Images/Manual/MultiMarkedFiles.csv +1 -0
  41. OMRChecker/outputs/Images/Results/Results_10PM.csv +2 -0
  42. OMRChecker/outputs/Manual/ErrorFiles.csv +3 -0
  43. OMRChecker/outputs/Manual/MultiMarkedFiles.csv +1 -0
  44. OMRChecker/outputs/MobileCamera/Manual/ErrorFiles.csv +1 -0
  45. OMRChecker/outputs/MobileCamera/Manual/MultiMarkedFiles.csv +1 -0
  46. OMRChecker/outputs/MobileCamera/Results/Results_09PM.csv +1 -0
  47. OMRChecker/pyproject.toml +18 -0
  48. OMRChecker/pytest.ini +6 -0
  49. OMRChecker/requirements.dev.txt +7 -0
  50. OMRChecker/requirements.txt +8 -0
.dockerignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ .git
2
+ .env
3
+ .claude
4
+ __pycache__
5
+ *.pyc
6
+ outputs/
.env.example ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # Required
2
+ GEMINI_API_KEY=your_gemini_api_key
3
+ SUPABASE_URL=your_supabase_project_url
4
+ SUPABASE_ANON_KEY=your_supabase_anon_key
5
+
6
+ # Optional (auto-detected on Linux, only needed for custom installs)
7
+ # TESSERACT_CMD=/usr/bin/tesseract
8
+ # POPPLER_PATH=/usr/bin
9
+ # PORT=7860
10
+ # FLASK_DEBUG=false
.gitattributes CHANGED
@@ -1,35 +1,44 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
3
+ Images/OCRSheet.jpg filter=lfs diff=lfs merge=lfs -text
4
+ Images/OcrSheetMarked.jpg filter=lfs diff=lfs merge=lfs -text
5
+ Images/omr_answer_key.pdf filter=lfs diff=lfs merge=lfs -text
6
+ Images/omr_answer_key.png filter=lfs diff=lfs merge=lfs -text
7
+ Images/OMRSheet.jpg filter=lfs diff=lfs merge=lfs -text
8
+ Images/OMRSheet2.jpg filter=lfs diff=lfs merge=lfs -text
9
+ Images/OMRSheet3.jpg filter=lfs diff=lfs merge=lfs -text
10
+ Images/OMRTest.jpg filter=lfs diff=lfs merge=lfs -text
11
+ Images/question_paper.png filter=lfs diff=lfs merge=lfs -text
12
+ Images/test.jpg filter=lfs diff=lfs merge=lfs -text
13
+ OMRChecker/inputs/OMRImage.jpg filter=lfs diff=lfs merge=lfs -text
14
+ OMRChecker/outputs/CheckedOMRs/OcrSheetMarked.jpg filter=lfs diff=lfs merge=lfs -text
15
+ OMRChecker/outputs/CheckedOMRs/OMRImage.jpg filter=lfs diff=lfs merge=lfs -text
16
+ OMRChecker/outputs/CheckedOMRs/OMRSheet.jpg filter=lfs diff=lfs merge=lfs -text
17
+ OMRChecker/outputs/Images/CheckedOMRs/OMRSheet.jpg filter=lfs diff=lfs merge=lfs -text
18
+ OMRChecker/samples/answer-key/weighted-answers/images/adrian_omr.png filter=lfs diff=lfs merge=lfs -text
19
+ OMRChecker/samples/community/Sandeep-1507/omr-1.png filter=lfs diff=lfs merge=lfs -text
20
+ OMRChecker/samples/community/Sandeep-1507/omr-2.png filter=lfs diff=lfs merge=lfs -text
21
+ OMRChecker/samples/community/Sandeep-1507/omr-3.png filter=lfs diff=lfs merge=lfs -text
22
+ OMRChecker/samples/community/Shamanth/omr_sheet_01.png filter=lfs diff=lfs merge=lfs -text
23
+ OMRChecker/samples/community/UmarFarootAPS/scans/scan-type-1.jpg filter=lfs diff=lfs merge=lfs -text
24
+ OMRChecker/samples/community/UmarFarootAPS/scans/scan-type-2.jpg filter=lfs diff=lfs merge=lfs -text
25
+ OMRChecker/samples/community/UPSC-mock/answer_key.jpg filter=lfs diff=lfs merge=lfs -text
26
+ OMRChecker/samples/community/UPSC-mock/scan-angles/angle-1.jpg filter=lfs diff=lfs merge=lfs -text
27
+ OMRChecker/samples/community/UPSC-mock/scan-angles/angle-2.jpg filter=lfs diff=lfs merge=lfs -text
28
+ OMRChecker/samples/community/UPSC-mock/scan-angles/angle-3.jpg filter=lfs diff=lfs merge=lfs -text
29
+ OMRChecker/samples/sample1/MobileCamera/sheet1.jpg filter=lfs diff=lfs merge=lfs -text
30
+ OMRChecker/samples/sample2/AdrianSample/adrian_omr.png filter=lfs diff=lfs merge=lfs -text
31
+ OMRChecker/samples/sample3/colored-thick-sheet/rgb-100-gsm.jpg filter=lfs diff=lfs merge=lfs -text
32
+ OMRChecker/samples/sample3/xeroxed-thin-sheet/grayscale-80-gsm.jpg filter=lfs diff=lfs merge=lfs -text
33
+ OMRChecker/samples/sample4/IMG_20201116_143512.jpg filter=lfs diff=lfs merge=lfs -text
34
+ OMRChecker/samples/sample4/IMG_20201116_150717658.jpg filter=lfs diff=lfs merge=lfs -text
35
+ OMRChecker/samples/sample4/IMG_20201116_150750830.jpg filter=lfs diff=lfs merge=lfs -text
36
+ OMRChecker/samples/sample5/ScanBatch1/camscanner-1.jpg filter=lfs diff=lfs merge=lfs -text
37
+ OMRChecker/samples/sample5/ScanBatch2/camscanner-2.jpg filter=lfs diff=lfs merge=lfs -text
38
+ OMRChecker/samples/sample6/doc-scans/sample_roll_01.jpg filter=lfs diff=lfs merge=lfs -text
39
+ OMRChecker/samples/sample6/doc-scans/sample_roll_02.jpg filter=lfs diff=lfs merge=lfs -text
40
+ OMRChecker/samples/sample6/doc-scans/sample_roll_03.jpg filter=lfs diff=lfs merge=lfs -text
41
+ OMRChecker/samples/sample6/reference.png filter=lfs diff=lfs merge=lfs -text
42
+ OMRChecker/src/tests/test_samples/sample2/sample.jpg filter=lfs diff=lfs merge=lfs -text
43
+ output/test_ocr_res_img.jpg filter=lfs diff=lfs merge=lfs -text
44
+ output/test_preprocessed_img.jpg filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+
110
+ # pdm
111
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
112
+ #pdm.lock
113
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
114
+ # in version control.
115
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
116
+ .pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
121
+ __pypackages__/
122
+
123
+ # Celery stuff
124
+ celerybeat-schedule
125
+ celerybeat.pid
126
+
127
+ # SageMath parsed files
128
+ *.sage.py
129
+
130
+ # Environments
131
+ .env
132
+ .venv
133
+ env/
134
+ venv/
135
+ ENV/
136
+ env.bak/
137
+ venv.bak/
138
+
139
+ # Spyder project settings
140
+ .spyderproject
141
+ .spyproject
142
+
143
+ # Rope project settings
144
+ .ropeproject
145
+
146
+ # mkdocs documentation
147
+ /site
148
+
149
+ # mypy
150
+ .mypy_cache/
151
+ .dmypy.json
152
+ dmypy.json
153
+
154
+ # Pyre type checker
155
+ .pyre/
156
+
157
+ # pytype static type analyzer
158
+ .pytype/
159
+
160
+ # Cython debug symbols
161
+ cython_debug/
162
+
163
+ # PyCharm
164
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
165
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
166
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
167
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
168
+ #.idea/
169
+
170
+ # App outputs
171
+ outputs/
172
+ .claude/
173
+
174
+ # Temp/debug images
175
+ Images/debug_*.png
176
+
177
+ # Ruff stuff:
178
+ .ruff_cache/
179
+
180
+ # PyPI configuration file
181
+ .pypirc
182
+
183
+ # Cursor
184
+ # Cursor is an AI-powered code editor.`.cursorignore` specifies files/directories to
185
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
186
+ # refer to https://docs.cursor.com/context/ignore-files
187
+ .cursorignore
188
+ .cursorindexingignore
Dockerfile ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ # System deps: tesseract, poppler, opencv libs
4
+ RUN apt-get update && apt-get install -y --no-install-recommends \
5
+ tesseract-ocr \
6
+ poppler-utils \
7
+ libgl1 \
8
+ libglib2.0-0 \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ WORKDIR /app
12
+
13
+ # Install CPU-only PyTorch first (avoids ~4GB of NVIDIA CUDA libs)
14
+ RUN pip install --no-cache-dir torch torchvision --index-url https://download.pytorch.org/whl/cpu
15
+
16
+ # Install remaining Python deps
17
+ COPY requirements.txt .
18
+ RUN pip install --no-cache-dir -r requirements.txt
19
+
20
+ # Copy application code
21
+ COPY . .
22
+
23
+ # Create required directories
24
+ RUN mkdir -p OMRChecker/inputs outputs/Results outputs/CheckedOMRs outputs/Manual outputs/Evaluation Images
25
+
26
+ # HF Spaces expects port 7860
27
+ ENV PORT=7860
28
+ EXPOSE 7860
29
+
30
+ CMD ["python", "app.py"]
Images/GK_Question_Paper_A4.pdf ADDED
Binary file (2.26 kB). View file
 
Images/OCR2.jpg ADDED
Images/OCRSheet.jpg ADDED

Git LFS Details

  • SHA256: 76d3a863bc910ffa2de222ead17eb7021999e594c9fd5a6a0116dc3ed7149fff
  • Pointer size: 131 Bytes
  • Size of remote file: 113 kB
Images/OCRTest.pdf ADDED
Binary file (85.5 kB). View file
 
Images/OMRSheet.jpg ADDED

Git LFS Details

  • SHA256: 4439b6a479cb9fea92de9656b900a528052616ae8e8962a6c33b8e81ed7f327a
  • Pointer size: 131 Bytes
  • Size of remote file: 267 kB
Images/OMRSheet2.jpg ADDED

Git LFS Details

  • SHA256: 4c6661dce53a4ff8292ee218a2acf5f0aa921c3f337cc0117bda6c71f487735b
  • Pointer size: 131 Bytes
  • Size of remote file: 233 kB
Images/OMRSheet3.jpg ADDED

Git LFS Details

  • SHA256: 2072f72607f9e9363cba21b700c86e5dffd3fce0cf2d7e2d1288c23b5066b257
  • Pointer size: 131 Bytes
  • Size of remote file: 238 kB
Images/OMRTest.jpg ADDED

Git LFS Details

  • SHA256: daaa90fa7b3fe40fbf1dd0fee2941de0c0d138290f1d32523979b95bcd253907
  • Pointer size: 131 Bytes
  • Size of remote file: 273 kB
Images/OcrSheetMarked.jpg ADDED

Git LFS Details

  • SHA256: 328a515ffb5367799509a284fc85bca8114508337db76049e86c9c8415b96221
  • Pointer size: 131 Bytes
  • Size of remote file: 221 kB
Images/omr_answer_key.pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:879c8f7aa369a6f0cbc65f9a5279a18ae42a35d541ba53e70b140178e83acf3f
3
+ size 105714
Images/omr_answer_key.png ADDED

Git LFS Details

  • SHA256: 4439b6a479cb9fea92de9656b900a528052616ae8e8962a6c33b8e81ed7f327a
  • Pointer size: 131 Bytes
  • Size of remote file: 267 kB
Images/question.png ADDED
Images/question_paper.pdf ADDED
Binary file (85.5 kB). View file
 
Images/question_paper.png ADDED

Git LFS Details

  • SHA256: ebf1ff49a9b76cf2259890ec30c7c369f60c900331d06bc81d096e2d3efbe134
  • Pointer size: 131 Bytes
  • Size of remote file: 200 kB
Images/test.jpg ADDED

Git LFS Details

  • SHA256: dc40095b38d1a4e8248d464ba1e14d943e6ce2eaf5a0173316c4ce3bcbfabf5e
  • Pointer size: 131 Bytes
  • Size of remote file: 332 kB
OMRChecker/.pre-commit-config.yaml ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ exclude: "__snapshots__/.*$"
2
+ default_install_hook_types: [pre-commit, pre-push]
3
+ repos:
4
+ - repo: https://github.com/pre-commit/pre-commit-hooks
5
+ rev: v4.4.0
6
+ hooks:
7
+ - id: check-yaml
8
+ stages: [commit]
9
+ - id: check-added-large-files
10
+ args: ['--maxkb=300']
11
+ fail_fast: false
12
+ stages: [commit]
13
+ - id: pretty-format-json
14
+ args: ['--autofix', '--no-sort-keys']
15
+ - id: end-of-file-fixer
16
+ exclude_types: ["csv", "json"]
17
+ stages: [commit]
18
+ - id: trailing-whitespace
19
+ stages: [commit]
20
+ - repo: https://github.com/pycqa/isort
21
+ rev: 5.12.0
22
+ hooks:
23
+ - id: isort
24
+ args: ["--profile", "black"]
25
+ stages: [commit]
26
+ - repo: https://github.com/psf/black
27
+ rev: 23.3.0
28
+ hooks:
29
+ - id: black
30
+ fail_fast: true
31
+ stages: [commit]
32
+ - repo: https://github.com/pycqa/flake8
33
+ rev: 6.0.0
34
+ hooks:
35
+ - id: flake8
36
+ args:
37
+ - "--ignore=E501,W503,E203,E741,F541" # Line too long, Line break occurred before a binary operator, Whitespace before ':'
38
+ fail_fast: true
39
+ stages: [commit]
40
+ - repo: local
41
+ hooks:
42
+ - id: pytest-on-commit
43
+ name: Running single sample test
44
+ entry: python3 -m pytest -rfpsxEX --disable-warnings --verbose -k sample1
45
+ language: system
46
+ pass_filenames: false
47
+ always_run: true
48
+ fail_fast: true
49
+ stages: [commit]
50
+ - repo: local
51
+ hooks:
52
+ - id: pytest-on-push
53
+ name: Running all tests before push...
54
+ entry: python3 -m pytest -rfpsxEX --disable-warnings --verbose --durations=3
55
+ language: system
56
+ pass_filenames: false
57
+ always_run: true
58
+ fail_fast: true
59
+ stages: [push]
OMRChecker/.pylintrc ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [BASIC]
2
+ # Regular expression matching correct variable names. Overrides variable-naming-style.
3
+ # snake_case with single letter regex -
4
+ variable-rgx=[a-z0-9_]{1,30}$
5
+
6
+ # Good variable names which should always be accepted, separated by a comma.
7
+ good-names=x,y,pt
8
+
9
+ [MESSAGES CONTROL]
10
+
11
+ # Disable the message, report, category or checker with the given id(s). You
12
+ # can either give multiple identifiers separated by comma (,) or put this
13
+ # option multiple times (only on the command line, not in the configuration
14
+ # file where it should appear only once). You can also use "--disable=all" to
15
+ # disable everything first and then reenable specific checks. For example, if
16
+ # you want to run only the similarities checker, you can use "--disable=all
17
+ # --enable=similarities". If you want to run only the classes checker, but have
18
+ # no Warning level messages displayed, use "--disable=all --enable=classes
19
+ # --disable=W".
20
+ disable=import-error,
21
+ unresolved-import,
22
+ too-few-public-methods,
23
+ missing-docstring,
24
+ relative-beyond-top-level,
25
+ too-many-instance-attributes,
26
+ bad-continuation,
27
+ no-member
28
+
29
+ # Note: bad-continuation is a false positive showing bug in pylint
30
+ # https://github.com/psf/black/issues/48
31
+
32
+
33
+ [REPORTS]
34
+ # Set the output format. Available formats are text, parseable, colorized, json
35
+ # and msvs (visual studio). You can also give a reporter class, e.g.
36
+ # mypackage.mymodule.MyReporterClass.
37
+ output-format=text
38
+
39
+ # Tells whether to display a full report or only the messages.
40
+ reports=no
41
+
42
+ # Activate the evaluation score.
43
+ score=yes
OMRChecker/CODE_OF_CONDUCT.md ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- https://www.contributor-covenant.org/version/2/1/code_of_conduct/code_of_conduct.md -->
2
+ # Contributor Covenant Code of Conduct
3
+
4
+ ## Our Pledge
5
+
6
+ We as members, contributors, and leaders pledge to make participation in our
7
+ community a harassment-free experience for everyone, regardless of age, body
8
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
9
+ identity and expression, level of experience, education, socio-economic status,
10
+ nationality, personal appearance, race, caste, color, religion, or sexual
11
+ identity and orientation.
12
+
13
+ We pledge to act and interact in ways that contribute to an open, welcoming,
14
+ diverse, inclusive, and healthy community.
15
+
16
+ ## Our Standards
17
+
18
+ Examples of behavior that contributes to a positive environment for our
19
+ community include:
20
+
21
+ * Demonstrating empathy and kindness toward other people
22
+ * Being respectful of differing opinions, viewpoints, and experiences
23
+ * Giving and gracefully accepting constructive feedback
24
+ * Accepting responsibility and apologizing to those affected by our mistakes,
25
+ and learning from the experience
26
+ * Focusing on what is best not just for us as individuals, but for the overall
27
+ community
28
+
29
+ Examples of unacceptable behavior include:
30
+
31
+ * The use of sexualized language or imagery, and sexual attention or advances of
32
+ any kind
33
+ * Trolling, insulting or derogatory comments, and personal or political attacks
34
+ * Public or private harassment
35
+ * Publishing others' private information, such as a physical or email address,
36
+ without their explicit permission
37
+ * Other conduct which could reasonably be considered inappropriate in a
38
+ professional setting
39
+
40
+ ## Enforcement Responsibilities
41
+
42
+ Community leaders are responsible for clarifying and enforcing our standards of
43
+ acceptable behavior and will take appropriate and fair corrective action in
44
+ response to any behavior that they deem inappropriate, threatening, offensive,
45
+ or harmful.
46
+
47
+ Community leaders have the right and responsibility to remove, edit, or reject
48
+ comments, commits, code, wiki edits, issues, and other contributions that are
49
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
50
+ decisions when appropriate.
51
+
52
+ ## Scope
53
+
54
+ This Code of Conduct applies within all community spaces, and also applies when
55
+ an individual is officially representing the community in public spaces.
56
+ Examples of representing our community include using an official email address,
57
+ posting via an official social media account, or acting as an appointed
58
+ representative at an online or offline event.
59
+
60
+ ## Enforcement
61
+
62
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
63
+ reported to the community leaders responsible for enforcement at
64
+ [INSERT CONTACT METHOD].
65
+ All complaints will be reviewed and investigated promptly and fairly.
66
+
67
+ All community leaders are obligated to respect the privacy and security of the
68
+ reporter of any incident.
69
+
70
+ ## Enforcement Guidelines
71
+
72
+ Community leaders will follow these Community Impact Guidelines in determining
73
+ the consequences for any action they deem in violation of this Code of Conduct:
74
+
75
+ ### 1. Correction
76
+
77
+ **Community Impact**: Use of inappropriate language or other behavior deemed
78
+ unprofessional or unwelcome in the community.
79
+
80
+ **Consequence**: A private, written warning from community leaders, providing
81
+ clarity around the nature of the violation and an explanation of why the
82
+ behavior was inappropriate. A public apology may be requested.
83
+
84
+ ### 2. Warning
85
+
86
+ **Community Impact**: A violation through a single incident or series of
87
+ actions.
88
+
89
+ **Consequence**: A warning with consequences for continued behavior. No
90
+ interaction with the people involved, including unsolicited interaction with
91
+ those enforcing the Code of Conduct, for a specified period of time. This
92
+ includes avoiding interactions in community spaces as well as external channels
93
+ like social media. Violating these terms may lead to a temporary or permanent
94
+ ban.
95
+
96
+ ### 3. Temporary Ban
97
+
98
+ **Community Impact**: A serious violation of community standards, including
99
+ sustained inappropriate behavior.
100
+
101
+ **Consequence**: A temporary ban from any sort of interaction or public
102
+ communication with the community for a specified period of time. No public or
103
+ private interaction with the people involved, including unsolicited interaction
104
+ with those enforcing the Code of Conduct, is allowed during this period.
105
+ Violating these terms may lead to a permanent ban.
106
+
107
+ ### 4. Permanent Ban
108
+
109
+ **Community Impact**: Demonstrating a pattern of violation of community
110
+ standards, including sustained inappropriate behavior, harassment of an
111
+ individual, or aggression toward or disparagement of classes of individuals.
112
+
113
+ **Consequence**: A permanent ban from any sort of public interaction within the
114
+ community.
115
+
116
+ ## Attribution
117
+
118
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
119
+ version 2.1, available at
120
+ [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
121
+
122
+ Community Impact Guidelines were inspired by
123
+ [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
124
+
125
+ For answers to common questions about this code of conduct, see the FAQ at
126
+ [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
127
+ [https://www.contributor-covenant.org/translations][translations].
128
+
129
+ [homepage]: https://www.contributor-covenant.org
130
+ [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
131
+ [Mozilla CoC]: https://github.com/mozilla/diversity
132
+ [FAQ]: https://www.contributor-covenant.org/faq
133
+ [translations]: https://www.contributor-covenant.org/translations
OMRChecker/CONTRIBUTING.md ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # How to contribute
2
+ So you want to write code and get it landed in the official OMRChecker repository?
3
+ First, fork our repository into your own GitHub account, and create a local clone of it as described in the installation instructions.
4
+ The latter will be used to get new features implemented or bugs fixed.
5
+
6
+ Once done and you have the code locally on the disk, you can get started. We advise you to not work directly on the master branch,
7
+ but to create a separate branch for each issue you are working on. That way you can easily switch between different work,
8
+ and you can update each one for the latest changes on the upstream master individually.
9
+
10
+
11
+ # Writing Code
12
+ For writing the code just follow the [Pep8 Python style](https://peps.python.org/pep-0008/) guide, If there is something unclear about the style, just look at existing code which might help you to understand it better.
13
+
14
+ Also, try to use commits with [conventional messages](https://www.conventionalcommits.org/en/v1.0.0/#summary).
15
+
16
+
17
+ # Code Formatting
18
+ Before committing your code, make sure to run the following command to format your code according to the PEP8 style guide:
19
+ ```.sh
20
+ pip install -r requirements.dev.txt && pre-commit install
21
+ ```
22
+
23
+ Run `pre-commit` before committing your changes:
24
+ ```.sh
25
+ git add .
26
+ pre-commit run -a
27
+ ```
28
+
29
+ # Where to contribute from
30
+
31
+ - You can pickup any open [issues](https://github.com/Udayraj123/OMRChecker/issues) to solve.
32
+ - You can also check out the [ideas list](https://github.com/users/Udayraj123/projects/2/views/1)
OMRChecker/Contributors.md ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Contributors
2
+
3
+ - [Udayraj123](https://github.com/Udayraj123)
4
+ - [leongwaikay](https://github.com/leongwaikay)
5
+ - [deepakgouda](https://github.com/deepakgouda)
6
+ - [apurva91](https://github.com/apurva91)
7
+ - [sparsh2706](https://github.com/sparsh2706)
8
+ - [namit2saxena](https://github.com/namit2saxena)
9
+ - [Harsh-Kapoorr](https://github.com/Harsh-Kapoorr)
10
+ - [Sandeep-1507](https://github.com/Sandeep-1507)
11
+ - [SpyzzVVarun](https://github.com/SpyzzVVarun)
12
+ - [asc249](https://github.com/asc249)
13
+ - [05Alston](https://github.com/05Alston)
14
+ - [Antibodyy](https://github.com/Antibodyy)
15
+ - [infinity1729](https://github.com/infinity1729)
16
+ - [Rohan-G](https://github.com/Rohan-G)
17
+ - [UjjwalMahar](https://github.com/UjjwalMahar)
18
+ - [Kurtsley](https://github.com/Kurtsley)
19
+ - [gaursagar21](https://github.com/gaursagar21)
20
+ - [aayushibansal2001](https://github.com/aayushibansal2001)
21
+ - [ShamanthVallem](https://github.com/ShamanthVallem)
22
+ - [rudrapsc](https://github.com/rudrapsc)
OMRChecker/LICENSE ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present Udayraj Deshmukh and other contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
OMRChecker/README.md ADDED
@@ -0,0 +1,359 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # OMR Checker
2
+
3
+ Read OMR sheets fast and accurately using a scanner 🖨 or your phone 🤳.
4
+
5
+ ## What is OMR?
6
+
7
+ OMR stands for Optical Mark Recognition, used to detect and interpret human-marked data on documents. OMR refers to the process of reading and evaluating OMR sheets, commonly used in exams, surveys, and other forms.
8
+
9
+ #### **Quick Links**
10
+
11
+ - [Installation](#getting-started)
12
+ - [User Guide](https://github.com/Udayraj123/OMRChecker/wiki)
13
+ - [Contributor Guide](https://github.com/Udayraj123/OMRChecker/blob/master/CONTRIBUTING.md)
14
+ - [Project Ideas List](https://github.com/users/Udayraj123/projects/2/views/1)
15
+
16
+ <hr />
17
+
18
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/Udayraj123/OMRChecker/pull/new/master) <!-- [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-brightgreen.svg)](https://github.com/Udayraj123/OMRChecker/wiki/TODOs) -->
19
+ [![GitHub pull-requests closed](https://img.shields.io/github/issues-pr-closed/Udayraj123/OMRChecker.svg)](https://github.com/Udayraj123/OMRChecker/pulls?q=is%3Aclosed)
20
+ [![GitHub issues-closed](https://img.shields.io/github/issues-closed/Udayraj123/OMRChecker.svg)](https://GitHub.com/Udayraj123/OMRChecker/issues?q=is%3Aissue+is%3Aclosed)
21
+ [![Ask me](https://img.shields.io/badge/Discuss-on_Github-purple.svg?style=flat-square)](https://github.com/Udayraj123/OMRChecker/issues/5)
22
+
23
+ <!-- [![GitHub contributors](https://img.shields.io/github/contributors/Udayraj123/OMRChecker.svg)](https://GitHub.com/Udayraj123/OMRChecker/graphs/contributors/) -->
24
+
25
+ [![GitHub stars](https://img.shields.io/github/stars/Udayraj123/OMRChecker.svg?style=social&label=Stars✯)](https://GitHub.com/Udayraj123/OMRChecker/stargazers/)
26
+ [![Join](https://img.shields.io/badge/Join-Discord_group-purple.svg?style=flat-square)](https://discord.gg/qFv2Vqf)
27
+
28
+ <!-- [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/gist/Udayraj123/a125b1531c61cceed5f06994329cba66/omrchecker-on-cloud.ipynb) -->
29
+
30
+ ## 🎯 Features
31
+
32
+ A full-fledged OMR checking software that can read and evaluate OMR sheets scanned at any angle and having any color.
33
+
34
+ | Specs <img width=200/> | ![Current_Speed](https://img.shields.io/badge/Speed-200+_OMRs/min-blue.svg?style=flat-square) ![Min Resolution](https://img.shields.io/badge/Min_Resolution-640x480-blue.svg?style=flat-square) <img width=200/> |
35
+ | :--------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
36
+ | 💯 **Accurate** | Currently nearly 100% accurate on good quality document scans; and about 90% accurate on mobile images. |
37
+ | 💪🏿 **Robust** | Supports low resolution, xeroxed sheets. See [**Robustness**](https://github.com/Udayraj123/OMRChecker/wiki/Robustness) for more. |
38
+ | ⏩ **Fast** | Current processing speed without any optimization is 200 OMRs/minute. |
39
+ | ✅ **Customizable** | [Easily apply](https://github.com/Udayraj123/OMRChecker/wiki/User-Guide) to custom OMR layouts, surveys, etc. |
40
+ | 📊 **Visually Rich** | [Get insights](https://github.com/Udayraj123/OMRChecker/wiki/Rich-Visuals) to configure and debug easily. |
41
+ | 🎈 **Lightweight** | Very minimal core code size. |
42
+ | 🏫 **Large Scale** | Tested on a large scale at [Technothlon](https://en.wikipedia.org/wiki/Technothlon). |
43
+ | 👩🏿‍💻 **Dev Friendly** | [Pylinted](http://pylint.pycqa.org/) and [Black formatted](https://github.com/psf/black) code. Also has a [developer community](https://discord.gg/qFv2Vqf) on discord. |
44
+
45
+ Note: For solving interesting challenges, developers can check out [**TODOs**](https://github.com/Udayraj123/OMRChecker/wiki/TODOs).
46
+
47
+ See the complete guide and details at [Project Wiki](https://github.com/Udayraj123/OMRChecker/wiki/).
48
+
49
+ <!-- 💁🏿‍♂️ **User Friendly** - WIP, Help by contributing! -->
50
+
51
+ ## 💡 What can OMRChecker do for me?
52
+
53
+ Once you configure the OMR layout, just throw images of the sheets at the software; and you'll get back the marked responses in an excel sheet!
54
+
55
+ Images can be taken from various angles as shown below-
56
+
57
+ <p align="center">
58
+ <img alt="sample_input" width="400" src="https://raw.githubusercontent.com/wiki/Udayraj123/OMRChecker/extras/Progress/2019-04-26/images/sample_input.PNG">
59
+ </p>
60
+
61
+ ### Code in action on images taken by scanner:
62
+
63
+ <p align="center">
64
+ <img alt="document_scanner" height="300" src="https://raw.githubusercontent.com/wiki/Udayraj123/OMRChecker/extras/mini_scripts/outputs/gif/document_scanner.gif">
65
+
66
+ </p>
67
+
68
+ ### Code in action on images taken by a mobile phone:
69
+
70
+ <p align="center">
71
+ <img alt="checking_xeroxed_mobile" height="300" src="https://raw.githubusercontent.com/wiki/Udayraj123/OMRChecker/extras/mini_scripts/outputs/gif/checking_xeroxed_mobile.gif">
72
+ </p>
73
+
74
+ ## Visuals
75
+
76
+ ### Processing steps
77
+
78
+ See step-by-step processing of any OMR sheet:
79
+
80
+ <p align="center">
81
+ <a href="https://github.com/Udayraj123/OMRChecker/wiki/Rich-Visuals">
82
+ <img alt="rotation_stack" width="650" src="https://raw.githubusercontent.com/wiki/Udayraj123/OMRChecker/extras/Progress/2019-04-26/images/rotation.PNG">
83
+ </a>
84
+ <br>
85
+ *Note: This image is generated by the code itself!*
86
+ </p>
87
+
88
+ ### Output
89
+
90
+ Get a CSV sheet containing the detected responses and evaluated scores:
91
+
92
+ <p align="center">
93
+ <a href="https://github.com/Udayraj123/OMRChecker/wiki/Rich-Visuals">
94
+ <img alt="csv_output" width="550" src="https://raw.githubusercontent.com/wiki/Udayraj123/OMRChecker/extras/Progress/2019-04-26/images/csv_output.PNG">
95
+ </a>
96
+ </p>
97
+
98
+ We now support [colored outputs](https://github.com/Udayraj123/OMRChecker/wiki/%5Bv2%5D-About-Evaluation) as well. Here's a sample output on another image -
99
+ <p align="center">
100
+ <a href="https://github.com/Udayraj123/OMRChecker/wiki/%5Bv2%5D-About-Evaluation">
101
+ <img alt="colored_output" width="550" src="./docs/assets/colored_output.jpg">
102
+ </a>
103
+ </p>
104
+
105
+ #### There are many more visuals in the wiki. Check them out [here!](https://github.com/Udayraj123/OMRChecker/wiki/Rich-Visuals)
106
+
107
+ ## Getting started
108
+
109
+ ![Setup Time](https://img.shields.io/badge/Setup_Time-20_min-blue.svg)
110
+
111
+ **Operating system:** OSX or Linux is recommended although Windows is also supported.
112
+
113
+ ### 1. Install global dependencies
114
+
115
+ ![opencv 4.0.0](https://img.shields.io/badge/opencv-4.0.0-blue.svg) ![python 3.5+](https://img.shields.io/badge/python-3.5+-blue.svg)
116
+
117
+ To check if python3 and pip is already installed:
118
+
119
+ ```bash
120
+ python3 --version
121
+ python3 -m pip --version
122
+ ```
123
+
124
+ <details>
125
+ <summary><b>Install Python3</b></summary>
126
+
127
+ To install python3 follow instructions [here](https://www.python.org/downloads/)
128
+
129
+ To install pip - follow instructions [here](https://pip.pypa.io/en/stable/installation/)
130
+
131
+ </details>
132
+ <details>
133
+ <summary><b>Install OpenCV</b></summary>
134
+
135
+ **Any installation method is fine.**
136
+
137
+ Recommended:
138
+
139
+ ```bash
140
+ python3 -m pip install --user --upgrade pip
141
+ python3 -m pip install --user opencv-python
142
+ python3 -m pip install --user opencv-contrib-python
143
+ ```
144
+
145
+ More details on pip install openCV [here](https://www.pyimagesearch.com/2018/09/19/pip-install-opencv/).
146
+
147
+ </details>
148
+
149
+ <details>
150
+
151
+ <summary><b>Extra steps(for Linux users only)</b></summary>
152
+
153
+ <b>Installing missing libraries(if any):</b>
154
+
155
+ On a fresh computer, some of the libraries may get missing in event after a successful pip install. Install them using following commands[(ref)](https://www.pyimagesearch.com/2018/05/28/ubuntu-18-04-how-to-install-opencv/):
156
+
157
+ ```bash
158
+ sudo apt-get install -y build-essential cmake unzip pkg-config
159
+ sudo apt-get install -y libjpeg-dev libpng-dev libtiff-dev
160
+ sudo apt-get install -y libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
161
+ sudo apt-get install -y libatlas-base-dev gfortran
162
+ ```
163
+
164
+ </details>
165
+
166
+ ### 2. Install project dependencies
167
+
168
+ Clone the repo
169
+
170
+ ```bash
171
+ git clone https://github.com/Udayraj123/OMRChecker
172
+ cd OMRChecker/
173
+ ```
174
+
175
+ Install pip requirements
176
+
177
+ ```bash
178
+ python3 -m pip install --user -r requirements.txt
179
+ ```
180
+
181
+ _**Note:** If you face a distutils error in pip, use `--ignore-installed` flag in above command._
182
+
183
+ <!-- Wiki should not get cloned -->
184
+
185
+ ### 3. Run the code
186
+
187
+ 1. First copy and examine the sample data to know how to structure your inputs:
188
+ ```bash
189
+ cp -r ./samples/sample1 inputs/
190
+ # Note: you may remove previous inputs (if any) with `mv inputs/* ~/.trash`
191
+ # Change the number N in sampleN to see more examples
192
+ ```
193
+ 2. Run OMRChecker:
194
+ ```bash
195
+ python3 main.py
196
+ ```
197
+
198
+ Alternatively you can also use `python3 main.py -i ./samples/sample1`.
199
+
200
+ Each example in the samples folder demonstrates different ways in which OMRChecker can be used.
201
+
202
+ ### Common Issues
203
+
204
+ <details>
205
+ <summary>
206
+ 1. [Windows] ERROR: Could not open requirements file<br>
207
+ </summary>
208
+ Command: <code>python3 -m pip install --user -r requirements.txt</code>
209
+ <br>
210
+ Link to Solution: <a href="https://github.com/Udayraj123/OMRChecker/issues/54#issuecomment-1264569006">#54</a>
211
+ </details>
212
+ <details>
213
+ <summary>
214
+ 2. [Linux] ERROR: No module named pip<br>
215
+ </summary>
216
+ Command: <code>python3 -m pip install --user --upgrade pip</code>
217
+ <br>
218
+ Link to Solution: <a href="https://github.com/Udayraj123/OMRChecker/issues/70#issuecomment-1268094136">#70</a>
219
+ </details>
220
+
221
+ ## OMRChecker for custom OMR Sheets
222
+
223
+ 1. First, [create your own template.json](https://github.com/Udayraj123/OMRChecker/wiki/User-Guide).
224
+ 2. Configure the tuning parameters.
225
+ 3. Run OMRChecker with appropriate arguments (See full usage).
226
+ <!-- 4. Add answer key( TODO: add answer key/marking scheme guide) -->
227
+
228
+ ## Full Usage
229
+
230
+ ```
231
+ python3 main.py [--setLayout] [--inputDir dir1] [--outputDir dir1]
232
+ ```
233
+
234
+ Explanation for the arguments:
235
+
236
+ `--setLayout`: Set up OMR template layout - modify your json file and run again until the template is set.
237
+
238
+ `--inputDir`: Specify an input directory.
239
+
240
+ `--outputDir`: Specify an output directory.
241
+
242
+ <details>
243
+ <summary>
244
+ <b>Deprecation logs</b>
245
+ </summary>
246
+
247
+ - The old `--noCropping` flag has been replaced with the 'CropPage' plugin in "preProcessors" of the template.json(see [samples](https://github.com/Udayraj123/OMRChecker/tree/master/samples)).
248
+ - The `--autoAlign` flag is deprecated due to low performance on a generic OMR sheet
249
+ - The `--template` flag is deprecated and instead it's recommended to keep the template file at the parent folder containing folders of different images
250
+ </details>
251
+
252
+ <!-- #### Testing the code
253
+ Datasets to test on :
254
+ Low Quality Dataset(For CV Based methods)) (1.5 GB)
255
+ Standard Quality Dataset(For ML Based methods) (3 GB)
256
+ High Quality Dataset(For custom processing) (6 GB)
257
+ -->
258
+
259
+ ## FAQ
260
+
261
+ <details>
262
+ <summary>
263
+ <b>Why is this software free?</b>
264
+ </summary>
265
+
266
+ This project was born out of a student-led organization called as [Technothlon](https://technothlon.techniche.org.in). It is a logic-based international school championship organized by students of IIT Guwahati. Being a non-profit organization, and after seeing it work fabulously at such a large scale we decided to share this tool with the world. The OMR checking processes still involves so much tediousness which we aim to reduce dramatically.
267
+
268
+ We believe in the power of open source! Currently, OMRChecker is in an intermediate stage where only developers can use it. We hope to see it become more user-friendly as well as robust from exposure to different inputs from you all!
269
+
270
+ [![Open Source](https://badges.frapsoft.com/os/v1/open-source.svg?v=103)](https://github.com/ellerbrock/open-source-badges/)
271
+
272
+ </details>
273
+
274
+ <details>
275
+ <summary>
276
+ <b>Can I use this code in my (public) work?</b>
277
+ </summary>
278
+
279
+ OMRChecker can be forked and modified. You are encouraged to play with it and we would love to see your own projects in action!
280
+
281
+ It is published under the [MIT license](https://github.com/Udayraj123/OMRChecker/blob/master/LICENSE).
282
+
283
+ </details>
284
+
285
+ <details>
286
+ <summary>
287
+ <b>What are the ways to contribute?</b>
288
+ </summary>
289
+
290
+ <!-- - Help OMRChecker reach more people by giving a star! The Goal is to reach top position for the [OMR Topic](https://github.com/topics/omr) -->
291
+
292
+ - Join the developer community on [Discord](https://discord.gg/qFv2Vqf) to fix [issues](https://github.com/Udayraj123/OMRChecker/issues) with OMRChecker.
293
+
294
+ - If this project saved you large costs on OMR Software licenses, or saved efforts to make one. Consider donating an amount of your choice(donate section).
295
+
296
+ <!-- ![☕](https://miro.medium.com/fit/c/256/256/1*br7aoq_JVfxeg73x5tF_Sw.png) -->
297
+ <!-- [![paypal.me](https://www.paypalobjects.com/en_GB/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Z5BNNK7AVFVH8&source=url) -->
298
+ <!-- https://www.amazon.in/hz/wishlist/ls/3V0TDQBI3T8IL -->
299
+
300
+ </details>
301
+
302
+ ## Credits
303
+
304
+ _A Huge thanks to:_
305
+ _**Adrian Rosebrock** for his exemplary blog:_ https://pyimagesearch.com
306
+
307
+ _**Harrison Kinsley** aka sentdex for his [video tutorials](https://www.youtube.com/watch?v=Z78zbnLlPUA&list=PLQVvvaa0QuDdttJXlLtAJxJetJcqmqlQq) and many other resources._
308
+
309
+ _**Satya Mallic** for his resourceful blog:_ https://www.learnopencv.com
310
+
311
+ _And to other amazing people from all over the globe who've made significant improvements in this project._
312
+
313
+ _Thank you!_
314
+
315
+ <!--
316
+ OpencV
317
+ matplotlib
318
+ some SO answers from roughworks
319
+ prof
320
+ -->
321
+
322
+ ## Related Projects
323
+
324
+ Here's a snapshot of the [Android OMR Helper App (archived)](https://github.com/Udayraj123/AndroidOMRHelper):
325
+
326
+ <p align="center">
327
+ <a href="https://github.com/Udayraj123/AndroidOMRHelper">
328
+ <img height="300" src="https://raw.githubusercontent.com/wiki/Udayraj123/OMRChecker/extras/Progress/2019-04-26/images/app_flow.PNG">
329
+ </a>
330
+ </p>
331
+
332
+ ## Stargazers over time
333
+
334
+ [![Stargazers over time](https://starchart.cc/Udayraj123/OMRChecker.svg)](https://starchart.cc/Udayraj123/OMRChecker)
335
+
336
+ ---
337
+
338
+ <h2 align="center">Made with ❤️ by Awesome Contributors</h2>
339
+
340
+ <a href="https://github.com/Udayraj123/OMRChecker/graphs/contributors">
341
+ <img src="https://contrib.rocks/image?repo=Udayraj123/OMRChecker" />
342
+ </a>
343
+
344
+ ---
345
+
346
+ ### License
347
+
348
+ [![GitHub license](https://img.shields.io/github/license/Udayraj123/OMRChecker.svg)](https://github.com/Udayraj123/OMRChecker/blob/master/LICENSE)
349
+
350
+ For more details see [LICENSE](https://github.com/Udayraj123/OMRChecker/blob/master/LICENSE).
351
+
352
+ ### Donate
353
+
354
+ <a href="https://www.buymeacoffee.com/Udayraj123" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a> [![paypal](https://www.paypalobjects.com/en_GB/i/btn/btn_donate_LG.gif)](https://www.paypal.me/Udayraj123/500)
355
+
356
+ _Find OMRChecker on_ [**_Product Hunt_**](https://www.producthunt.com/posts/omr-checker/) **|** [**_Reddit_**](https://www.reddit.com/r/computervision/comments/ccbj6f/omrchecker_grade_exams_using_python_and_opencv/) **|** [**Discord**](https://discord.gg/qFv2Vqf) **|** [**Linkedin**](https://www.linkedin.com/pulse/open-source-talks-udayraj-udayraj-deshmukh/) **|** [**goodfirstissue.dev**](https://goodfirstissue.dev/language/python) **|** [**codepeak.tech**](https://www.codepeak.tech/) **|** [**fossoverflow.dev**](https://fossoverflow.dev/projects) **|** [**Interview on Console by CodeSee**](https://console.substack.com/p/console-140) **|** [**Open Source Hub**](https://opensourcehub.io/udayraj123/omrchecker)
357
+
358
+ <!-- [***Hacker News***](https://news.ycombinator.com/item?id=20420602) **|** -->
359
+ <!-- **|** [***Swyya***](https://www.swyya.com/projects/omrchecker) -->
OMRChecker/docs/assets/colored_output.jpg ADDED
OMRChecker/inputs/OMRImage.jpg ADDED

Git LFS Details

  • SHA256: 4439b6a479cb9fea92de9656b900a528052616ae8e8962a6c33b8e81ed7f327a
  • Pointer size: 131 Bytes
  • Size of remote file: 267 kB
OMRChecker/inputs/template.json ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "pageDimensions": [
3
+ 1122,
4
+ 1600
5
+ ],
6
+ "bubbleDimensions": [
7
+ 48,
8
+ 50
9
+ ],
10
+ "fieldBlocks": {
11
+ "q01block": {
12
+ "origin": [
13
+ 100,
14
+ 175
15
+ ],
16
+ "bubblesGap": 55,
17
+ "labelsGap": 67,
18
+ "fieldLabels": [
19
+ "q1..10"
20
+ ],
21
+ "fieldType": "QTYPE_MCQ4"
22
+ },
23
+ "q02block": {
24
+ "origin": [
25
+ 100,
26
+ 845
27
+ ],
28
+ "bubblesGap": 58,
29
+ "labelsGap": 70,
30
+ "fieldLabels": [
31
+ "q11..20"
32
+ ],
33
+ "fieldType": "QTYPE_MCQ4"
34
+ }
35
+ }
36
+
37
+ }
OMRChecker/main.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+
3
+ OMRChecker
4
+
5
+ Author: Udayraj Deshmukh
6
+ Github: https://github.com/Udayraj123
7
+
8
+ """
9
+
10
+ import argparse
11
+ import sys
12
+ from pathlib import Path
13
+
14
+ from src.entry import entry_point
15
+ from src.logger import logger
16
+
17
+
18
+ def parse_args():
19
+ # construct the argument parse and parse the arguments
20
+ argparser = argparse.ArgumentParser()
21
+
22
+ argparser.add_argument(
23
+ "-i",
24
+ "--inputDir",
25
+ default=["inputs"],
26
+ # https://docs.python.org/3/library/argparse.html#nargs
27
+ nargs="*",
28
+ required=False,
29
+ type=str,
30
+ dest="input_paths",
31
+ help="Specify an input directory.",
32
+ )
33
+
34
+ argparser.add_argument(
35
+ "-d",
36
+ "--debug",
37
+ required=False,
38
+ dest="debug",
39
+ action="store_false",
40
+ help="Enables debugging mode for showing detailed errors",
41
+ )
42
+
43
+ argparser.add_argument(
44
+ "-o",
45
+ "--outputDir",
46
+ default="outputs",
47
+ required=False,
48
+ dest="output_dir",
49
+ help="Specify an output directory.",
50
+ )
51
+
52
+ argparser.add_argument(
53
+ "-a",
54
+ "--autoAlign",
55
+ required=False,
56
+ dest="autoAlign",
57
+ action="store_true",
58
+ help="(experimental) Enables automatic template alignment - \
59
+ use if the scans show slight misalignments.",
60
+ )
61
+
62
+ argparser.add_argument(
63
+ "-l",
64
+ "--setLayout",
65
+ required=False,
66
+ dest="setLayout",
67
+ action="store_true",
68
+ help="Set up OMR template layout - modify your json file and \
69
+ run again until the template is set.",
70
+ )
71
+
72
+ (
73
+ args,
74
+ unknown,
75
+ ) = argparser.parse_known_args()
76
+
77
+ args = vars(args)
78
+
79
+ if len(unknown) > 0:
80
+ logger.warning(f"\nError: Unknown arguments: {unknown}", unknown)
81
+ argparser.print_help()
82
+ exit(11)
83
+ return args
84
+
85
+
86
+ def entry_point_for_args(args):
87
+ if args["debug"] is True:
88
+ # Disable tracebacks
89
+ sys.tracebacklimit = 0
90
+ for root in args["input_paths"]:
91
+ entry_point(
92
+ Path(root),
93
+ args,
94
+ )
95
+
96
+
97
+ if __name__ == "__main__":
98
+ args = parse_args()
99
+ entry_point_for_args(args)
OMRChecker/outputs/AdrianSample/Manual/ErrorFiles.csv ADDED
@@ -0,0 +1 @@
 
 
1
+ "file_id","input_path","output_path","score","q1","q2","q3","q4","q5"
OMRChecker/outputs/AdrianSample/Manual/MultiMarkedFiles.csv ADDED
@@ -0,0 +1 @@
 
 
1
+ "file_id","input_path","output_path","score","q1","q2","q3","q4","q5"
OMRChecker/outputs/AdrianSample/Results/Results_07PM.csv ADDED
@@ -0,0 +1 @@
 
 
1
+ "file_id","input_path","output_path","score","q1","q2","q3","q4","q5"
OMRChecker/outputs/CheckedOMRs/OMRImage.jpg ADDED

Git LFS Details

  • SHA256: b9104889d79a25e0550e8e1bd258f1c8520ae1162e41b567d5cdfebad64c2ab4
  • Pointer size: 131 Bytes
  • Size of remote file: 402 kB
OMRChecker/outputs/CheckedOMRs/OMRSheet.jpg ADDED

Git LFS Details

  • SHA256: f16c45dda1d02bf06e33a6d219c8282c363bf3943b94960eede1efe2bc6204d9
  • Pointer size: 131 Bytes
  • Size of remote file: 409 kB
OMRChecker/outputs/CheckedOMRs/OcrSheetMarked.jpg ADDED

Git LFS Details

  • SHA256: b9104889d79a25e0550e8e1bd258f1c8520ae1162e41b567d5cdfebad64c2ab4
  • Pointer size: 131 Bytes
  • Size of remote file: 402 kB
OMRChecker/outputs/Images/CheckedOMRs/OMRSheet.jpg ADDED

Git LFS Details

  • SHA256: 7e9678555042535c83ab920d0b616d4f99f9f08017629d46a15eb64d7c3abd3c
  • Pointer size: 131 Bytes
  • Size of remote file: 407 kB
OMRChecker/outputs/Images/Manual/ErrorFiles.csv ADDED
@@ -0,0 +1 @@
 
 
1
+ "file_id","input_path","output_path","score","q1","q2","q3","q4","q5","q6","q7","q8","q9","q10","q11","q12","q13","q14","q15","q16","q17","q18","q19","q20"
OMRChecker/outputs/Images/Manual/MultiMarkedFiles.csv ADDED
@@ -0,0 +1 @@
 
 
1
+ "file_id","input_path","output_path","score","q1","q2","q3","q4","q5","q6","q7","q8","q9","q10","q11","q12","q13","q14","q15","q16","q17","q18","q19","q20"
OMRChecker/outputs/Images/Results/Results_10PM.csv ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ "file_id","input_path","output_path","score","q1","q2","q3","q4","q5","q6","q7","q8","q9","q10","q11","q12","q13","q14","q15","q16","q17","q18","q19","q20"
2
+ "OMRSheet.jpg","inputs\Images\OMRSheet.jpg","outputs\Images\CheckedOMRs\OMRSheet.jpg","0","C","D","A","C","B","C","C","D","D","B","B","B","D","C","C","ABCD","B","ABCD","C","ABCD"
OMRChecker/outputs/Manual/ErrorFiles.csv ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ "file_id","input_path","output_path","score","q1","q2","q3","q4","q5","q6","q7","q8","q9","q10","q11","q12","q13","q14","q15","q16","q17","q18","q19","q20"
2
+ "OMRSheet.jpg","inputs\OMRSheet.jpg","outputs\Manual\ErrorFiles\OMRSheet.jpg","NA","","","","","","","","","","","","","","","","","","","",""
3
+ "OMRSheet.jpg","inputs\OMRSheet.jpg","outputs\Manual\ErrorFiles\OMRSheet.jpg","NA","","","","","","","","","","","","","","","","","","","",""
OMRChecker/outputs/Manual/MultiMarkedFiles.csv ADDED
@@ -0,0 +1 @@
 
 
1
+ "file_id","input_path","output_path","score","q1","q2","q3","q4","q5","q6","q7","q8","q9","q10","q11","q12","q13","q14","q15","q16","q17","q18","q19","q20"
OMRChecker/outputs/MobileCamera/Manual/ErrorFiles.csv ADDED
@@ -0,0 +1 @@
 
 
1
+ "file_id","input_path","output_path","score","Roll","q1","q2","q3","q4","q5","q6","q7","q8","q9","q10","q11","q12","q13","q14","q15","q16","q17","q18","q19","q20"
OMRChecker/outputs/MobileCamera/Manual/MultiMarkedFiles.csv ADDED
@@ -0,0 +1 @@
 
 
1
+ "file_id","input_path","output_path","score","Roll","q1","q2","q3","q4","q5","q6","q7","q8","q9","q10","q11","q12","q13","q14","q15","q16","q17","q18","q19","q20"
OMRChecker/outputs/MobileCamera/Results/Results_09PM.csv ADDED
@@ -0,0 +1 @@
 
 
1
+ "file_id","input_path","output_path","score","Roll","q1","q2","q3","q4","q5","q6","q7","q8","q9","q10","q11","q12","q13","q14","q15","q16","q17","q18","q19","q20"
OMRChecker/pyproject.toml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [tool.black]
2
+ exclude = '''
3
+ (
4
+ /(
5
+ \.eggs # exclude a few common directories in the
6
+ | \.git # root of the project
7
+ | \.venv
8
+ | _build
9
+ | build
10
+ | dist
11
+ )/
12
+ | foo.py # also separately exclude a file named foo.py in
13
+ # the root of the project
14
+ )
15
+ '''
16
+ include = '\.pyi?$'
17
+ line-length = 88
18
+ target-version = ['py37']
OMRChecker/pytest.ini ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # pytest.ini
2
+ [pytest]
3
+ minversion = 7.0
4
+ addopts = -qq --capture=no
5
+ testpaths =
6
+ src/tests
OMRChecker/requirements.dev.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ -r requirements.txt
2
+ flake8>=6.0.0
3
+ freezegun>=1.2.2
4
+ pre-commit>=3.3.3
5
+ pytest-mock>=3.11.1
6
+ pytest>=7.4.0
7
+ syrupy>=4.0.4
OMRChecker/requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ deepmerge>=1.1.0
2
+ dotmap>=1.3.30
3
+ jsonschema>=4.17.3
4
+ matplotlib>=3.7.1
5
+ numpy>=1.25.0
6
+ pandas>=2.0.2
7
+ rich>=13.4.2
8
+ screeninfo>=0.8.1