unfake


Nameunfake JSON
Version 1.0.1 PyPI version JSON
download
home_pageNone
SummaryHigh-performance tool for improving AI-generated pixel art
upload_time2025-07-26 21:35:36
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseMIT
keywords pixel-art image-processing quantization ai-art optimization rust-python
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # unfake

Improve AI-generated pixel art through scale detection, color quantization, and smart downscaling. Features Rust acceleration for critical operations, achieving a 10-20% speedup over the original JavaScript implementation.

Based on the excellent work by:
- **Eugeniy Smirnov** ([jenissimo/unfake.js](https://github.com/jenissimo/unfake.js)) - Original JavaScript implementation
- **Igor Bezkrovnyi** ([ibezkrovnyi/image-quantization](https://github.com/ibezkrovnyi/image-quantization)) - Image quantization algorithms

## Examples
Click each image to view the original, processed result, and results of two different naïve fixed-size-nearest-neighbor methods.
<img width="4156" height="1054" alt="comparison_grid" src="https://github.com/user-attachments/assets/f48d09a6-991e-4c51-b881-f75ddfc45e86" />
<img width="4140" height="1054" alt="comparison_grid" src="https://github.com/user-attachments/assets/4b17c7c3-cb0e-48d5-b47b-9daaa44e7999" />
<img width="4128" height="1038" alt="comparison_grid" src="https://github.com/user-attachments/assets/2bdee15e-ee00-462b-bc1a-456e8f156377" />
<img width="7212" height="2328" alt="comparison_grid" src="https://github.com/user-attachments/assets/9f37e1f7-68aa-4173-90d7-1fbfbcad5895" />
<img width="7196" height="2334" alt="comparison_grid" src="https://github.com/user-attachments/assets/65afdd0d-6f80-4997-bb6f-5b63e2fa83bc" />

Images taken from examples for AI pixel art models like [Pixel Art XL](https://huggingface.co/nerijs/pixel-art-xl), [FLUX.1-Dev Pixel LoRA](https://huggingface.co/UmeAiRT/FLUX.1-dev-LoRA-Modern_Pixel_art), and [FLUX.1-Kontext Pixel LoRA](https://huggingface.co/Shakker-Labs/FLUX.1-Kontext-dev-LoRA-Pixel-Style?image-viewer=EE86A1D8F1D252D65E9E06A3AAA2F5EF79A47E8A).

## Features

- **Automatic Scale Detection**: Detects the inherent scale of pixel art using both runs-based and edge-aware methods
- **Advanced Color Quantization**: Wu color quantization algorithm with Rust acceleration
- **Smart Downscaling**: Multiple methods including dominant color, median, mode, and content-adaptive
- **Image Cleanup**: Alpha binarization, morphological operations, and jaggy edge removal
- **Grid Snapping**: Automatic alignment to pixel grid for clean results
- **Flexible API**: Both synchronous and asynchronous interfaces
- **Fast**: Process a 1-megapixel image in as fast as half a second.

### Upcoming

- Vectorization

## Installation

### From PyPI (recommended)

```bash
pip install unfake
```

### From Source

```bash
# Clone the repository
git clone https://github.com/yourusername/unfake.git
cd unfake

# Install with pip (includes Rust compilation)
pip install .

# Or for development
pip install -e .
```

### Requirements

- Python 3.8+
- Rust toolchain (for building from source)
- OpenCV Python bindings
- Pillow
- NumPy

## Usage

### Command Line

```bash
# Basic usage with auto-detection
unfake input.png

# Specify output file
unfake input.png -o output.png

# Control color palette size
unfake input.png -c 16                    # Maximum 16 colors
unfake input.png --auto-colors            # Auto-detect optimal color count

# Force specific scale
unfake input.png --scale 4                # Force 4x downscaling

# Choose downscaling method
unfake input.png -m dominant              # Dominant color (default, best for pixel art)
unfake input.png -m median                # Median color
unfake input.png -m content-adaptive      # High quality but slower

# Enable cleanup operations
unfake input.png --cleanup morph,jaggy    # Morphological + jaggy edge cleanup

# Use fixed color palette
unfake input.png --palette palette.txt    # File with hex colors, one per line

# Adjust processing parameters
unfake input.png --alpha-threshold 200    # Higher threshold for alpha binarization
unfake input.png --threshold 0.1          # Dominant color threshold (0.0-1.0)
unfake input.png --no-snap                # Disable grid snapping

# Verbose output
unfake input.png -v                       # Show detailed processing info
```

### Python API

```python
import unfake

# Basic processing with defaults
result = unfake.process_image_sync(
    "input.png",
    max_colors=32,                       # Maximum colors in output
    detect_method="auto",                # Scale detection: "auto", "runs", "edge"
    downscale_method="dominant",         # Method: "dominant", "median", "mode", "mean", "content-adaptive"
    cleanup={"morph": False, "jaggy": False},
    snap_grid=True                       # Align to pixel grid
)

# Access results
processed_image = result['image']        # PIL Image
palette = result['palette']              # List of hex colors
manifest = result['manifest']            # Processing metadata

# Auto-detect optimal colors
result = unfake.process_image_sync(
    "input.png",
    max_colors=None,                     # Auto-detect
    auto_color_detect=True
)

# Use fixed palette
fixed_colors = ['#000000', '#ffffff', '#ff0000', '#00ff00', '#0000ff']
result = unfake.process_image_sync(
    "input.png",
    fixed_palette=fixed_colors
)
```

#### Asynchronous API

```python
import asyncio
import unfake

async def process_image_async():
    result = await unfake.process_image(
        "input.png",
        max_colors=16,
        detect_method="runs",
        downscale_method="median",
        cleanup={"morph": True, "jaggy": False},
        snap_grid=True
    )
    result["image"].save("output.png")

asyncio.run(process_image_async())
```

### Processing Options

#### Scale Detection Methods
- **`auto`** (default): Tries runs-based first, falls back to edge-aware
- **`runs`**: Analyzes color run lengths (fast, works well for clean pixel art)
- **`edge`**: Uses edge detection (slower but handles anti-aliased images)

#### Downscaling Methods
- **`dominant`** (default): Uses most frequent color in each block (best for pixel art)
- **`median`**: Median color value (good for photos)
- **`mode`**: Most common color (similar to dominant)
- **`mean`**: Average color (can create new colors)
- **`content-adaptive`**: Advanced algorithm based on [Kopf & Lischinski 2011](https://johanneskopf.de/publications/downscaling/)

#### Cleanup Options
- **`morph`**: Morphological operations to remove noise
- **`jaggy`**: Removes isolated diagonal pixels

## Performance
Example processing times for a 1024x1024 image on a high-end Intel desktop CPU using defaults:
- Pure Python: ~71 seconds
- With Rust Acceleration: ~700 milliseconds (about 100x speedup!)

## Algorithm Details

### Scale Detection
The tool uses two methods to detect the inherent scale of pixel art:

1. **Runs-based**: Analyzes horizontal and vertical color runs to find the GCD
2. **Edge-aware**: Uses Sobel edge detection to find regular grid patterns

### Color Quantization
Implements the Wu color quantization algorithm (1992) which:
- Builds a 3D color histogram
- Recursively subdivides color space
- Minimizes variance within each partition
- Produces high-quality palettes

### Downscaling
The dominant color method:
- Divides image into scale×scale blocks
- Finds most frequent color in each block
- Falls back to mean if no color is dominant
- Preserves original palette colors

## Credits

This Python/Rust implementation is based on:

- **[unfake.js](https://github.com/jenissimo/unfake.js)** by Eugeniy Smirnov - The original JavaScript implementation that inspired this project
- **[image-quantization](https://github.com/ibezkrovnyi/image-quantization)** by Igor Bezkrovnyi - TypeScript implementation of various color quantization algorithms

Additional references:
- Wu, Xiaolin. "Efficient Statistical Computations for Optimal Color Quantization" (1992)
- Kopf, Johannes and Dani Lischinski. "Depixelizing Pixel Art" (2011)

## License

MIT License 


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "unfake",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "pixel-art, image-processing, quantization, ai-art, optimization, rust-python",
    "author": null,
    "author_email": "Benjamin Paine <painebenjamin@gmail.com>",
    "download_url": null,
    "platform": null,
    "description": "# unfake\n\nImprove AI-generated pixel art through scale detection, color quantization, and smart downscaling. Features Rust acceleration for critical operations, achieving a 10-20% speedup over the original JavaScript implementation.\n\nBased on the excellent work by:\n- **Eugeniy Smirnov** ([jenissimo/unfake.js](https://github.com/jenissimo/unfake.js)) - Original JavaScript implementation\n- **Igor Bezkrovnyi** ([ibezkrovnyi/image-quantization](https://github.com/ibezkrovnyi/image-quantization)) - Image quantization algorithms\n\n## Examples\nClick each image to view the original, processed result, and results of two different na\u00efve fixed-size-nearest-neighbor methods.\n<img width=\"4156\" height=\"1054\" alt=\"comparison_grid\" src=\"https://github.com/user-attachments/assets/f48d09a6-991e-4c51-b881-f75ddfc45e86\" />\n<img width=\"4140\" height=\"1054\" alt=\"comparison_grid\" src=\"https://github.com/user-attachments/assets/4b17c7c3-cb0e-48d5-b47b-9daaa44e7999\" />\n<img width=\"4128\" height=\"1038\" alt=\"comparison_grid\" src=\"https://github.com/user-attachments/assets/2bdee15e-ee00-462b-bc1a-456e8f156377\" />\n<img width=\"7212\" height=\"2328\" alt=\"comparison_grid\" src=\"https://github.com/user-attachments/assets/9f37e1f7-68aa-4173-90d7-1fbfbcad5895\" />\n<img width=\"7196\" height=\"2334\" alt=\"comparison_grid\" src=\"https://github.com/user-attachments/assets/65afdd0d-6f80-4997-bb6f-5b63e2fa83bc\" />\n\nImages taken from examples for AI pixel art models like [Pixel Art XL](https://huggingface.co/nerijs/pixel-art-xl), [FLUX.1-Dev Pixel LoRA](https://huggingface.co/UmeAiRT/FLUX.1-dev-LoRA-Modern_Pixel_art), and [FLUX.1-Kontext Pixel LoRA](https://huggingface.co/Shakker-Labs/FLUX.1-Kontext-dev-LoRA-Pixel-Style?image-viewer=EE86A1D8F1D252D65E9E06A3AAA2F5EF79A47E8A).\n\n## Features\n\n- **Automatic Scale Detection**: Detects the inherent scale of pixel art using both runs-based and edge-aware methods\n- **Advanced Color Quantization**: Wu color quantization algorithm with Rust acceleration\n- **Smart Downscaling**: Multiple methods including dominant color, median, mode, and content-adaptive\n- **Image Cleanup**: Alpha binarization, morphological operations, and jaggy edge removal\n- **Grid Snapping**: Automatic alignment to pixel grid for clean results\n- **Flexible API**: Both synchronous and asynchronous interfaces\n- **Fast**: Process a 1-megapixel image in as fast as half a second.\n\n### Upcoming\n\n- Vectorization\n\n## Installation\n\n### From PyPI (recommended)\n\n```bash\npip install unfake\n```\n\n### From Source\n\n```bash\n# Clone the repository\ngit clone https://github.com/yourusername/unfake.git\ncd unfake\n\n# Install with pip (includes Rust compilation)\npip install .\n\n# Or for development\npip install -e .\n```\n\n### Requirements\n\n- Python 3.8+\n- Rust toolchain (for building from source)\n- OpenCV Python bindings\n- Pillow\n- NumPy\n\n## Usage\n\n### Command Line\n\n```bash\n# Basic usage with auto-detection\nunfake input.png\n\n# Specify output file\nunfake input.png -o output.png\n\n# Control color palette size\nunfake input.png -c 16                    # Maximum 16 colors\nunfake input.png --auto-colors            # Auto-detect optimal color count\n\n# Force specific scale\nunfake input.png --scale 4                # Force 4x downscaling\n\n# Choose downscaling method\nunfake input.png -m dominant              # Dominant color (default, best for pixel art)\nunfake input.png -m median                # Median color\nunfake input.png -m content-adaptive      # High quality but slower\n\n# Enable cleanup operations\nunfake input.png --cleanup morph,jaggy    # Morphological + jaggy edge cleanup\n\n# Use fixed color palette\nunfake input.png --palette palette.txt    # File with hex colors, one per line\n\n# Adjust processing parameters\nunfake input.png --alpha-threshold 200    # Higher threshold for alpha binarization\nunfake input.png --threshold 0.1          # Dominant color threshold (0.0-1.0)\nunfake input.png --no-snap                # Disable grid snapping\n\n# Verbose output\nunfake input.png -v                       # Show detailed processing info\n```\n\n### Python API\n\n```python\nimport unfake\n\n# Basic processing with defaults\nresult = unfake.process_image_sync(\n    \"input.png\",\n    max_colors=32,                       # Maximum colors in output\n    detect_method=\"auto\",                # Scale detection: \"auto\", \"runs\", \"edge\"\n    downscale_method=\"dominant\",         # Method: \"dominant\", \"median\", \"mode\", \"mean\", \"content-adaptive\"\n    cleanup={\"morph\": False, \"jaggy\": False},\n    snap_grid=True                       # Align to pixel grid\n)\n\n# Access results\nprocessed_image = result['image']        # PIL Image\npalette = result['palette']              # List of hex colors\nmanifest = result['manifest']            # Processing metadata\n\n# Auto-detect optimal colors\nresult = unfake.process_image_sync(\n    \"input.png\",\n    max_colors=None,                     # Auto-detect\n    auto_color_detect=True\n)\n\n# Use fixed palette\nfixed_colors = ['#000000', '#ffffff', '#ff0000', '#00ff00', '#0000ff']\nresult = unfake.process_image_sync(\n    \"input.png\",\n    fixed_palette=fixed_colors\n)\n```\n\n#### Asynchronous API\n\n```python\nimport asyncio\nimport unfake\n\nasync def process_image_async():\n    result = await unfake.process_image(\n        \"input.png\",\n        max_colors=16,\n        detect_method=\"runs\",\n        downscale_method=\"median\",\n        cleanup={\"morph\": True, \"jaggy\": False},\n        snap_grid=True\n    )\n    result[\"image\"].save(\"output.png\")\n\nasyncio.run(process_image_async())\n```\n\n### Processing Options\n\n#### Scale Detection Methods\n- **`auto`** (default): Tries runs-based first, falls back to edge-aware\n- **`runs`**: Analyzes color run lengths (fast, works well for clean pixel art)\n- **`edge`**: Uses edge detection (slower but handles anti-aliased images)\n\n#### Downscaling Methods\n- **`dominant`** (default): Uses most frequent color in each block (best for pixel art)\n- **`median`**: Median color value (good for photos)\n- **`mode`**: Most common color (similar to dominant)\n- **`mean`**: Average color (can create new colors)\n- **`content-adaptive`**: Advanced algorithm based on [Kopf & Lischinski 2011](https://johanneskopf.de/publications/downscaling/)\n\n#### Cleanup Options\n- **`morph`**: Morphological operations to remove noise\n- **`jaggy`**: Removes isolated diagonal pixels\n\n## Performance\nExample processing times for a 1024x1024 image on a high-end Intel desktop CPU using defaults:\n- Pure Python: ~71 seconds\n- With Rust Acceleration: ~700 milliseconds (about 100x speedup!)\n\n## Algorithm Details\n\n### Scale Detection\nThe tool uses two methods to detect the inherent scale of pixel art:\n\n1. **Runs-based**: Analyzes horizontal and vertical color runs to find the GCD\n2. **Edge-aware**: Uses Sobel edge detection to find regular grid patterns\n\n### Color Quantization\nImplements the Wu color quantization algorithm (1992) which:\n- Builds a 3D color histogram\n- Recursively subdivides color space\n- Minimizes variance within each partition\n- Produces high-quality palettes\n\n### Downscaling\nThe dominant color method:\n- Divides image into scale\u00d7scale blocks\n- Finds most frequent color in each block\n- Falls back to mean if no color is dominant\n- Preserves original palette colors\n\n## Credits\n\nThis Python/Rust implementation is based on:\n\n- **[unfake.js](https://github.com/jenissimo/unfake.js)** by Eugeniy Smirnov - The original JavaScript implementation that inspired this project\n- **[image-quantization](https://github.com/ibezkrovnyi/image-quantization)** by Igor Bezkrovnyi - TypeScript implementation of various color quantization algorithms\n\nAdditional references:\n- Wu, Xiaolin. \"Efficient Statistical Computations for Optimal Color Quantization\" (1992)\n- Kopf, Johannes and Dani Lischinski. \"Depixelizing Pixel Art\" (2011)\n\n## License\n\nMIT License \n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "High-performance tool for improving AI-generated pixel art",
    "version": "1.0.1",
    "project_urls": {
        "Bug Tracker": "https://github.com/painebenjamin/unfake.py/issues",
        "Homepage": "https://github.com/painebenjamin/unfake.py",
        "Repository": "https://github.com/painebenjamin/unfake.py"
    },
    "split_keywords": [
        "pixel-art",
        " image-processing",
        " quantization",
        " ai-art",
        " optimization",
        " rust-python"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "1466ef784e88a56ed5c23906f7bb36ab140645d1db5725e15c400226c75c439b",
                "md5": "6e8fda69752bdeef7d0dfe1a527af0dd",
                "sha256": "1df61a549c201183f260fccd79e3145ac55b042fc872c1be94d195608799de46"
            },
            "downloads": -1,
            "filename": "unfake-1.0.1-cp38-abi3-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "6e8fda69752bdeef7d0dfe1a527af0dd",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.8",
            "size": 306248,
            "upload_time": "2025-07-26T21:35:36",
            "upload_time_iso_8601": "2025-07-26T21:35:36.358401Z",
            "url": "https://files.pythonhosted.org/packages/14/66/ef784e88a56ed5c23906f7bb36ab140645d1db5725e15c400226c75c439b/unfake-1.0.1-cp38-abi3-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "ce5c3c59408ebefa8130d915d97f015202df83da5f4d58563845a87c3a6148da",
                "md5": "4248f15be021d6c93e43c0c10bbf6362",
                "sha256": "82658acfa3cb1526c1746c68faa60e81b518fe535e40d2fd8c926e087b7bebe8"
            },
            "downloads": -1,
            "filename": "unfake-1.0.1-cp38-abi3-manylinux_2_34_x86_64.whl",
            "has_sig": false,
            "md5_digest": "4248f15be021d6c93e43c0c10bbf6362",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.8",
            "size": 350694,
            "upload_time": "2025-07-26T21:35:37",
            "upload_time_iso_8601": "2025-07-26T21:35:37.877361Z",
            "url": "https://files.pythonhosted.org/packages/ce/5c/3c59408ebefa8130d915d97f015202df83da5f4d58563845a87c3a6148da/unfake-1.0.1-cp38-abi3-manylinux_2_34_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b13fbd8d2acff4790292de5db040a9142650641bba543db9219725d6644e8cc6",
                "md5": "f651ebac4bbd721c40173aeeb61d0982",
                "sha256": "13a695b90712ae97673bcde0081151d8649ac165595269955c1a5a311da45d9f"
            },
            "downloads": -1,
            "filename": "unfake-1.0.1-cp38-abi3-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "f651ebac4bbd721c40173aeeb61d0982",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.8",
            "size": 268933,
            "upload_time": "2025-07-26T21:35:38",
            "upload_time_iso_8601": "2025-07-26T21:35:38.884771Z",
            "url": "https://files.pythonhosted.org/packages/b1/3f/bd8d2acff4790292de5db040a9142650641bba543db9219725d6644e8cc6/unfake-1.0.1-cp38-abi3-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-26 21:35:36",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "painebenjamin",
    "github_project": "unfake.py",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "unfake"
}
        
Elapsed time: 1.64187s