mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 02:39:03 -04:00 
			
		
		
		
	* modularize model classes * various fixes * expose port * change response * round coordinates * simplify preload * update server * simplify interface simplify * update tests * composable endpoint * cleanup fixes remove unnecessary interface support text input, cleanup * ew camelcase * update server server fixes fix typing * ml fixes update locustfile fixes * cleaner response * better repo response * update tests formatting and typing rename * undo compose change * linting fix type actually fix typing * stricter typing fix detection-only response no need for defaultdict * update spec file update api linting * update e2e * unnecessary dimension * remove commented code * remove duplicate code * remove unused imports * add batch dim
		
			
				
	
	
		
			63 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			63 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from io import BytesIO
 | |
| from typing import IO
 | |
| 
 | |
| import cv2
 | |
| import numpy as np
 | |
| from numpy.typing import NDArray
 | |
| from PIL import Image
 | |
| 
 | |
| _PIL_RESAMPLING_METHODS = {resampling.name.lower(): resampling for resampling in Image.Resampling}
 | |
| 
 | |
| 
 | |
| def resize_pil(img: Image.Image, size: int) -> Image.Image:
 | |
|     if img.width < img.height:
 | |
|         return img.resize((size, int((img.height / img.width) * size)), resample=Image.Resampling.BICUBIC)
 | |
|     else:
 | |
|         return img.resize((int((img.width / img.height) * size), size), resample=Image.Resampling.BICUBIC)
 | |
| 
 | |
| 
 | |
| # https://stackoverflow.com/a/60883103
 | |
| def crop_pil(img: Image.Image, size: int) -> Image.Image:
 | |
|     left = int((img.size[0] / 2) - (size / 2))
 | |
|     upper = int((img.size[1] / 2) - (size / 2))
 | |
|     right = left + size
 | |
|     lower = upper + size
 | |
| 
 | |
|     return img.crop((left, upper, right, lower))
 | |
| 
 | |
| 
 | |
| def to_numpy(img: Image.Image) -> NDArray[np.float32]:
 | |
|     return np.asarray(img if img.mode == "RGB" else img.convert("RGB"), dtype=np.float32) / 255.0
 | |
| 
 | |
| 
 | |
| def normalize(
 | |
|     img: NDArray[np.float32], mean: float | NDArray[np.float32], std: float | NDArray[np.float32]
 | |
| ) -> NDArray[np.float32]:
 | |
|     return np.divide(img - mean, std, dtype=np.float32)
 | |
| 
 | |
| 
 | |
| def get_pil_resampling(resample: str) -> Image.Resampling:
 | |
|     return _PIL_RESAMPLING_METHODS[resample.lower()]
 | |
| 
 | |
| 
 | |
| def pil_to_cv2(image: Image.Image) -> NDArray[np.uint8]:
 | |
|     return cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)  # type: ignore
 | |
| 
 | |
| 
 | |
| def decode_pil(image_bytes: bytes | IO[bytes] | Image.Image) -> Image.Image:
 | |
|     if isinstance(image_bytes, Image.Image):
 | |
|         return image_bytes
 | |
|     image = Image.open(BytesIO(image_bytes) if isinstance(image_bytes, bytes) else image_bytes)
 | |
|     image.load()  # type: ignore
 | |
|     if not image.mode == "RGB":
 | |
|         image = image.convert("RGB")
 | |
|     return image
 | |
| 
 | |
| 
 | |
| def decode_cv2(image_bytes: NDArray[np.uint8] | bytes | Image.Image) -> NDArray[np.uint8]:
 | |
|     if isinstance(image_bytes, bytes):
 | |
|         image_bytes = decode_pil(image_bytes)  # pillow is much faster than cv2
 | |
|     if isinstance(image_bytes, Image.Image):
 | |
|         return pil_to_cv2(image_bytes)
 | |
|     return image_bytes
 |