falcocv 1.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. falcocv-1.0.1/.gitattributes +3 -0
  2. falcocv-1.0.1/.gitignore +46 -0
  3. falcocv-1.0.1/AGENTS.md +149 -0
  4. falcocv-1.0.1/ARCHITECTURE.md +597 -0
  5. falcocv-1.0.1/CREDITS.md +77 -0
  6. falcocv-1.0.1/LICENSE +674 -0
  7. falcocv-1.0.1/PKG-INFO +273 -0
  8. falcocv-1.0.1/README.md +221 -0
  9. falcocv-1.0.1/TODO.md +28 -0
  10. falcocv-1.0.1/benchmarks/bench_matcher.py +331 -0
  11. falcocv-1.0.1/benchmarks/bench_shape_match.py +190 -0
  12. falcocv-1.0.1/benchmarks/bench_tools.py +256 -0
  13. falcocv-1.0.1/build_kernel.bat +73 -0
  14. falcocv-1.0.1/build_kernel.sh +24 -0
  15. falcocv-1.0.1/cpp/kernel/CMakeLists.txt +42 -0
  16. falcocv-1.0.1/cpp/kernel/src/kernel.cpp +969 -0
  17. falcocv-1.0.1/docs/RELEASING.md +128 -0
  18. falcocv-1.0.1/docs/SMOKE_TEST.md +52 -0
  19. falcocv-1.0.1/docs/hmi_api.api +47 -0
  20. falcocv-1.0.1/examples/README.md +72 -0
  21. falcocv-1.0.1/examples/build_demo_job.py +133 -0
  22. falcocv-1.0.1/examples/demo.hmi +51 -0
  23. falcocv-1.0.1/examples/demo_inspection.cvj +0 -0
  24. falcocv-1.0.1/examples/demo_job1.cvj +0 -0
  25. falcocv-1.0.1/examples/demo_job2.cvj +0 -0
  26. falcocv-1.0.1/examples/generate_demo.py +78 -0
  27. falcocv-1.0.1/examples/generate_demo_images.py +233 -0
  28. falcocv-1.0.1/examples/images/01_ok.jpg +0 -0
  29. falcocv-1.0.1/examples/images/02_ok.jpg +0 -0
  30. falcocv-1.0.1/examples/images/03_ok.jpg +0 -0
  31. falcocv-1.0.1/examples/images/04_ok.jpg +0 -0
  32. falcocv-1.0.1/examples/images/05_ok.jpg +0 -0
  33. falcocv-1.0.1/examples/images/06_ok.jpg +0 -0
  34. falcocv-1.0.1/examples/images/07_ok.jpg +0 -0
  35. falcocv-1.0.1/examples/images/08_ok.jpg +0 -0
  36. falcocv-1.0.1/examples/images/09_ok_scratch.jpg +0 -0
  37. falcocv-1.0.1/examples/images/10_ok_stain.jpg +0 -0
  38. falcocv-1.0.1/examples/images/11_ng_missing_hole.jpg +0 -0
  39. falcocv-1.0.1/examples/images/12_ng_blocked_hole.jpg +0 -0
  40. falcocv-1.0.1/examples/images/13_ng_extra_hole.jpg +0 -0
  41. falcocv-1.0.1/examples/images/14_ng_holes_too_close.jpg +0 -0
  42. falcocv-1.0.1/examples/images/manifest.json +143 -0
  43. falcocv-1.0.1/examples/render_demo_result.py +45 -0
  44. falcocv-1.0.1/examples/result_ng.jpg +0 -0
  45. falcocv-1.0.1/examples/result_ok.jpg +0 -0
  46. falcocv-1.0.1/examples/train/part_reference.png +0 -0
  47. falcocv-1.0.1/plans/falcocv-plan-v2.md +472 -0
  48. falcocv-1.0.1/plans/opencv5_opportunities.md +411 -0
  49. falcocv-1.0.1/pyproject.toml +144 -0
  50. falcocv-1.0.1/requirements.txt +27 -0
  51. falcocv-1.0.1/scripts/check_wheel.py +95 -0
  52. falcocv-1.0.1/scripts/download_ocr_models.py +56 -0
  53. falcocv-1.0.1/scripts/export_effnet_b0.py +48 -0
  54. falcocv-1.0.1/scripts/export_effnet_multilayer.py +108 -0
  55. falcocv-1.0.1/scripts/export_resnet_layer3.py +71 -0
  56. falcocv-1.0.1/scripts/export_resnet_patchcore.py +72 -0
  57. falcocv-1.0.1/scripts/wheel_smoke.py +131 -0
  58. falcocv-1.0.1/specifications/falcocv.md +68 -0
  59. falcocv-1.0.1/specifications/third-party/anomaly_detector_spec.md +1071 -0
  60. falcocv-1.0.1/specifications/third-party/edge_classifier_opinionated_spec.md +993 -0
  61. falcocv-1.0.1/specifications/third-party/edge_learning_classifier_spec.md +2286 -0
  62. falcocv-1.0.1/specifications/third-party/ocr_industrial_spec.md +1583 -0
  63. falcocv-1.0.1/src/falcocv/__init__.py +5 -0
  64. falcocv-1.0.1/src/falcocv/__main__.py +4 -0
  65. falcocv-1.0.1/src/falcocv/accuracy/__init__.py +1 -0
  66. falcocv-1.0.1/src/falcocv/accuracy/synthetic.py +206 -0
  67. falcocv-1.0.1/src/falcocv/cli.py +23 -0
  68. falcocv-1.0.1/src/falcocv/core/__init__.py +27 -0
  69. falcocv-1.0.1/src/falcocv/core/anomaly/__init__.py +0 -0
  70. falcocv-1.0.1/src/falcocv/core/anomaly/backbone_effnet.py +92 -0
  71. falcocv-1.0.1/src/falcocv/core/anomaly/backbone_layer2.py +93 -0
  72. falcocv-1.0.1/src/falcocv/core/anomaly/detector.py +481 -0
  73. falcocv-1.0.1/src/falcocv/core/anomaly/memory.py +135 -0
  74. falcocv-1.0.1/src/falcocv/core/anomaly/patch_backbone.py +89 -0
  75. falcocv-1.0.1/src/falcocv/core/anomaly/patch_memory.py +178 -0
  76. falcocv-1.0.1/src/falcocv/core/anomaly/simple_memory.py +108 -0
  77. falcocv-1.0.1/src/falcocv/core/classifier/__init__.py +0 -0
  78. falcocv-1.0.1/src/falcocv/core/classifier/classifier_memory.py +119 -0
  79. falcocv-1.0.1/src/falcocv/core/classifier/inference.py +103 -0
  80. falcocv-1.0.1/src/falcocv/core/classifier/projection.py +42 -0
  81. falcocv-1.0.1/src/falcocv/core/classifier/trainer.py +10 -0
  82. falcocv-1.0.1/src/falcocv/core/classifier/trainer_numpy.py +208 -0
  83. falcocv-1.0.1/src/falcocv/core/config.py +186 -0
  84. falcocv-1.0.1/src/falcocv/core/config_paths.py +38 -0
  85. falcocv-1.0.1/src/falcocv/core/depth_viz.py +148 -0
  86. falcocv-1.0.1/src/falcocv/core/environment.py +134 -0
  87. falcocv-1.0.1/src/falcocv/core/hmi.py +675 -0
  88. falcocv-1.0.1/src/falcocv/core/job_manager.py +72 -0
  89. falcocv-1.0.1/src/falcocv/core/models.py +174 -0
  90. falcocv-1.0.1/src/falcocv/core/ocr/__init__.py +6 -0
  91. falcocv-1.0.1/src/falcocv/core/ocr/industrial_ocr_engine.py +394 -0
  92. falcocv-1.0.1/src/falcocv/core/overlay_layer.py +438 -0
  93. falcocv-1.0.1/src/falcocv/core/plane_fit.py +290 -0
  94. falcocv-1.0.1/src/falcocv/core/pointcloud_utils.py +570 -0
  95. falcocv-1.0.1/src/falcocv/core/results.py +26 -0
  96. falcocv-1.0.1/src/falcocv/core/roi_3d.py +302 -0
  97. falcocv-1.0.1/src/falcocv/core/roi_utils.py +211 -0
  98. falcocv-1.0.1/src/falcocv/core/script_debugger.py +304 -0
  99. falcocv-1.0.1/src/falcocv/core/tool_base.py +161 -0
  100. falcocv-1.0.1/src/falcocv/core/tool_registry.py +77 -0
  101. falcocv-1.0.1/src/falcocv/core/vision_image.py +755 -0
  102. falcocv-1.0.1/src/falcocv/core/workflow.py +187 -0
  103. falcocv-1.0.1/src/falcocv/core/workflow_controller.py +75 -0
  104. falcocv-1.0.1/src/falcocv/hmi_designer.py +110 -0
  105. falcocv-1.0.1/src/falcocv/main.py +962 -0
  106. falcocv-1.0.1/src/falcocv/run_job.py +214 -0
  107. falcocv-1.0.1/src/falcocv/self_test.py +207 -0
  108. falcocv-1.0.1/src/falcocv/tools/__init__.py +19 -0
  109. falcocv-1.0.1/src/falcocv/tools/anomaly_detector/__init__.py +6 -0
  110. falcocv-1.0.1/src/falcocv/tools/anomaly_detector/config.py +706 -0
  111. falcocv-1.0.1/src/falcocv/tools/anomaly_detector/logic.py +251 -0
  112. falcocv-1.0.1/src/falcocv/tools/barcode_decoder/__init__.py +6 -0
  113. falcocv-1.0.1/src/falcocv/tools/barcode_decoder/config.py +392 -0
  114. falcocv-1.0.1/src/falcocv/tools/barcode_decoder/logic.py +666 -0
  115. falcocv-1.0.1/src/falcocv/tools/blob_detector/__init__.py +6 -0
  116. falcocv-1.0.1/src/falcocv/tools/blob_detector/config.py +264 -0
  117. falcocv-1.0.1/src/falcocv/tools/blob_detector/logic.py +208 -0
  118. falcocv-1.0.1/src/falcocv/tools/block/__init__.py +6 -0
  119. falcocv-1.0.1/src/falcocv/tools/block/config.py +154 -0
  120. falcocv-1.0.1/src/falcocv/tools/block/logic.py +45 -0
  121. falcocv-1.0.1/src/falcocv/tools/classifier/__init__.py +6 -0
  122. falcocv-1.0.1/src/falcocv/tools/classifier/config.py +701 -0
  123. falcocv-1.0.1/src/falcocv/tools/classifier/logic.py +350 -0
  124. falcocv-1.0.1/src/falcocv/tools/classifier/train_worker.py +86 -0
  125. falcocv-1.0.1/src/falcocv/tools/depth_range_loader/__init__.py +6 -0
  126. falcocv-1.0.1/src/falcocv/tools/depth_range_loader/config.py +507 -0
  127. falcocv-1.0.1/src/falcocv/tools/depth_range_loader/logic.py +237 -0
  128. falcocv-1.0.1/src/falcocv/tools/edge_detection/__init__.py +6 -0
  129. falcocv-1.0.1/src/falcocv/tools/edge_detection/config.py +321 -0
  130. falcocv-1.0.1/src/falcocv/tools/edge_detection/logic.py +377 -0
  131. falcocv-1.0.1/src/falcocv/tools/filters/__init__.py +6 -0
  132. falcocv-1.0.1/src/falcocv/tools/filters/config.py +466 -0
  133. falcocv-1.0.1/src/falcocv/tools/filters/logic.py +486 -0
  134. falcocv-1.0.1/src/falcocv/tools/fixture_overlay/__init__.py +6 -0
  135. falcocv-1.0.1/src/falcocv/tools/fixture_overlay/config.py +218 -0
  136. falcocv-1.0.1/src/falcocv/tools/fixture_overlay/logic.py +133 -0
  137. falcocv-1.0.1/src/falcocv/tools/gige_camera/__init__.py +6 -0
  138. falcocv-1.0.1/src/falcocv/tools/gige_camera/config.py +504 -0
  139. falcocv-1.0.1/src/falcocv/tools/gige_camera/logic.py +413 -0
  140. falcocv-1.0.1/src/falcocv/tools/histogram/__init__.py +6 -0
  141. falcocv-1.0.1/src/falcocv/tools/histogram/config.py +235 -0
  142. falcocv-1.0.1/src/falcocv/tools/histogram/logic.py +242 -0
  143. falcocv-1.0.1/src/falcocv/tools/image_calculator/__init__.py +6 -0
  144. falcocv-1.0.1/src/falcocv/tools/image_calculator/config.py +493 -0
  145. falcocv-1.0.1/src/falcocv/tools/image_calculator/logic.py +321 -0
  146. falcocv-1.0.1/src/falcocv/tools/image_loader/__init__.py +6 -0
  147. falcocv-1.0.1/src/falcocv/tools/image_loader/config.py +174 -0
  148. falcocv-1.0.1/src/falcocv/tools/image_loader/logic.py +100 -0
  149. falcocv-1.0.1/src/falcocv/tools/measurement/__init__.py +6 -0
  150. falcocv-1.0.1/src/falcocv/tools/measurement/config.py +454 -0
  151. falcocv-1.0.1/src/falcocv/tools/measurement/logic.py +472 -0
  152. falcocv-1.0.1/src/falcocv/tools/ocr/__init__.py +6 -0
  153. falcocv-1.0.1/src/falcocv/tools/ocr/config.py +217 -0
  154. falcocv-1.0.1/src/falcocv/tools/ocr/logic.py +164 -0
  155. falcocv-1.0.1/src/falcocv/tools/pattern_matcher/__init__.py +6 -0
  156. falcocv-1.0.1/src/falcocv/tools/pattern_matcher/config.py +444 -0
  157. falcocv-1.0.1/src/falcocv/tools/pattern_matcher/logic.py +719 -0
  158. falcocv-1.0.1/src/falcocv/tools/plane_fitter/__init__.py +6 -0
  159. falcocv-1.0.1/src/falcocv/tools/plane_fitter/config.py +446 -0
  160. falcocv-1.0.1/src/falcocv/tools/plane_fitter/logic.py +227 -0
  161. falcocv-1.0.1/src/falcocv/tools/python_script/__init__.py +6 -0
  162. falcocv-1.0.1/src/falcocv/tools/python_script/config.py +696 -0
  163. falcocv-1.0.1/src/falcocv/tools/python_script/logic.py +174 -0
  164. falcocv-1.0.1/src/falcocv/tools/shape_match/__init__.py +6 -0
  165. falcocv-1.0.1/src/falcocv/tools/shape_match/config.py +487 -0
  166. falcocv-1.0.1/src/falcocv/tools/shape_match/logic.py +1857 -0
  167. falcocv-1.0.1/src/falcocv/ui/__init__.py +1 -0
  168. falcocv-1.0.1/src/falcocv/ui/adapters/__init__.py +1 -0
  169. falcocv-1.0.1/src/falcocv/ui/adapters/controller_adapter.py +50 -0
  170. falcocv-1.0.1/src/falcocv/ui/assets/brand/FalcoCV_logo_source.jpg +0 -0
  171. falcocv-1.0.1/src/falcocv/ui/assets/favicon.png +0 -0
  172. falcocv-1.0.1/src/falcocv/ui/assets/icon.ico +0 -0
  173. falcocv-1.0.1/src/falcocv/ui/assets/icon_light.ico +0 -0
  174. falcocv-1.0.1/src/falcocv/ui/assets/logo.svg +4 -0
  175. falcocv-1.0.1/src/falcocv/ui/assets/logo_light.svg +4 -0
  176. falcocv-1.0.1/src/falcocv/ui/assets/logo_lockup_dark.png +0 -0
  177. falcocv-1.0.1/src/falcocv/ui/assets/logo_lockup_light.png +0 -0
  178. falcocv-1.0.1/src/falcocv/ui/assets/logo_mark_dark.png +0 -0
  179. falcocv-1.0.1/src/falcocv/ui/assets/logo_mark_light.png +0 -0
  180. falcocv-1.0.1/src/falcocv/ui/safe_refresh.py +21 -0
  181. falcocv-1.0.1/src/falcocv/ui/splash.py +85 -0
  182. falcocv-1.0.1/src/falcocv/ui/style.py +575 -0
  183. falcocv-1.0.1/src/falcocv/ui/tool_config_helpers.py +130 -0
  184. falcocv-1.0.1/src/falcocv/ui/tool_help.py +1660 -0
  185. falcocv-1.0.1/src/falcocv/ui/widgets/__init__.py +1 -0
  186. falcocv-1.0.1/src/falcocv/ui/widgets/contour_editor.py +254 -0
  187. falcocv-1.0.1/src/falcocv/ui/widgets/debug_panels.py +282 -0
  188. falcocv-1.0.1/src/falcocv/ui/widgets/help_dialog.py +408 -0
  189. falcocv-1.0.1/src/falcocv/ui/widgets/hmi_designer_dialog.py +2447 -0
  190. falcocv-1.0.1/src/falcocv/ui/widgets/hmi_preview.py +248 -0
  191. falcocv-1.0.1/src/falcocv/ui/widgets/hmi_scene.py +514 -0
  192. falcocv-1.0.1/src/falcocv/ui/widgets/job_config_dialog.py +60 -0
  193. falcocv-1.0.1/src/falcocv/ui/widgets/roi_editor.py +245 -0
  194. falcocv-1.0.1/src/falcocv/ui/widgets/roi_editor_3d.py +676 -0
  195. falcocv-1.0.1/src/falcocv/ui/widgets/script_editor.py +339 -0
  196. falcocv-1.0.1/src/falcocv/ui/widgets/tool_config_dialog.py +108 -0
  197. falcocv-1.0.1/src/falcocv/ui/widgets/toolbox.py +86 -0
  198. falcocv-1.0.1/src/falcocv/ui/widgets/viewer.py +804 -0
  199. falcocv-1.0.1/src/falcocv/ui/widgets/viewer3d.py +1521 -0
  200. falcocv-1.0.1/src/falcocv/ui/widgets/workflow_editor.py +611 -0
  201. falcocv-1.0.1/src/falcocv/ui/widgets/workflow_tree.py +757 -0
  202. falcocv-1.0.1/src/falcocv/ui/window_geometry.py +39 -0
  203. falcocv-1.0.1/src/falcocv/version.py +20 -0
  204. falcocv-1.0.1/src/falcocv/web/__init__.py +0 -0
  205. falcocv-1.0.1/src/falcocv/web/__main__.py +22 -0
  206. falcocv-1.0.1/src/falcocv/web/controller_adapter.py +57 -0
  207. falcocv-1.0.1/src/falcocv/web/deploy.py +119 -0
  208. falcocv-1.0.1/src/falcocv/web/hmi/dashboard.html +44 -0
  209. falcocv-1.0.1/src/falcocv/web/hmi/dashboard.js +108 -0
  210. falcocv-1.0.1/src/falcocv/web/hmi/favicon.png +0 -0
  211. falcocv-1.0.1/src/falcocv/web/hmi/hmi.css +71 -0
  212. falcocv-1.0.1/src/falcocv/web/hmi/hmi.js +672 -0
  213. falcocv-1.0.1/src/falcocv/web/hmi/index.html +23 -0
  214. falcocv-1.0.1/src/falcocv/web/hmi/logo_lockup_dark.png +0 -0
  215. falcocv-1.0.1/src/falcocv/web/hmi_worker.py +328 -0
  216. falcocv-1.0.1/src/falcocv/web/image_utils.py +34 -0
  217. falcocv-1.0.1/src/falcocv/web/server.py +516 -0
  218. falcocv-1.0.1/src/falcocv/web_runner.py +45 -0
  219. falcocv-1.0.1/tests/__init__.py +1 -0
  220. falcocv-1.0.1/tests/accuracy/__init__.py +1 -0
  221. falcocv-1.0.1/tests/accuracy/test_synthetic.py +53 -0
  222. falcocv-1.0.1/tests/conftest.py +29 -0
  223. falcocv-1.0.1/tests/integration/__init__.py +1 -0
  224. falcocv-1.0.1/tests/integration/helpers.py +37 -0
  225. falcocv-1.0.1/tests/integration/test_demo_job.py +47 -0
  226. falcocv-1.0.1/tests/integration/test_headless_run.py +178 -0
  227. falcocv-1.0.1/tests/integration/test_job_roundtrip.py +72 -0
  228. falcocv-1.0.1/tests/integration/test_pattern_matcher.py +195 -0
  229. falcocv-1.0.1/tests/integration/test_shape_match.py +568 -0
  230. falcocv-1.0.1/tests/integration/test_tool_contract.py +36 -0
  231. falcocv-1.0.1/tests/integration/test_workflow_pipelines.py +155 -0
  232. falcocv-1.0.1/tests/packaging/__init__.py +1 -0
  233. falcocv-1.0.1/tests/packaging/test_wheel_contents.py +23 -0
  234. falcocv-1.0.1/tests/test_barcode_decoder.py +482 -0
  235. falcocv-1.0.1/tests/test_blob_detector_fixture.py +52 -0
  236. falcocv-1.0.1/tests/test_cv_api_compat.py +122 -0
  237. falcocv-1.0.1/tests/test_edge_affine.py +233 -0
  238. falcocv-1.0.1/tests/test_fixture_roi.py +190 -0
  239. falcocv-1.0.1/tests/test_help_import.py +41 -0
  240. falcocv-1.0.1/tests/test_image_viewer_roi_scale.py +95 -0
  241. falcocv-1.0.1/tests/test_kernel_input_validation.py +126 -0
  242. falcocv-1.0.1/tests/test_migrated_tools.py +72 -0
  243. falcocv-1.0.1/tests/test_optional_tools.py +25 -0
  244. falcocv-1.0.1/tests/test_plane_fitter.py +797 -0
  245. falcocv-1.0.1/tests/test_ported_regressions.py +190 -0
  246. falcocv-1.0.1/tests/test_python_support.py +14 -0
  247. falcocv-1.0.1/tests/test_self_test.py +10 -0
  248. falcocv-1.0.1/tests/test_tool_logic_config_split.py +140 -0
  249. falcocv-1.0.1/tests/test_trainer_equivalence.py +149 -0
  250. falcocv-1.0.1/tests/test_viewer3d_handles.py +185 -0
  251. falcocv-1.0.1/tests/test_web_server.py +72 -0
  252. falcocv-1.0.1/tests/test_workflow_tree_array_shape.py +13 -0
  253. falcocv-1.0.1/tests/test_workflow_tree_rename.py +47 -0
  254. falcocv-1.0.1/tests/test_world_coordinates.py +191 -0
  255. falcocv-1.0.1/tests/ui/__init__.py +1 -0
  256. falcocv-1.0.1/tests/ui/conftest.py +48 -0
  257. falcocv-1.0.1/tests/ui/test_main_window.py +121 -0
  258. falcocv-1.0.1/tests/ui/test_tool_configs.py +199 -0
  259. falcocv-1.0.1/tests/web/__init__.py +1 -0
  260. falcocv-1.0.1/tests/web/test_server_api.py +95 -0
