teody-vision 0.1.0__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.
File without changes
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.4
2
+ Name: teody-vision
3
+ Version: 0.1.0
4
+ Summary: A deterministic, non-neural topological tensor framework for real-time UI text and field localization.
5
+ Author-email: Teody Arboneda Banagan <teody882011@gmail.com>
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
10
+ Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: numpy>=1.21.0
14
+ Requires-Dist: opencv-python>=4.5.0
15
+ Requires-Dist: mss>=9.0.0
16
+ Dynamic: license-file
File without changes
@@ -0,0 +1,25 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "teody-vision"
7
+ version = "0.1.0"
8
+ description = "A deterministic, non-neural topological tensor framework for real-time UI text and field localization."
9
+ authors = [
10
+ { name="Teody Arboneda Banagan", email="teody882011@gmail.com" }
11
+ ]
12
+
13
+ readme = "README.md"
14
+ requires-python = ">=3.9"
15
+ dependencies = [
16
+ "numpy>=1.21.0",
17
+ "opencv-python>=4.5.0",
18
+ "mss>=9.0.0"
19
+ ]
20
+ classifiers = [
21
+ "Programming Language :: Python :: 3",
22
+ "License :: OSI Approved :: MIT License",
23
+ "Operating System :: OS Independent",
24
+ "Topic :: Scientific/Engineering :: Image Processing",
25
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,11 @@
1
+ """
2
+ TEODY-Vision Package Initialization
3
+ """
4
+
5
+ from .core import TEODYEngine
6
+ from .tensor import TEODYTensorEngine
7
+ from .topology import TEODYTopologyEngine
8
+ from .matcher import TEODYMatcher
9
+
10
+ __version__ = "0.1.0"
11
+ __all__ = ["TEODYEngine", "TEODYTensorEngine", "TEODYTopologyEngine", "TEODYMatcher"]
@@ -0,0 +1,27 @@
1
+ import cv2
2
+ import numpy as np
3
+ from mss import mss
4
+ from .tensor import TEODYTensorEngine
5
+ from .topology import TEODYTopologyEngine
6
+
7
+ class TEODYEngine:
8
+ def __init__(self, monitor_index: int = 1, block_size: int = 3, k: float = 0.04):
9
+ self.monitor_index = monitor_index
10
+ self.sct = mss()
11
+ # Initialize tensor engine with block_size and k matching its definition
12
+ self.tensor_engine = TEODYTensorEngine(block_size=block_size, k=k)
13
+ self.topology_engine = TEODYTopologyEngine()
14
+
15
+ def capture_frame(self) -> np.ndarray:
16
+ """Captures a high-speed screen frame using mss."""
17
+ monitor = self.sct.monitors[self.monitor_index]
18
+ sct_img = self.sct.grab(monitor)
19
+ frame = np.array(sct_img)
20
+ # Convert BGRA to BGR
21
+ return cv2.cvtColor(frame, cv2.COLOR_BGRA2BGR) if frame.shape[2] == 4 else frame
22
+
23
+ def process_frame(self, frame: np.ndarray) -> tuple[np.ndarray, list[tuple[int, int, int, int]]]:
24
+ """Runs the tensor coherence and topological region extraction pipeline."""
25
+ coherence = self.tensor_engine.compute_coherence(frame)
26
+ regions = self.topology_engine.extract_regions(coherence)
27
+ return coherence, regions
@@ -0,0 +1,60 @@
1
+ import cv2
2
+ import numpy as np
3
+
4
+ class TEODYMatcher:
5
+ @staticmethod
6
+ def match_template_in_regions(frame: np.ndarray,
7
+ template: np.ndarray,
8
+ regions: list[tuple[int, int, int, int]],
9
+ threshold: float = 0.48) -> list[tuple[int, int, int, int]]:
10
+ """
11
+ Performs Multi-Scale Gradient Magnitude Template Matching.
12
+ Resilient to browser anti-aliasing, font smoothing, and variable font sizes.
13
+ """
14
+ if template is None or len(regions) == 0:
15
+ return []
16
+
17
+ gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) if len(frame.shape) == 3 else frame
18
+ gray_template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY) if len(template.shape) == 3 else template
19
+
20
+ def get_gradient_magnitude(img):
21
+ grad_x = cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=3)
22
+ grad_y = cv2.Sobel(img, cv2.CV_32F, 0, 1, ksize=3)
23
+ magnitude = cv2.magnitude(grad_x, grad_y)
24
+ return cv2.normalize(magnitude, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)
25
+
26
+ template_grad_base = get_gradient_magnitude(gray_template)
27
+
28
+ # Scale pyramid range supporting small sidebar fonts (0.6x) up to large headers (1.8x)
29
+ scales = [0.6, 0.8, 1.0, 1.2, 1.5, 1.8]
30
+ matched_boxes = []
31
+
32
+ for (x, y, w, h) in regions:
33
+ roi = gray_frame[y:y+h, x:x+w]
34
+ if roi.size == 0:
35
+ continue
36
+
37
+ roi_grad = get_gradient_magnitude(roi)
38
+ best_match_val = -1
39
+ best_box = None
40
+
41
+ for scale in scales:
42
+ scaled_w = int(template_grad_base.shape[1] * scale)
43
+ scaled_h = int(template_grad_base.shape[0] * scale)
44
+
45
+ if scaled_w <= 0 or scaled_h <= 0 or scaled_w > roi_grad.shape[1] or scaled_h > roi_grad.shape[0]:
46
+ continue
47
+
48
+ scaled_template = cv2.resize(template_grad_base, (scaled_w, scaled_h), interpolation=cv2.INTER_AREA)
49
+
50
+ result = cv2.matchTemplate(roi_grad, scaled_template, cv2.TM_CCOEFF_NORMED)
51
+ _, max_val, _, max_loc = cv2.minMaxLoc(result)
52
+
53
+ if max_val > best_match_val:
54
+ best_match_val = max_val
55
+ best_box = (x + max_loc[0], y + max_loc[1], scaled_w, scaled_h)
56
+
57
+ if best_match_val >= threshold and best_box is not None:
58
+ matched_boxes.append(best_box)
59
+
60
+ return matched_boxes
@@ -0,0 +1,51 @@
1
+ import cv2
2
+ import numpy as np
3
+
4
+ class TEODYTensorEngine:
5
+ def __init__(self, block_size: int = 3, k: float = 0.04):
6
+ self.block_size = block_size
7
+ self.k = k
8
+
9
+ def compute_structure_tensor(self, frame: np.ndarray) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
10
+ """Calculates spatial image derivatives and structure tensor components."""
11
+ gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) if len(frame.shape) == 3 else frame
12
+
13
+ # Spatial gradients using Sobel operators
14
+ Ix = cv2.Sobel(gray, cv2.CV_32F, 1, 0, ksize=3)
15
+ Iy = cv2.Sobel(gray, cv2.CV_32F, 0, 1, ksize=3)
16
+
17
+ # Structure tensor elements
18
+ Ixx = Ix * Ix
19
+ Iyy = Iy * Iy
20
+ Ixy = Ix * Iy
21
+
22
+ # Smooth components over the local neighborhood
23
+ ksize = (self.block_size, self.block_size)
24
+ Sxx = cv2.GaussianBlur(Ixx, ksize, 0)
25
+ Syy = cv2.GaussianBlur(Iyy, ksize, 0)
26
+ Sxy = cv2.GaussianBlur(Ixy, ksize, 0)
27
+
28
+ return Sxx, Syy, Sxy
29
+
30
+ def compute_coherence(self, frame: np.ndarray) -> np.ndarray:
31
+ """Computes anisotropic coherence map from structure tensor eigenvalues."""
32
+ Sxx, Syy, Sxy = self.compute_structure_tensor(frame)
33
+
34
+ # Trace and determinant
35
+ trace = Sxx + Syy
36
+ det = (Sxx * Syy) - (Sxy ** 2)
37
+
38
+ # Difference squared term for eigenvalues
39
+ diff = Sxx - Syy
40
+ lambda_diff_sq = (diff ** 2) + (4 * (Sxy ** 2))
41
+ lambda_diff = np.sqrt(np.maximum(lambda_diff_sq, 0))
42
+
43
+ # Eigenvalues
44
+ lambda1 = 0.5 * (trace + lambda_diff)
45
+ lambda2 = 0.5 * (trace - lambda_diff)
46
+
47
+ # Anisotropic coherence metric (normalized difference)
48
+ denom = lambda1 + lambda2 + 1e-6
49
+ coherence = (lambda1 - lambda2) / denom
50
+
51
+ return np.clip(coherence * 255, 0, 255).astype(np.uint8)
@@ -0,0 +1,27 @@
1
+ import cv2
2
+ import numpy as np
3
+
4
+ class TEODYTopologyEngine:
5
+ def __init__(self, min_width: int = 10, min_height: int = 6):
6
+ self.min_width = min_width
7
+ self.min_height = min_height
8
+
9
+ def extract_regions(self, coherence_map: np.ndarray) -> list[tuple[int, int, int, int]]:
10
+ """Isolates UI text and layout boundaries via morphological operations and contour analysis."""
11
+ # Binarize coherence map
12
+ _, thresh = cv2.threshold(coherence_map, 40, 255, cv2.THRESH_BINARY)
13
+
14
+ # Morphological closing to connect nearby character strokes and text components
15
+ kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15, 3))
16
+ closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
17
+
18
+ # Find external contours
19
+ contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
20
+
21
+ regions = []
22
+ for cnt in contours:
23
+ x, y, w, h = cv2.boundingRect(cnt)
24
+ if w >= self.min_width and h >= self.min_height:
25
+ regions.append((x, y, w, h))
26
+
27
+ return regions
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.4
2
+ Name: teody-vision
3
+ Version: 0.1.0
4
+ Summary: A deterministic, non-neural topological tensor framework for real-time UI text and field localization.
5
+ Author-email: Teody Arboneda Banagan <teody882011@gmail.com>
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
10
+ Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: numpy>=1.21.0
14
+ Requires-Dist: opencv-python>=4.5.0
15
+ Requires-Dist: mss>=9.0.0
16
+ Dynamic: license-file
@@ -0,0 +1,14 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ teody_vision/__init__.py
5
+ teody_vision/core.py
6
+ teody_vision/matcher.py
7
+ teody_vision/tensor.py
8
+ teody_vision/topology.py
9
+ teody_vision.egg-info/PKG-INFO
10
+ teody_vision.egg-info/SOURCES.txt
11
+ teody_vision.egg-info/dependency_links.txt
12
+ teody_vision.egg-info/requires.txt
13
+ teody_vision.egg-info/top_level.txt
14
+ tests/test_engine.py
@@ -0,0 +1,3 @@
1
+ numpy>=1.21.0
2
+ opencv-python>=4.5.0
3
+ mss>=9.0.0
@@ -0,0 +1 @@
1
+ teody_vision
@@ -0,0 +1,80 @@
1
+ """
2
+ TEODY-Vision: Automated Unit Test Suite
3
+ File: tests/test_engine.py
4
+ """
5
+
6
+ import unittest
7
+ import numpy as np
8
+ import cv2
9
+ from teody_vision import TEODYTensorEngine, TEODYTopologyEngine, TEODYMatcher
10
+
11
+ class TestTEODYVisionEngine(unittest.TestCase):
12
+ """Test cases for core TEODY-Vision non-neural computer vision components."""
13
+
14
+ def setUp(self):
15
+ """Set up synthetic test images simulating UI screens with text and borders."""
16
+ self.tensor_engine = TEODYTensorEngine(sigma=1.0, rho=2.0)
17
+ self.topology_engine = TEODYTopologyEngine(min_width=10, min_height=5)
18
+
19
+ # Create a blank 300x300 grayscale synthetic UI screen canvas
20
+ self.synthetic_screen = np.full((300, 300), 255, dtype=np.uint8)
21
+
22
+ # Draw a simulated UI box (representing a button or input field)
23
+ cv2.rectangle(self.synthetic_screen, (50, 50), (180, 90), 0, 2)
24
+
25
+ # Draw simulated text/label inside the box
26
+ cv2.putText(self.synthetic_screen, "Login", (60, 78), cv2.FONT_HERSHEY_SIMPLEX, 0.7, 0, 2, cv2.LINE_AA)
27
+
28
+ def test_tensor_anisotropy_computation(self):
29
+ """Test that the structure tensor computes anisotropic coherence maps successfully."""
30
+ coherence_map = self.tensor_engine.compute_anisotropic_coherence(self.synthetic_screen)
31
+
32
+ # Verify output dimensions match input frame
33
+ self.assertEqual(coherence_map.shape, self.synthetic_screen.shape)
34
+ # Verify output is an 8-bit unsigned integer array
35
+ self.assertEqual(coherence_map.dtype, np.uint8)
36
+ # Verify that tensor values detect high-contrast edges (max coherence > 0)
37
+ self.assertGreater(np.max(coherence_map), 0)
38
+
39
+ def test_topology_boundary_extraction(self):
40
+ """Test that topological morphology isolates UI text and field bounding boxes."""
41
+ coherence_map = self.tensor_engine.compute_anisotropic_coherence(self.synthetic_screen)
42
+ regions = self.topology_engine.extract_field_boundaries(coherence_map)
43
+
44
+ # Verify that regions are returned as a list
45
+ self.assertIsInstance(regions, list)
46
+ # Verify that at least one valid bounding box was detected around our simulated UI elements
47
+ self.assertGreater(len(regions), 0, "Failed to isolate any structural UI regions.")
48
+
49
+ # Check that bounding box tuples have 4 elements (x, y, w, h)
50
+ for box in regions:
51
+ self.assertEqual(len(box), 4)
52
+ x, y, w, h = box
53
+ self.assertGreater(w, 0)
54
+ self.assertGreater(h, 0)
55
+
56
+ def test_deterministic_matcher(self):
57
+ """Test that template matching successfully locates a target word within extracted regions."""
58
+ # Generate a synthetic template for the word "Login"
59
+ font = cv2.FONT_HERSHEY_SIMPLEX
60
+ (tw, th), _ = cv2.getTextSize("Login", font, 0.7, 2)
61
+ template = np.full((th + 10, tw + 10), 255, dtype=np.uint8)
62
+ cv2.putText(template, "Login", (5, th + 5), font, 0.7, 0, 2, cv2.LINE_AA)
63
+
64
+ # Extract regions from synthetic screen
65
+ coherence_map = self.tensor_engine.compute_anisotropic_coherence(self.synthetic_screen)
66
+ regions = self.topology_engine.extract_field_boundaries(coherence_map)
67
+
68
+ # Run matcher
69
+ matches = TEODYMatcher.match_template_in_regions(self.synthetic_screen, template, regions, threshold=0.75)
70
+
71
+ # Verify matching behavior
72
+ self.assertIsInstance(matches, list)
73
+ if len(matches) > 0:
74
+ mx, my, mw, mh = matches[0]
75
+ self.assertGreaterEqual(mw, tw)
76
+ self.assertGreaterEqual(mh, th)
77
+
78
+
79
+ if __name__ == "__main__":
80
+ unittest.main()