Faster than the fastest in the world pixel-by-pixel image difference tool.

Related tags

Images tools imgdiff
Overview

imgdiff

Faster than the fastest in the world pixel-by-pixel image difference tool.

Why?

imgdiff isn't as fast as a tool like this should be and I'm not proud of it, but it is 3X faster than the fastest in the world pixel-by-pixel image difference tool, so maybe you'll find it useful.

Features

It can do everything odiff can. Faster.

Benchmarks

I've tested it on Linux, Intel(R) Core(TM) i7-4700HQ CPU @ 2.40GHz, 8 cores.

Cypress image 3446 x 10728

Command Mean [s] Min [s] Max [s] Relative
imgdiff images/cypress-1.png images/cypress-2.png output.png 1.442 ± 0.012 1.420 1.462 1.00
odiff images/cypress-1.png images/cypress-2.png output.png 6.475 ± 0.092 6.300 6.583 4.49

Water image 8400 x 4725

Command Mean [s] Min [s] Max [s] Relative
imgdiff images/water-1.png images/water-2.png output.png 1.908 ± 0.0058 1.841 2.002 1.00
odiff images/water-1.png images/water-2.png output.png 6.016 ± 0.415 5.643 7.140 3.15

Usage

Usage: imgdiff [--threshold THRESHOLD] [--diff-image] [--fail-on-layout] BASE COMPARE OUTPUT

Positional arguments:
  BASE                   Base image.
  COMPARE                Image to compare with.
  OUTPUT                 Output image path.

Options:
  --threshold THRESHOLD, -t THRESHOLD
                         Color difference threshold (from 0 to 1). Less more precise. [default: 0.1]
  --diff-image           Render image to the diff output instead of transparent background. [default: false]
  --fail-on-layout       Do not compare images and produce output if images layout is different. [default: false]
  --help, -h             display this help and exit

Download

You can find pre-built binaries here. imgdiff is written in Go, so there shouldn't be any troubles to compile it for the most of popular platforms.

