Sign inSign up

gafda/pidupe-net

By gafda

โ€ขUpdated 5 months ago

High-performance picture duplicate finder.

Image
Content management system
1

240

gafda/pidupe-net repository overview

โ Pidupe.Net

GitHub

High-performance image duplicate finder โ€” powered by .NET 10, Blazor Server, SkiaSharp, and optional GPU acceleration (NVIDIA CUDA ยท AMD ROCm/OpenCL ยท Intel OpenCL ยท CPU fallback).

๐Ÿ‘ค Developer: @gafdaโ 
๐Ÿ“„ License: GPL v3


main

โ What is Pidupe.Net?

Pidupe.Net scans your photo library and surfaces near-duplicate files through seven complementary algorithms:

AlgorithmSpeedAccuracyDescription
CLIPโ˜…โ˜…โ˜†โ˜†โ˜†โ˜…โ˜…โ˜…โ˜…โ˜…+Semantic visual matching via CLIP ViT-B/32 (ONNX, GPU recommended)
LPIPSโ˜…โ˜…โ˜†โ˜†โ˜†โ˜…โ˜…โ˜…โ˜…โ˜…Deep perceptual distance via AlexNet backbone (ONNX, GPU recommended)
SSIMโ˜…โ˜…โ˜…โ˜†โ˜†โ˜…โ˜…โ˜…โ˜…โ˜†Structural Similarity Index (GPU-accelerable via ILGPU)
pHashโ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜†โ˜†DCT perceptual hash โ€” fast structural fingerprinting
dHashโ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜†โ˜†Gradient-based difference hash โ€” robust to scaling
Histogramโ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜†โ˜†โ˜†Color distribution correlation
MSEโ˜…โ˜…โ˜…โ˜…โ˜…โ˜…โ˜†โ˜†โ˜†โ˜†Mean Squared Error โ€” pixel-level comparison

Results appear in a clean browser UI with side-by-side previews, metadata comparison, and one-click delete or ignore actions. Everything is cached in SQLite so repeated scans are instant.


โ Image tags

Tags follow semantic versioningโ  (X.Y.Z).

TagArchitectureDescription
latestamd64 + arm64Multi-arch alias for the most recent stable release
1.0.0amd64 + arm64Current stable release

Both tags are multi-arch manifest lists โ€” Docker and Podman automatically pull the correct image for your host architecture. Use an exact X.Y.Z tag for reproducible deployments; latest is convenient for quick testing.


โ Quick start

# Docker
docker run -d \
  --name pidupe \
  -p 8008:8008 \
  -v /path/to/your/photos:/photos:rw \
  -v pidupe-data:/data \
  gafda/pidupe-net:1.0.0

# Podman
podman run -d \
  --name pidupe \
  -p 8008:8008 \
  -v /path/to/your/photos:/photos:rw \
  -v pidupe-data:/data \
  gafda/pidupe-net:1.0.0

Then open http://localhost:8008โ  in your browser, add /photos as a scan folder, and start scanning.


โ Docker Compose

โ Basic (CPU only)
services:
  pidupe:
    image: gafda/pidupe-net:1.0.0
    container_name: pidupe
    ports:
      - "8008:8008"
    volumes:
      # Your photo library (read-only is enough for scanning but not for removal)
      - /path/to/photos:/photos:ro
      # Add as many source directories as you need
      # - /mnt/nas/camera-roll:/camera-roll:ro
      # Persistent cache database and settings
      - pidupe-data:/data
    environment:
      - Pidupe__DataDirectory=/data
    restart: unless-stopped

volumes:
  pidupe-data:

โ GPU Acceleration

Pidupe.Net uses two independent GPU systems โ€” ILGPU (pHash DCT, SSIM) and ONNX Runtime (CLIP, LPIPS). The container image is GPU-agnostic โ€” GPU drivers are injected at runtime by the host toolkit. Add the relevant section to your Compose service and choose only one.

โ NVIDIA (CUDA)

Docker: Install nvidia-container-toolkitโ .
Podman: Install nvidia-ctk CDIโ .

# Docker Compose
services:
  pidupe:
    image: gafda/pidupe-net:1.0.0
    container_name: pidupe
    ports:
      - "8008:8008"
    volumes:
      - /path/to/photos:/photos:ro
      - pidupe-data:/data
    environment:
      - Pidupe__DataDirectory=/data
    restart: unless-stopped
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

volumes:
  pidupe-data:
# Podman (CDI-based, no compose changes needed)
podman run -d --name pidupe -p 8008:8008 \
  --device nvidia.com/gpu=all \
  -v /path/to/photos:/photos:ro \
  -v pidupe-data:/data \
  gafda/pidupe-net:1.0.0

Verify GPU access:

# Docker
docker run --rm --gpus all nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi
# Podman
podman run --rm --device nvidia.com/gpu=all nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi

โ AMD (ROCm / OpenCL)

Prerequisite: AMDGPU kernel module and ROCm runtime on the host.
Desktop cards RX 5000+ work with the open-source amdgpu driver.

services:
  pidupe:
    image: gafda/pidupe-net:1.0.0
    container_name: pidupe
    ports:
      - "8008:8008"
    volumes:
      - /path/to/photos:/photos:ro
      - pidupe-data:/data
    devices:
      - /dev/kfd:/dev/kfd
      - /dev/dri:/dev/dri
    group_add:
      - video
      - render
    environment:
      - Pidupe__DataDirectory=/data
    restart: unless-stopped

