demeter
Autonomous Hydroponic Intelligencegit clone https://github.com/maydayv7/demeter
agent/Sentinel/Encoders/Vision.py (3336B)
1# encoders/clip_encoder.py
2import torch
3import clip
4from PIL import Image
5import io
6import base64
7from pathlib import Path
8
9class VisionEncoder:
10 def __init__(self, model_name="ViT-B/32"):
11 self.device = "cuda" if torch.cuda.is_available() else "cpu"
12 self.model, self.preprocess = clip.load(model_name, device=self.device)
13 self.model.eval()
14
15 def encode(self, image_input):
16 """
17 Encode an image from multiple input types:
18 - File path (str or Path)
19 - Base64 string
20 - BytesIO object
21 - PIL Image object
22
23 Args:
24 image_input: File path, base64 string, BytesIO, or PIL Image
25
26 Returns:
27 numpy array: Normalized image embedding vector
28 """
29 # Convert input to PIL Image
30 pil_image = self._to_pil_image(image_input)
31
32 # Preprocess and encode
33 image = self.preprocess(pil_image.convert("RGB")) \
34 .unsqueeze(0).to(self.device)
35
36 with torch.no_grad():
37 vec = self.model.encode_image(image)
38 vec = vec / vec.norm(dim=-1, keepdim=True)
39
40 return vec.cpu().numpy().flatten()
41
42 def _to_pil_image(self, image_input):
43 """
44 Convert various input types to PIL Image.
45 """
46 # If already a PIL Image
47 if isinstance(image_input, Image.Image):
48 return image_input
49
50 # If BytesIO object
51 if isinstance(image_input, io.BytesIO):
52 image_input.seek(0) # Reset to beginning
53 return Image.open(image_input)
54
55 # If it's a string, determine if it's a path or base64
56 if isinstance(image_input, (str, Path)):
57 # Check if it's a file path
58 if isinstance(image_input, Path) or Path(image_input).exists():
59 return Image.open(image_input)
60
61 # Otherwise, treat as base64
62 return self._base64_to_pil(image_input)
63
64 # If bytes object
65 if isinstance(image_input, bytes):
66 return Image.open(io.BytesIO(image_input))
67
68 raise TypeError(f"Unsupported image input type: {type(image_input)}")
69
70 def _base64_to_pil(self, base64_string):
71 """
72 Convert base64 string to PIL Image.
73 """
74 # Remove header if present (e.g., "data:image/png;base64,...")
75 if "," in base64_string:
76 base64_string = base64_string.split(",")[1]
77
78 # Add padding if necessary
79 missing_padding = len(base64_string) % 4
80 if missing_padding:
81 base64_string += '=' * (4 - missing_padding)
82
83 # Decode and open
84 image_bytes = base64.b64decode(base64_string)
85 return Image.open(io.BytesIO(image_bytes))
86
87
88# Example usage:
89if __name__ == "__main__":
90 encoder = VisionEncoder()
91
92 # Test with file path
93 # vec1 = encoder.encode("path/to/image.jpg")
94
95 # Test with base64
96 sample_base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+ip1sAAAAASUVORK5CYII="
97 vec2 = encoder.encode(sample_base64)
98 print(f"✅ Encoded base64 image. Vector shape: {vec2.shape}")
99
100 # Test with BytesIO
101 # image_stream = io.BytesIO(image_bytes)
102 # vec3 = encoder.encode(image_stream)