Comments
  • Make the module available for developers

    Make the module available for developers

    To integrate your tool in an other projects, the module path must be changed from imgdiff to github.com/n7olkachev/imgdiff.

    So one can use your project as package. It would be great, e.g. in unit tests.

    opened by Mik- 5
  • Output is a zero-byte PNG file

    Output is a zero-byte PNG file

    Version: 1.0.0

    It computed the number of different pixels, but the output is empty.

    Example:

    curl -O https://user-images.githubusercontent.com/640840/112396875-03837d80-8ccf-11eb-8aa2-ef605eb6ab60.png
    curl -O https://user-images.githubusercontent.com/640840/112396905-0da57c00-8ccf-11eb-8cd3-dab6d42cbfa1.png
    
    ./bin/imgdiff-darwin-amd64 --threshold 0.01 112396875-03837d80-8ccf-11eb-8aa2-ef605eb6ab60.png 112396905-0da57c00-8ccf-11eb-8cd3-dab6d42cbfa1.png output_diff.png
    

    I get this output:

    Failure! Images are different.
    Different pixels: 3992
    

    But the file is empty:

    0B 24 Mar 18:34 output_diff.png
    

    Any ideas? This is a fantastic tool that really boosted our end-to-end screenshots tests. I get these zero-byte files every ~1-2 in 100 diffs.

    opened by eliseumds 4
  • Update docs :D

    Update docs :D

    First of all, I want to say thank you for doing this. I spent pretty a lot of time on making it works, but thanks to this library I realized that one of the dependencies were doing massive data copying and finally made it the fastest :D

    If you will manually run odiff v2 with the same cypress.io screenshot you will see that

    | Command | Mean [s] | Min [s] | Max [s] | Relative | |:---|---:|---:|---:|---:| | odiff www.cypress.io.png www.cypress.io-1.png www.cypress-diff.png | 1.194 ± 0.017 | 1.173 | 1.217 | 1.04 ± 0.06 | | ./main www.cypress.io.png www.cypress.io-1.png www.cypress-diff.png | 1.146 ± 0.068 | 1.096 | 1.321 | 1.00 |

    wow, its slower. But a little big magic of removing parallelization

    git diff removing parallelization

    Just make git apply "code" if you want

    diff --git a/pkg/imgdiff/imgdiff.go b/pkg/imgdiff/imgdiff.go
    index 3af22c0..8a7ae41 100644
    --- a/pkg/imgdiff/imgdiff.go
    +++ b/pkg/imgdiff/imgdiff.go
    @@ -4,8 +4,6 @@ import (
     	"image"
     	"image/color"
     	"imgdiff/pkg/yiq"
    -	"runtime"
    -	"sync"
     	"sync/atomic"
     )
     
    @@ -30,43 +28,29 @@ func Diff(image1 image.Image, image2 image.Image, options *Options) *Result {
     
     	diff := image.NewNRGBA(image1.Bounds())
     
    -	wg := sync.WaitGroup{}
    +	diffPixelsCounter := 0
     
    -	cpus := runtime.NumCPU()
    +	for y := 0; y <= image1.Bounds().Max.Y; y++ {
    +		for x := 0; x <= image1.Bounds().Max.X; x++ {
    +			pixel1, pixel2 := image1.At(x, y), image2.At(x, y)
     
    -	for i := 0; i < cpus; i++ {
    -		wg.Add(1)
    +			if pixel1 != pixel2 {
    +				delta := yiq.Delta(pixel1, pixel2)
     
    -		go func(i int) {
    -			diffPixelsCounter := 0
    +				if delta > maxDelta {
    +					diff.SetNRGBA(x, y, color.NRGBA{R: 255, G: 0, B: 0, A: 255})
     
    -			for y := i; y <= image1.Bounds().Max.Y; y += cpus {
    -				for x := 0; x <= image1.Bounds().Max.X; x++ {
    -					pixel1, pixel2 := image1.At(x, y), image2.At(x, y)
    -
    -					if pixel1 != pixel2 {
    -						delta := yiq.Delta(pixel1, pixel2)
    -
    -						if delta > maxDelta {
    -							diff.SetNRGBA(x, y, color.NRGBA{R: 255, G: 0, B: 0, A: 255})
    -
    -							diffPixelsCounter++
    -						}
    -					} else if options.DiffImage {
    -						diff.Set(x, y, pixel1)
    -					}
    +					diffPixelsCounter++
     				}
    +			} else if options.DiffImage {
    +				diff.Set(x, y, pixel1)
     			}
    -
    -			if diffPixelsCounter > 0 {
    -				atomic.AddUint64(&diffPixelsCount, uint64(diffPixelsCounter))
    -			}
    -
    -			wg.Done()
    -		}(i)
    +		}
     	}
     
    -	wg.Wait()
    +	if diffPixelsCounter > 0 {
    +		atomic.AddUint64(&diffPixelsCount, uint64(diffPixelsCounter))
    +	}
     
     	return &Result{
     		Equal:           diffPixelsCount == 0,
    

    And odiff becomes 2x faster

    | Command | Mean [s] | Min [s] | Max [s] | Relative | |:---|---:|---:|---:|---:| | odiff www.cypress.io.png www.cypress.io-1.png www.cypress-diff.png | 1.192 ± 0.018 | 1.172 | 1.229 | 1.00 | | ./main www.cypress.io.png www.cypress.io-1.png www.cypress-diff.png | 2.616 ± 0.023 | 2.587 | 2.649 | 2.19 ± 0.04 |

    Actually, it's not a problem of making such kinds of tools multi-core, but it doesn't make a lot of sense, cause they are mostly will be executed as a child process. But parallelizing itself costs, so if we will take a little bit smaller image – even with parallelization it is slower

    | Command | Mean [ms] | Min [ms] | Max [ms] | Relative | |:---|---:|---:|---:|---:| | odiff donkey.png donkey-2.png donkey-diff.png | 370.9 ± 35.8 | 347.7 | 438.5 | 1.00 | | ./main donkey.png donkey-2.png donkey-diff.png | 381.6 ± 7.6 | 375.2 | 399.6 | 1.03 ± 0.10 |

    It's your turn :D

    opened by dmtrKovalenko 3
  • Why is threshold multiplied twice?

    Why is threshold multiplied twice?

    https://github.com/n7olkachev/imgdiff/blob/3eef05cf1006158db2aab884cb3ca755dd180090/pkg/imgdiff/imgdiff.go#L30

    I'm confused why this line is like this. I'd assume the threshold (from 0 to 1) only needs to be multiplied once?

    opened by makeworld-the-better-one 2
  • Create LICENSE

    Create LICENSE

    Just saw this on Hacker News and I was wondering if you would like to add a license to the imgdiff tool since, by default, copyright is "all rights reserved". A list of popular licenses are available here, though I might suggest the MIT license.

    opened by 0x326 1
  • how to output coordinate x,y  of  difference area

    how to output coordinate x,y of difference area

    sir instead of store output image to local drive ,how can i get the four corner point x y value array top x,y lowest x,y so i can crop the area from original file

    opened by wanghaisheng 0
Owner
Nikita Tolkachev
Nikita Tolkachev
Build apps for pixel-based displays.

Pixlet Pixlet is an app runtime and UX toolkit for highly-constrained displays. We use Pixlet to develop applets for Tidbyt, which has a 64x32 RGB LED

Tidbyt 531 Nov 26, 2022
Example of how to achieve pixel perfect shadows in a 2D view

Lights and Shadows Example of how to achieve pixel perfect shadows in a 2D view. The sample is based on the following sources: 2D Pixel Perfect Shadow

Defold 13 Oct 26, 2022
darkroom - An image proxy with changeable storage backends and image processing engines with focus on speed and resiliency.

Darkroom - Yet Another Image Proxy Introduction Darkroom combines the storage backend and the image processor and acts as an Image Proxy on your image

Gojek 203 Dec 6, 2022
Easily customizable Social image (or Open graph image) generator

fancycard Easily customizable Social image (or Open graph image) generator Built with Go, Gin, GoQuery and Chromedp Build & Run Simply, Clone this rep

Youngbin Han 4 Jan 14, 2022
An API which allows you to upload an image and responds with the same image, stripped of EXIF data

strip-metadata This is an API which allows you to upload an image and responds with the same image, stripped of EXIF data. How to run You need to have

Cristina Simionescu 0 Nov 25, 2021
Imgpreview - Tiny image previews for HTML while the original image is loading

imgpreview This is a Go program that generates tiny blurry previews for images t

Dmitry Chestnykh 8 May 22, 2022
🔍 Go tool for LSB steganography, capable of hiding any file within an image.

stegify Overview stegify is a simple command line tool capable of fully transparent hiding any file within an image or set of images. This technique i

Dimitar Petrov 1.1k Nov 27, 2022
An extensive, fast, and accurate command-line image dithering tool.

didder is an extensive, fast, and accurate command-line image dithering tool. It is designed to work well for both power users as well as pipeline scripting. It is backed by my dithering library, and is unique in its correctness and variety of dithering algorithms.

makeworld 162 Nov 21, 2022
A lightweight and easy to use tool for deflickering timelapse image sequences.

Simple Deflicker A minimalist, lightning-fast and easy to use tool for deflickering image sequences such as timelapses. It's still in its early stages

Lennart Demes 83 Aug 12, 2022
Tool to scan a container image's rootfs

image-rootfs-scanner A tool to pull and scan the rootfs of any container image for different binaries. It started out as a means of finding "restricte

Microsoft Azure 10 Mar 30, 2022
Image processing algorithms in pure Go

bild A collection of parallel image processing algorithms in pure Go. The aim of this project is simplicity in use and development over absolute high

Anthony N. Simon 3.7k Dec 3, 2022
Go package for fast high-level image processing powered by libvips C library

bimg Small Go package for fast high-level image processing using libvips via C bindings, providing a simple programmatic API. bimg was designed to be

Tom 2.1k Dec 3, 2022
Image processing library and rendering toolkit for Go.

blend Image processing library and rendering toolkit for Go. (WIP) Installation: This library is compatible with Go1. go get github.com/phrozen/blend

Guillermo Estrada 61 Nov 11, 2022
Decode embedded EXIF meta data from image files.

goexif Provides decoding of basic exif and tiff encoded data. Still in alpha - no guarantees. Suggestions and pull requests are welcome. Functionality

Robert Carlsen 540 Nov 19, 2022
A lightning fast image processing and resizing library for Go

govips A lightning fast image processing and resizing library for Go This package wraps the core functionality of libvips image processing library by

David Byttow 799 Dec 8, 2022
Fast, simple, scalable, Docker-ready HTTP microservice for high-level image processing

imaginary Fast HTTP microservice written in Go for high-level image processing backed by bimg and libvips. imaginary can be used as private or public

Tom 4.7k Dec 1, 2022
Imaging is a simple image processing package for Go

Imaging Package imaging provides basic image processing functions (resize, rotate, crop, brightness/contrast adjustments, etc.). All the image process

Grigory Dryapak 4.5k Dec 6, 2022
Pure golang image resizing

This package is no longer being updated! Please look for alternatives if that bothers you. Resize Image resizing for the Go programming language with

Jan Schlicht 2.9k Nov 24, 2022
smartcrop finds good image crops for arbitrary crop sizes

smartcrop smartcrop finds good image crops for arbitrary sizes. It is a pure Go implementation, based on Jonas Wagner's smartcrop.js Image: https://ww

Christian Muehlhaeuser 1.7k Nov 25, 2022