imagebaker 0.0.2__tar.gz → 0.0.3__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 (49) hide show
  1. {imagebaker-0.0.2 → imagebaker-0.0.3}/PKG-INFO +1 -1
  2. imagebaker-0.0.3/imagebaker/utils/__init__.py +0 -0
  3. imagebaker-0.0.3/imagebaker/utils/image.py +95 -0
  4. imagebaker-0.0.3/imagebaker/utils/state_utils.py +64 -0
  5. imagebaker-0.0.3/imagebaker/utils/transform_mask.py +112 -0
  6. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker.egg-info/PKG-INFO +1 -1
  7. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker.egg-info/SOURCES.txt +4 -0
  8. {imagebaker-0.0.2 → imagebaker-0.0.3}/setup.py +1 -1
  9. {imagebaker-0.0.2 → imagebaker-0.0.3}/LICENSE +0 -0
  10. {imagebaker-0.0.2 → imagebaker-0.0.3}/README.md +0 -0
  11. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/__init__.py +0 -0
  12. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/core/__init__.py +0 -0
  13. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/core/configs/__init__.py +0 -0
  14. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/core/configs/configs.py +0 -0
  15. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/core/defs/__init__.py +0 -0
  16. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/core/defs/defs.py +0 -0
  17. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/core/plugins/__init__.py +0 -0
  18. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/core/plugins/base_plugin.py +0 -0
  19. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/core/plugins/cosine_plugin.py +0 -0
  20. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/layers/__init__.py +0 -0
  21. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/layers/annotable_layer.py +0 -0
  22. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/layers/base_layer.py +0 -0
  23. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/layers/canvas_layer.py +0 -0
  24. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/list_views/__init__.py +0 -0
  25. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/list_views/annotation_list.py +0 -0
  26. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/list_views/canvas_list.py +0 -0
  27. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/list_views/image_list.py +0 -0
  28. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/list_views/layer_list.py +0 -0
  29. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/list_views/layer_settings.py +0 -0
  30. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/models/__init__.py +0 -0
  31. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/models/base_model.py +0 -0
  32. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/models/rtdetr_v2.py +0 -0
  33. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/models/sam_model.py +0 -0
  34. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/models/segmentation.py +0 -0
  35. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/tabs/__init__.py +0 -0
  36. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/tabs/baker_tab.py +0 -0
  37. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/tabs/layerify_tab.py +0 -0
  38. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/window/__init__.py +0 -0
  39. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/window/app.py +0 -0
  40. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/window/main_window.py +0 -0
  41. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/workers/__init__.py +0 -0
  42. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/workers/baker_worker.py +0 -0
  43. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/workers/layerfy_worker.py +0 -0
  44. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker/workers/model_worker.py +0 -0
  45. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker.egg-info/dependency_links.txt +0 -0
  46. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker.egg-info/entry_points.txt +0 -0
  47. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker.egg-info/requires.txt +0 -0
  48. {imagebaker-0.0.2 → imagebaker-0.0.3}/imagebaker.egg-info/top_level.txt +0 -0
  49. {imagebaker-0.0.2 → imagebaker-0.0.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: imagebaker
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: A package for baking images.
5
5
  Home-page: https://github.com/q-viper/Image-Baker
6
6
  Author: Ramkrishna Acharya
File without changes
@@ -0,0 +1,95 @@
1
+ import numpy as np
2
+ from PySide6.QtGui import QPixmap, QImage
3
+ import cv2
4
+
5
+ from imagebaker.core.defs.defs import Annotation
6
+
7
+
8
+ def qpixmap_to_numpy(pixmap: QPixmap | QImage) -> np.ndarray:
9
+ """
10
+ Convert QPixmap to RGBA numpy array.
11
+
12
+ Args:
13
+ pixmap: The QPixmap to convert
14
+
15
+ Returns:
16
+ numpy.ndarray: Array with shape (height, width, 4) containing RGBA values
17
+ """
18
+
19
+ if isinstance(pixmap, QPixmap):
20
+ # Convert QPixmap to QImage first
21
+ image = pixmap.toImage()
22
+ else:
23
+ image = pixmap
24
+ # Convert to Format_RGBA8888 for consistent channel ordering
25
+ if image.format() != QImage.Format_RGBA8888:
26
+ image = image.convertToFormat(QImage.Format_RGBA8888)
27
+
28
+ width = image.width()
29
+ height = image.height()
30
+
31
+ # Get the bytes directly from the QImage
32
+ ptr = image.constBits()
33
+
34
+ # Convert memoryview to bytes and then to numpy array
35
+ bytes_data = bytes(ptr)
36
+ arr = np.frombuffer(bytes_data, dtype=np.uint8).reshape((height, width, 4))
37
+
38
+ return arr
39
+
40
+
41
+ def draw_annotations(image: np.ndarray, annotations: list[Annotation]):
42
+ for i, ann in enumerate(annotations):
43
+ if ann.rectangle:
44
+ cv2.rectangle(
45
+ image,
46
+ (int(ann.rectangle.x()), int(ann.rectangle.y())),
47
+ (
48
+ int(ann.rectangle.x() + ann.rectangle.width()),
49
+ int(ann.rectangle.y() + ann.rectangle.height()),
50
+ ),
51
+ (0, 255, 0),
52
+ 2,
53
+ )
54
+ rect_center = ann.rectangle.center()
55
+
56
+ cv2.putText(
57
+ image,
58
+ ann.label,
59
+ (int(rect_center.x()), int(rect_center.y())),
60
+ cv2.FONT_HERSHEY_SIMPLEX,
61
+ 1,
62
+ (0, 255, 0),
63
+ 2,
64
+ )
65
+ elif ann.polygon:
66
+ cv2.polylines(
67
+ image,
68
+ [np.array([[int(p.x()), int(p.y())] for p in ann.polygon])],
69
+ True,
70
+ (0, 255, 0),
71
+ 2,
72
+ )
73
+ polygon_center = ann.polygon.boundingRect().center()
74
+ cv2.putText(
75
+ image,
76
+ ann.label,
77
+ (int(polygon_center.x()), int(polygon_center.y())),
78
+ cv2.FONT_HERSHEY_SIMPLEX,
79
+ 1,
80
+ (0, 255, 0),
81
+ 2,
82
+ )
83
+ elif ann.points:
84
+ for p in ann.points:
85
+ cv2.circle(image, (int(p.x()), int(p.y())), 5, (0, 255, 0), -1)
86
+ cv2.putText(
87
+ image,
88
+ ann.label,
89
+ (int(ann.points[0].x()), int(ann.points[0].y())),
90
+ cv2.FONT_HERSHEY_SIMPLEX,
91
+ 1,
92
+ (0, 255, 0),
93
+ 2,
94
+ )
95
+ return image
@@ -0,0 +1,64 @@
1
+ from imagebaker.core.defs import LayerState
2
+ from PySide6.QtCore import QPointF
3
+
4
+
5
+ def calculate_intermediate_states(previous_state, current_state, steps: int):
6
+ """
7
+ Calculate intermediate states between previous_state and current_state for a layer.
8
+ Append the current_state to the list of states after calculating intermediates.
9
+ """
10
+ if not previous_state or not current_state:
11
+ return [current_state] # If no previous state, return only the current state
12
+
13
+ intermediate_states = []
14
+ for i in range(steps):
15
+ # Interpolate attributes between previous_state and current_state
16
+ interpolated_state = LayerState(
17
+ layer_id=current_state.layer_id,
18
+ layer_name=current_state.layer_name,
19
+ opacity=previous_state.opacity
20
+ + (current_state.opacity - previous_state.opacity) * (i / steps),
21
+ position=QPointF(
22
+ previous_state.position.x()
23
+ + (current_state.position.x() - previous_state.position.x())
24
+ * (i / steps),
25
+ previous_state.position.y()
26
+ + (current_state.position.y() - previous_state.position.y())
27
+ * (i / steps),
28
+ ),
29
+ rotation=previous_state.rotation
30
+ + (current_state.rotation - previous_state.rotation) * (i / steps),
31
+ scale=previous_state.scale
32
+ + (current_state.scale - previous_state.scale) * (i / steps),
33
+ scale_x=previous_state.scale_x
34
+ + (current_state.scale_x - previous_state.scale_x) * (i / steps),
35
+ scale_y=previous_state.scale_y
36
+ + (current_state.scale_y - previous_state.scale_y) * (i / steps),
37
+ transform_origin=QPointF(
38
+ previous_state.transform_origin.x()
39
+ + (
40
+ current_state.transform_origin.x()
41
+ - previous_state.transform_origin.x()
42
+ )
43
+ * (i / steps),
44
+ previous_state.transform_origin.y()
45
+ + (
46
+ current_state.transform_origin.y()
47
+ - previous_state.transform_origin.y()
48
+ )
49
+ * (i / steps),
50
+ ),
51
+ order=current_state.order,
52
+ visible=current_state.visible,
53
+ allow_annotation_export=current_state.allow_annotation_export,
54
+ playing=current_state.playing,
55
+ selected=current_state.selected,
56
+ is_annotable=current_state.is_annotable,
57
+ status=current_state.status,
58
+ )
59
+ intermediate_states.append(interpolated_state)
60
+
61
+ # Append the current state as the final state
62
+ intermediate_states.append(current_state)
63
+
64
+ return intermediate_states
@@ -0,0 +1,112 @@
1
+ import cv2
2
+ import numpy as np
3
+ from typing import List, Tuple
4
+
5
+
6
+ def mask_to_polygons(
7
+ mask: np.ndarray,
8
+ min_polygon_area: float = 10,
9
+ merge_polygons: bool = False,
10
+ merge_distance: int = 5, # Max distance between polygons to merge
11
+ ) -> List[List[Tuple[int, int]]]:
12
+ """
13
+ Convert a binary mask to a list of polygons.
14
+ Each polygon is a list of (x, y) coordinates.
15
+
16
+ Args:
17
+ mask (np.ndarray): Binary mask (0 or 255).
18
+ min_polygon_area (float): Minimum area for a polygon to be included.
19
+ merge_polygons (bool): If True, merges nearby/overlapping polygons.
20
+ merge_distance (int): Max distance between polygons to merge (if merge_polygons=True).
21
+
22
+ Returns:
23
+ List[List[Tuple[int, int]]]: List of polygons, each represented as a list of (x, y) points.
24
+ """
25
+ contours, _ = cv2.findContours(
26
+ mask.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
27
+ )
28
+
29
+ polygons = []
30
+ for contour in contours:
31
+ area = cv2.contourArea(contour)
32
+ if area >= min_polygon_area:
33
+ polygons.append(contour)
34
+
35
+ # Sort polygons by area (descending)
36
+ polygons = sorted(
37
+ polygons, key=lambda p: cv2.contourArea(np.array(p)), reverse=True
38
+ )
39
+
40
+ # Merge polygons if requested
41
+ if merge_polygons and len(polygons) > 1:
42
+ # Use morphological dilation to merge nearby regions
43
+ kernel = np.ones((merge_distance, merge_distance), np.uint8)
44
+ merged_mask = cv2.dilate(mask, kernel, iterations=1)
45
+
46
+ # Re-extract contours after merging
47
+ merged_contours, _ = cv2.findContours(
48
+ merged_mask.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
49
+ )
50
+
51
+ # Filter again by area
52
+ merged_polygons = []
53
+ for contour in merged_contours:
54
+ area = cv2.contourArea(contour)
55
+ if area >= min_polygon_area:
56
+ merged_polygons.append(contour)
57
+
58
+ polygons = merged_polygons
59
+
60
+ # Convert contours to list of points
61
+ result = []
62
+ for poly in polygons:
63
+ points = poly.squeeze().tolist() # Remove extra dimensions
64
+ if len(points) >= 3: # Ensure it's a valid polygon
65
+ result.append([(int(x), int(y)) for x, y in points])
66
+
67
+ return result
68
+
69
+
70
+ import cv2
71
+ import numpy as np
72
+ from typing import List, Tuple
73
+
74
+
75
+ def mask_to_rectangles(
76
+ mask: np.ndarray,
77
+ merge_rectangles: bool = False,
78
+ merge_threshold: int = 1,
79
+ merge_epsilon: float = 0.5,
80
+ ) -> List[Tuple[int, int, int, int]]:
81
+ """
82
+ Convert a binary mask to a list of rectangles.
83
+ Each rectangle is a tuple of (x, y, w, h).
84
+
85
+ Args:
86
+ mask (np.ndarray): Binary mask (0 or 255).
87
+ merge_rectangles (bool): If True, merges overlapping or nearby rectangles.
88
+ merge_threshold (int): Min number of rectangles to merge into one.
89
+ merge_epsilon (float): Controls how close rectangles must be to merge (0.0 to 1.0).
90
+
91
+ Returns:
92
+ List[Tuple[int, int, int, int]]: List of rectangles, each as (x, y, w, h).
93
+ """
94
+ contours, _ = cv2.findContours(
95
+ mask.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
96
+ )
97
+
98
+ rectangles = []
99
+ for contour in contours:
100
+ x, y, w, h = cv2.boundingRect(contour)
101
+ rectangles.append((x, y, w, h))
102
+
103
+ if merge_rectangles and len(rectangles) > 1:
104
+ # Convert rectangles to the format expected by groupRectangles
105
+ rects = np.array(rectangles)
106
+ # groupRectangles requires [x, y, w, h] format
107
+ grouped_rects, _ = cv2.groupRectangles(
108
+ rects.tolist(), merge_threshold, merge_epsilon
109
+ )
110
+ rectangles = [tuple(map(int, rect)) for rect in grouped_rects]
111
+
112
+ return rectangles
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: imagebaker
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: A package for baking images.
5
5
  Home-page: https://github.com/q-viper/Image-Baker
6
6
  Author: Ramkrishna Acharya
@@ -34,6 +34,10 @@ imagebaker/models/segmentation.py
34
34
  imagebaker/tabs/__init__.py
35
35
  imagebaker/tabs/baker_tab.py
36
36
  imagebaker/tabs/layerify_tab.py
37
+ imagebaker/utils/__init__.py
38
+ imagebaker/utils/image.py
39
+ imagebaker/utils/state_utils.py
40
+ imagebaker/utils/transform_mask.py
37
41
  imagebaker/window/__init__.py
38
42
  imagebaker/window/app.py
39
43
  imagebaker/window/main_window.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="imagebaker",
5
- version="0.0.2",
5
+ version="0.0.3",
6
6
  packages=find_packages(), # Automatically finds all packages
7
7
  install_requires=[
8
8
  "numpy",
File without changes
File without changes
File without changes