@@ -0,0 +1,3 @@
1
+ models/*.onnx binary
2
+ models/*.onnx.data binary
3
+ models/ppocrv5_dict.txt -text
@@ -0,0 +1,46 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ .venv/
6
+ env/
7
+ venv/
8
+ .env
9
+ .pytest_cache/
10
+
11
+ # IDEs
12
+ .vscode/
13
+ .idea/
14
+
15
+ # OS
16
+ Thumbs.db
17
+ .DS_Store
18
+
19
+ # Local models (downloaded by users; not part of the public repo)
20
+ models/
21
+ # Local datasets (e.g. VisA, CC BY 4.0): downloaded on demand, never committed
22
+ datasets/
23
+
24
+ # FalcoCV specific (optional)
25
+ # *.cvj <-- Keep them if you want to include demo jobs
26
+ temp/
27
+ logs/
28
+
29
+ # Local build artifacts
30
+ build/
31
+ dist/
32
+ benchmarks/.legacy/
33
+ benchmarks/__pycache__/
34
+
35
+ # OpenCV 5 source/build (downloaded locally, not part of the repo)
36
+ cpp/opencv5/
37
+ cpp/build/
38
+ cpp/opencv-5.0.0-src.zip
39
+
40
+ # Native kernel build outputs
41
+ *.pyd
42
+ *.dll
43
+ cpp/bin/
44
+
45
+ # Local agent tooling
46
+ .opencode/
@@ -0,0 +1,149 @@
1
+ # FalcoCV — Context Summary
2
+
3
+ Industrial machine vision framework. Python + PyQt6 + OpenCV 5, with a small
4
+ native kernel for the two measured C++ hot paths.
5
+
6
+ ## Architecture
7
+
8
+ ```
9
+ src/falcocv/
10
+ core/ → workflow engine, VisionImage, overlays, ROI, depth/3D helpers
11
+ tools/ → vision tools: logic.py (processing) + config.py (PyQt6 widget)
12
+ ui/ → PyQt6 widgets, viewers, ROI editors, HMI designer
13
+ web/ → FastAPI + HMI worker subprocesses + dashboard
14
+ main.py → Vision Editor entry point
15
+ cli.py → `falcocv` / `python -m falcocv`
16
+ version.py
17
+ cpp/kernel/ → _falco_kernel (pybind11, NO OpenCV):
18
+ · generate_pointcloud
19
+ · plane_fit (LSQ/RANSAC)
20
+ tests/ → pytest suite
21
+ cpp/bin/ → local kernel build output (gitignored)
22
+ ```
23
+
24
+ ### Rules
25
+ - Use **Python/OpenCV/NumPy** for tools unless a measured benchmark shows a
26
+ meaningful (>1.5× end-to-end) win.
27
+ - C++ is reserved for **point-cloud generation**, **plane fitting** and
28
+ measured shape-matching hot paths. Any new C++ hot path must ship with a
29
+ benchmark and live in `cpp/kernel`, not in the old `_cv_core` architecture.
30
+ - The kernel exposes **dict→dict / ndarray functions**, never `BaseTool`,
31
+ `VisionImage`, overlays or `data_changed` logic.
32
+ - `_falco_kernel` must not depend on OpenCV. OpenCV comes from
33
+ `opencv-python` for Python code.
34
+ - Models are **not** in the wheel. `core/models.py` resolves/downloads them on
35
+ first run (`%APPDATA%/FalcoCV/models`, `$XDG_DATA_HOME/FalcoCV/models`).
36
+
37
+ ## Key pitfalls (do not repeat)
38
+
39
+ - **Point-cloud Z convention** → `z = depth * z_res + z_offset` (not minus).
40
+ X is mirrored: `x = (img_width - 1 - col) * x_res` so image-left maps to
41
+ world +X and the default isometric 3D camera looks natural.
42
+ - **Point-cloud stride** → `step = ceil(sqrt(total_pixels / target_points))`;
43
+ a Python fallback lives in `core.pointcloud_utils.generate_pointcloud`.
44
+ - **PlaneFitter ROIs** → ROIs are stored in fixture coordinates and converted
45
+ to absolute image coordinates before calling the kernel. The kernel converts
46
+ image centers to world coordinates and negates the angle (Qt clockwise
47
+ convention vs world axes).
48
+ - **Plane polygon Z range** → use the depth range of the **whole image**, not
49
+ the ROI, so the overlay spans the image.
50
+ - **Overlay flow** → `inherit_overlays_from` copies layers (no shared lists).
51
+ Correct flow: inherit → claim the layer with
52
+ `get_overlay_layer("default", source_tool=self.name)` → clean elements whose
53
+ `source_tool` is this tool → add new overlays → `_copy_overlays_to_input`.
54
+ Never accumulate. Claiming is mandatory: `add_roi()/add_contour()/add_text()`
55
+ copy `layer.source_tool` into each element, and `_copy_overlays_to_input`
56
+ filters by `element.source_tool`, so an unclaimed inherited layer tags the
57
+ new overlays with the upstream tool's name and they are silently dropped.
58
+ `composite_roi_to_full(..., source_tool=...)` does the same for ROI borders.
59
+ - **Overlay rendering** → render only in visible viewers; never rasterize into
60
+ the image buffer; keep overlays as mathematical primitives.
61
+ - **ROI helpers** accept 4- or 5-element ROIs (`[x,y,w,h]` or `[x,y,w,h,a]`).
62
+ - **ROI crops with rotated fixtures** → `get_roi_data()` and
63
+ `composite_roi_to_full()` must resolve the ROI origin with
64
+ `fixture_to_image()`. An upright ROI drawn on a rotated fixture is stored as
65
+ `ra = -fixture.angle`, so `total_angle == 0` while the fixture still moves
66
+ the ROI; `x + rx` is only valid when the fixture has no rotation. The
67
+ axis-aligned path slices at `int(fixture_to_image(...)[0:2])` (no resampling)
68
+ so crop and composite round-trip losslessly.
69
+ - **Filters on depth** → scrub NaNs, preserve float32 output; Canny/CLAHE/
70
+ equalize normalize float32 to uint8 internally; invert float32 with
71
+ `(max+min)-img`.
72
+ - **Histogram on depth** → support float32/NaN with a finite min/max range;
73
+ never call `np.iinfo` on a float dtype.
74
+ - **Barcode Auto** → try the fast 1D path first (downscaled pyzbar, then
75
+ zxing), then QR/DataMatrix/ArUco only if needed. zxing MicroQR enum names
76
+ differ between versions; look them up dynamically.
77
+ - **DataMatrix** → pylibdmtx uses a bottom-left origin; flip contour Y only.
78
+ - **3D ROIs** → stored in fixture coordinates; convert with
79
+ `image_to_fixture()` before storing and `fixture_to_image()` before drawing.
80
+ - **3D ROI handles** → large, filled, drawn without depth test; add a center
81
+ handle so they remain usable in dense clouds.
82
+ - **3D draw fallback** → if point-picking and plane back-projection both fail,
83
+ show a tooltip and abort; never keep an old ROI silently.
84
+ - **`zero_as_invalid` default True** → depth `0` is invalid for point clouds;
85
+ avoid phantom floor planes. Depth images displayed in 2D are normalized to
86
+ 0 after cloud generation.
87
+ - **3D camera** → default isometric camera `azimuth=45°, elevation=30°`.
88
+
89
+ - **ShapeMatch solvers** -> the native kernel is required; there is no Python
90
+ coarse fallback. Alignment >=0.90 uses the ECC solver; lower alignment uses the
91
+ explicit occlusion solver. ECC failure in the 0.90-0.98 band reclassifies to
92
+ occlusion; >=0.98 is rejected with a warning. Results carry `solver`,
93
+ `ncc_score`, `visible_fraction`, `ecc_cc` and `warnings`.
94
+ - **ShapeMatch model** -> `model_b64` stores features, edges, gray and color
95
+ templates. Training ROI is fixture-relative and supports rotation. Do not add
96
+ PatternMatcher-only parameters (`angle_step`, `scale_step`, `use_pyramid`, ...).
97
+ - **ShapeMatch coarse voting** -> vote on a downscaled image (4x for >=2 MP,
98
+ 2x for >=0.25 MP, 1x for small ROIs), keep the template >=40 px, cap scene
99
+ edges spatially (at least 4000, 8 per 32 px cell) and use the top 500 model
100
+ features.
101
+ Refine at full resolution; full gradients, Canny and the distance map stay
102
+ lazy and are only computed for the occlusion solver.
103
+ - **ShapeMatch search stage** -> NCC angle/scale scans run on a reduced ROI
104
+ (template >=48 px, max 4x) and reject candidates whose NCC is below
105
+ `_MIN_NCC` before any full-resolution alignment or solver. This is what keeps
106
+ the pipeline at ~4 coarse poses instead of paying for every kernel candidate.
107
+ - **ShapeMatch ECC** -> two levels: affine ECC on a reduced view (factor <=2)
108
+ then a translation-only pass at full resolution. The reduced pass must undo
109
+ its resampling with `template_scale`/`scene_scale`; without that correction
110
+ the reported scale drifts by up to 0.65 %. Small templates (factor 1) keep
111
+ the full-resolution affine + polish path.
112
+ - **ShapeMatch padding** -> the rotated template's padding diagonal must be even,
113
+ otherwise its center lands between pixels and translation is biased by ~0.5 px.
114
+ Render NCC padding with the template's median border color, never zero.
115
+ Crop the padding before `matchTemplate` (`_render_search`); a rotated rectangle
116
+ is centrally symmetric so the crop stays centred.
117
+
118
+ ## Build
119
+
120
+ ### Native kernel (only C++ build)
121
+ ```bash
122
+ build_kernel.bat # Windows: configure + build + deploy cpp/bin
123
+ build_kernel.bat --rebuild
124
+ ./build_kernel.sh # Linux/macOS
125
+ ```
126
+ No OpenCV world build. Requirements: CMake 3.20+, C++17 compiler, pybind11,
127
+ OpenMP.
128
+
129
+ ### Python package
130
+ ```bash
131
+ pip install -e ".[dev]" # builds the kernel via scikit-build-core
132
+ pytest -q --ignore=tests/test_trainer_equivalence.py
133
+ ```
134
+
135
+ ## Key facts
136
+ - Python 3.13.x (only supported version), branch: `main` / working branch
137
+ `public_refactor`.
138
+ - No PyInstaller/Inno distribution build; distribution is the PyPI wheel/sdist.
139
+ - `config.json` lives in `%APPDATA%/FalcoCV/config.json` (or XDG config).
140
+ - Models live in the user data dir and are downloaded from GitHub Releases.
141
+ - `core/` has no PyQt6/UI imports at module level.
142
+ - License: **GNU GPL v3 or later** (see `LICENSE`).
143
+ - Branding: `src/falcocv/ui/assets/` (`icon.ico`, `icon_light.ico`, `logo.svg`,
144
+ lockups). The splash uses `logo_lockup_dark.png`; the web dashboard serves
145
+ `/hmi/logo_lockup_dark.png`.
146
+ - Do not make commits without explicit permission.
147
+ - Server: `falcocv-server` or `python -m falcocv.web`; dashboard:
148
+ `http://localhost:8000`; HMI: `http://localhost:8000/?id=<project_id>`.
149
+ - Performance harness: `benchmarks/` (`python benchmarks/bench_tools.py`).