Kaelygon

amogusDither.py

Dec 3rd, 2025 (edited)
28
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.39 KB | None | 0 0
  1. ##CC0 Kaelygon 2025
  2. import math
  3. import numpy as np
  4. from PIL import Image
  5. from dataclasses import dataclass, field
  6.  
  7. class ImgConverter:
  8.     #amogus matrix
  9.     amogus = np.array([
  10.         [0,1,1,1,0],
  11.         [1,1,0,0,0],
  12.         [1,1,1,1,0],
  13.         [0,1,0,1,0],
  14.         [0,0,0,0,0],
  15.     ])
  16.     amogus = (amogus/(np.max(amogus)+1))**2.0 #gamma correct
  17.     dither_width = 1.0
  18.     amogus*=dither_width
  19.    
  20.     pixels = None #Don't mutate this after init
  21.     pixels_output = None #copy of pixels that can be modified
  22.     size = None
  23.  
  24.     def __init__(self, input_path):
  25.         self.imgToOkPixels(input_path)
  26.  
  27.     #private
  28.     def _limitDepth(self, colors: np.ndarray, color_depth: np.array):
  29.         return np.round(colors*color_depth)/color_depth
  30.  
  31.     #public
  32.     def imgToOkPixels(self, img_path: str):
  33.         in_img = Image.open(img_path).convert("RGBA")
  34.         rgba = np.array(in_img, dtype=np.float64) / 255.0
  35.         self.pixels = rgba.reshape(-1, 4)
  36.         self.pixels_output = self.pixels
  37.         self.size = in_img.size
  38.  
  39.     def saveImage(self, output_path: str, color_depth: np.array):
  40.         rgba = self.pixels_output
  41.         rgba = self._limitDepth(rgba, color_depth)
  42.         rgba = np.clip(np.round(rgba * 255), 0, 255).astype(np.uint8)
  43.         rgba = rgba.reshape((self.size[1], self.size[0], 4))
  44.         img = Image.fromarray(rgba, "RGBA")
  45.         img.save(output_path)
  46.  
  47.     def ditherAmogus(self, color_depth: [float]*3):
  48.         #palettize
  49.         color_depth_rgb = color_depth[:3]
  50.         pixels = self.pixels_output[...,:3].copy()
  51.  
  52.         y_idxs, x_idxs = np.divmod(np.arange(len(pixels)), self.size[0])
  53.         m_h, m_w = self.amogus.shape
  54.         thresholds = self.amogus[y_idxs % m_h, x_idxs % m_w]
  55.         pixel_gaps=1.0/np.array(color_depth_rgb)
  56.  
  57.         #apply mask
  58.         new_cols = pixels + thresholds[:,None] * pixel_gaps
  59.         new_cols = self._limitDepth(new_cols, color_depth_rgb)
  60.  
  61.         alpha = self.pixels_output[..., 3].copy()
  62.         self.pixels_output = np.concatenate([new_cols, alpha[:, None]], axis=1)
  63.    
  64.  
  65. @dataclass
  66. class ConvertPreset:
  67.     image: str #file names
  68.     output: str
  69.     color_depth: np.array #number of axis steps [R,G,B,A]
  70.  
  71. def palettizeImage(preset: ConvertPreset):
  72.     image_ok = ImgConverter(preset.image)
  73.     image_ok.ditherAmogus(preset.color_depth)
  74.     image_ok.saveImage(preset.output, preset.color_depth)
  75.  
  76.  
  77. if __name__ == '__main__':
  78.    
  79.     preset_list = [
  80.         ConvertPreset(
  81.             image           = "./testImg/KaelygonSeawing.png",
  82.             output      = "./output/palettizedImg.png",
  83.             color_depth = [6,6,7,8] #r,g,b,a
  84.         )
  85.     ]
  86.    
  87.     palettizeImage( preset_list[0]  )
Advertisement
Add Comment
Please, Sign In to add comment