volumes:
  pidupe-data:
# Podman equivalent
podman run -d --name pidupe -p 8008:8008 \
  --device /dev/kfd --device /dev/dri \
  --group-add video --group-add render \
  -v /path/to/photos:/photos:ro \
  -v pidupe-data:/data \
  gafda/pidupe-net:1.0.0

โ Intel (Arc / Iris / integrated graphics, OpenCL)

Prerequisite: i915 or xe kernel driver and Intel compute runtime (intel-opencl-icd) on the host.

services:
  pidupe:
    image: gafda/pidupe-net:1.0.0
    container_name: pidupe
    ports:
      - "8008:8008"
    volumes:
      - /path/to/photos:/photos:ro
      - pidupe-data:/data
    devices:
      - /dev/dri:/dev/dri
    group_add:
      - video
      - render
    environment:
      - Pidupe__DataDirectory=/data
    restart: unless-stopped

volumes:
  pidupe-data:
# Podman equivalent
podman run -d --name pidupe -p 8008:8008 \
  --device /dev/dri \
  --group-add video --group-add render \
  -v /path/to/photos:/photos:ro \
  -v pidupe-data:/data \
  gafda/pidupe-net:1.0.0

โ Force CPU mode (disable GPU)

Set Pidupe__PreferCpu=true to disable GPU detection entirely:

environment:
  - Pidupe__DataDirectory=/data
  - Pidupe__PreferCpu=true

โ Volumes

PathPurposeNotes
/dataSQLite cache DB + settingsMust be persistent โ€” mount a named volume or host path
/photos (or any path)Photo source directoriesRead-only (:ro) is sufficient for scanning; add as many as needed. Read-Write (:rw) if intended to delete files.
# Named volume (recommended)
-v pidupe-data:/data

# Host path (alternative)
-v /home/user/.pidupe:/data

โ Environment variables

VariableDefaultDescription
Pidupe__DataDirectory/dataDirectory for the SQLite cache and settings file
Pidupe__PreferCpufalseSet to true to skip GPU detection and use CPU only

โ Accessing over the network

By default Pidupe.Net listens on port 8008. Map it to any host port:

# Access on port 80
-p 80:8008

# Bind only to localhost (reverse-proxy setup)
-p 127.0.0.1:8008:8008

For HTTPS, place a reverse proxy (e.g. Caddy, Nginx, Traefik) in front and forward requests to port 8008.


โ Mounting network shares (NAS / SMB / NFS)

Pre-mount the share on the host, then bind-mount the directory into the container:

# Mount a Samba share on the host first
sudo mount -t cifs //192.168.1.100/photos /mnt/nas-photos \
  -o username=user,password=pass,vers=3.0

# Then reference the host mount in Docker Compose
volumes:
  - /mnt/nas-photos:/nas-photos:ro

Alternatively, use Docker named volumes with the local driver:

volumes:
  nas-photos:
    driver: local
    driver_opts:
      type: cifs
      o: "username=user,password=pass,vers=3.0"
      device: "//192.168.1.100/photos"

โ Upgrading

# Docker
docker pull gafda/pidupe-net:1.0.0
docker compose up -d

# Podman
podman pull gafda/pidupe-net:1.0.0
podman stop pidupe && podman rm pidupe
# Re-run with same volumes (data is preserved)

The SQLite cache and settings in /data are forward-compatible between minor versions. A fresh scan after upgrading reuses all cached metadata.


โ Troubleshooting

SymptomSolution
Page does not loadCheck docker logs pidupe โ€” port conflict or startup error
GPU not detectedVerify host drivers and toolkit, then check logs for ILGPU/ONNX output
CLIP/LPIPS on CPU despite GPUONNX Runtime CUDA needs CUDA Toolkit 12.x + cuDNN 9.x on the host (injected via nvidia-ctk)
Scan finds no imagesConfirm the volume mount path is correct with docker exec pidupe ls /photos
Volumes empty on Podman + SELinux (Fedora, Bazzite, RHEL)Add :z to each -v flag to relabel the mount: -v /path/to/photos:/photos:ro,z
Very slow first scanExpected โ€” subsequent scans use cache and are near-instant
Out of memory on large librariesRaise the container memory limit; the app will auto-pause and resume
# Stream live logs
docker logs -f pidupe
podman logs -f pidupe

# Open a shell inside the container
docker exec -it pidupe /bin/bash
podman exec -it pidupe /bin/bash

โ Architecture and technical notes

  • Runtime: .NET 10, published as a self-contained single-file binary
  • UI: Blazor Interactive Server (WebSocket-based, no npm/webpack)
  • Cache: SQLite in WAL mode โ€” safe for concurrent reads across scans
  • GPU (ILGPU): CUDA โ†’ OpenCL โ†’ CPU fallback for pHash DCT and SSIM
  • GPU (ONNX Runtime): CUDA โ†’ ROCm โ†’ CPU fallback for CLIP and LPIPS neural networks
  • Image loading: SkiaSharp for format decoding, resizing, and thumbnail generation
  • Metadata: MetadataExtractor for EXIF, IPTC, XMP extraction
  • Container: GPU-agnostic image; NVIDIA/AMD/Intel drivers injected at runtime via host toolkit

Pidupe.Net โ€” find the duplicates, reclaim the space.

Tag summary

Content type

Image

Digest

sha256:d7468dd6eโ€ฆ

Size

855.5 MB

Last updated

5 months ago

docker pull gafda/pidupe-net