Skip to content

octu0/blurry

Repository files navigation

blurry

MIT License GoDoc Go Report Card Releases

fast, high peformance image processing libary.

blurry provides image processing algorithms with halide-lang backend.
implements optimized processor for amd64 CPUs on Linux/macos

Installation

$ go get github.com/octu0/blurry

Examples

original image

original

Rotate

rotation 0/90/180/270 clockwise

img, err := blurry.Rotate(input, blurry.Rotate90)
blurry.RotationMode Result
blurry.Rotate90 example
blurry.Rotate180 example
blurry.Rotate270 example

Grayscale

img, err := blurry.Grayscale(input)

example

Invert

img, err := blurry.Invert(input)

example

Brightness

img, err := blurry.Brightness(input, 1.5)

example

Gamma

img, err := blurry.Gamma(input, 2.5)

example

Contrast

img, err := blurry.Contrast(input, 0.525)

example

BoxBlur

img, err := blurry.Boxblur(input, 11)

example

GaussianBlur

img, err := blurry.Gaussianblur(input, 5.0)

example

BlockMozaic

img, err := blurry.Blockmozaic(input, 10)

example

Erode

img, err := blurry.Erosion(input, 5)

example

Dilate

img, err := blurry.Dilation(input, 8)

example

Morphology

Morphology repeats Erode and Dilate N times.

size := 5
N := 2
img, err := blurry.Morphology(input, MorphOpen, size, N)
blurry.MorphologyMode Result
blurry.MorphologyOpen example
blurry.MorphologyClose example
blurry.MorphologyGradient example

Emboss

img, err := blurry.Emboss(input)

example

HighPass

img, err := blurry.Highpass(input)

example

Laplacian

img, err := blurry.Laplacian(input)

example

Gradient

img, err := blurry.Gradient(input)

example

Edge

a.k.a. Edge Detection

img, err := blurry.Edge(input)

example

Sobel

img, err := blurry.Sobel(input)

example

Canny

a.k.a. Canny Edge Detection

img, err := blurry.Canny(input, 250, 100)
max:250 min:100 max:400 min:10
example example2

Canny with Dilate

img, err := blurry.CannyWithDilate(input, 250, 100, 3)
max:250 min:100 dilate:3 max:250 min:150 dilate:4
example example2

Morphology Canny with Dilate

Pre-process morphology before applying Canny process.

mode := blurry.CannyMorphologyClose
morph_size := 5
dilate_size := 3
img, err := blurry.MorphologyCannyWithDilate(input, 250, 100, mode, morph_size, dilate_size);
blurry.CannyMorphologyMode Result
blurry.CannyMorphologyOpen example
blurry.CannyMorphologyClose example

Template Matching

SAD(Sum of Absolute Difference), SSD(Sum of Squared Difference), NCC(Normalized Cross Correlation) AND ZNCC(Zero means Normalized Cross Correlation) methods are available for template matching.

SAD

scores, err := blurry.MatchTemplateSAD(input, template, 1000)
filter input template Result
none example example example
grayscale example example example
sobel example example example
canny dilate:3 morph:open example example example

SSD

scores, err := blurry.MatchTemplateSSD(input, template, 1000)
filter input template Result
none example example example
grayscale example example example
sobel example example example
canny dilate:3 morph:open example example example

NCC

scores, err := blurry.MatchTemplateNCC(input, template, 0.1)
filter input template Result
none example example example
grayscale example example example
sobel example example example
canny dilate:3 morph:open example example example

Prepared NCC

Improve processing speed by pre-calculating part of NCC process.

p, err := blurry.PrepareNCCTemplate(template)
if err != nil {
  panic(err)
}
defer blurry.FreePreparedNCCTemplate(p)

for _, img := range images {
  scores, err := blurry.PreparedMatchTemplateNCC(img, p, 0.1)
  if err != nil {
    panic(err)
  }
}

ZNCC

scores, err := blurry.MatchTemplateZNCC(input, template, 0.1)
filter input template Result
none example example example
grayscale example example example
sobel example example example
canny dilate:3 morph:open example example example

Prepared ZNCC

Improve processing speed by pre-calculating part of ZNCC process.

p, err := blurry.PrepareZNCCTemplate(template)
if err != nil {
  panic(err)
}
defer blurry.FreePreparedZNCCTemplate(p)

for _, img := range images {
  scores, err := blurry.PreparedMatchTemplateZNCC(img, p, 0.1)
  if err != nil {
    panic(err)
  }
}

CLI usage

Run it via docker.
Use docker run -v to specify where to load the images and where to output them (/tmp will be used as a temporary file).

$ mkdir myimagedir
$ mkdir myimageout
$ cp /from/img/path.png myimagedir/src.png

# grayscale
$ docker run --rm -it \
  -v $PWD/myimagedir:/img \
  -v $PWD/myimageout:/tmp \
  blurry:1.0.0 grayscale -i /img/src.png

Help

NAME:
   blurry

USAGE:
   blurry [global options] command [command options] [arguments...]

VERSION:
   1.15.2

COMMANDS:
     blockmozaic
     boxblur
     brightness
     canny
     clone
     contrast
     dilation
     edge
     emboss
     erosion
     gamma
     gaussianblur
     gradient
     grayscale
     highpass
     invert
     laplacian
     morphology
     match_template
     rotate
     sobel
     help, h         Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --debug, -d    debug mode
   --verbose, -V  verbose. more message
   --help, -h     show help
   --version, -v  print the version

Benchmarks

Halide JIT benchmarks

This is the result of using halide's benchamrk.
darwin/amd64 Intel(R) Core(TM) i7-8569U CPU @ 2.80GHz

src 320x240
BenchmarkJIT/cloneimg                      : 0.01065ms
BenchmarkJIT/rotate0                       : 0.01089ms
BenchmarkJIT/rotate90                      : 0.06175ms
BenchmarkJIT/rotate180                     : 0.01150ms
BenchmarkJIT/rotate270                     : 0.06265ms
BenchmarkJIT/grayscale                     : 0.05361ms
BenchmarkJIT/invert                        : 0.06487ms
BenchmarkJIT/brightness                    : 0.05570ms
BenchmarkJIT/gammacorrection               : 0.09380ms
BenchmarkJIT/contrast                      : 0.06393ms
BenchmarkJIT/boxblur                       : 0.22507ms
BenchmarkJIT/gaussianblur                  : 0.16436ms
BenchmarkJIT/blockmozaic                   : 0.31727ms
BenchmarkJIT/erosion                       : 0.07028ms
BenchmarkJIT/dilation                      : 0.06876ms
BenchmarkJIT/morphology_open               : 0.13085ms
BenchmarkJIT/morphology_close              : 0.12909ms
BenchmarkJIT/morphology_gradient           : 0.08012ms
BenchmarkJIT/emboss$1                      : 0.16315ms
BenchmarkJIT/laplacian                     : 0.09986ms
BenchmarkJIT/highpass                      : 0.10241ms
BenchmarkJIT/gradient                      : 0.09807ms
BenchmarkJIT/edge                          : 0.10242ms
BenchmarkJIT/sobel                         : 0.11067ms
BenchmarkJIT/canny                         : 0.59974ms
BenchmarkJIT/canny_dilate                  : 0.61581ms
BenchmarkJIT/canny_morphology_open         : 0.71039ms
BenchmarkJIT/canny_morphology_close        : 0.70871ms
BenchmarkJIT/match_template_sad            : 5.30760ms
BenchmarkJIT/match_template_ssd            : 4.17522ms
BenchmarkJIT/match_template_ncc            : 8.02835ms
BenchmarkJIT/prepared_match_template_ncc   : 5.92526ms
BenchmarkJIT/match_template_zncc           : 11.82611ms
BenchmarkJIT/prepared_match_template_zncc  : 10.78653ms

AOT benchmarks

Calling a library compiled by AOT(ahead-of-time) via cgo.
In cgo, due to the overhead of ffi calls(e.g.), more complex operations will be optimized for CPU and become faster.
Also, the execution speed may be reduced by the overhead of multiple calls.

Blur

/D is DisablePool, i.e. the benchmark when BufferPool is off.

goos: darwin
goarch: amd64
pkg: github.com/octu0/blurry
cpu: Intel(R) Core(TM) i7-8569U CPU @ 2.80GHz
BenchmarkBlur
BenchmarkBlur/bild/blur/Box
BenchmarkBlur/bild/blur/Box-8         	     150	   7792666 ns/op	  640322 B/op	      11 allocs/op
BenchmarkBlur/bild/blur/Gaussian
BenchmarkBlur/bild/blur/Gaussian-8    	     338	   3317723 ns/op	 1262513 B/op	      21 allocs/op
BenchmarkBlur/imaging/Blur
BenchmarkBlur/imaging/Blur-8          	     801	   1482781 ns/op	  793696 B/op	      45 allocs/op
BenchmarkBlur/stackblur-go
BenchmarkBlur/stackblur-go-8          	     242	   4989647 ns/op	  925932 B/op	  153609 allocs/op
BenchmarkBlur/libyuv/ARGBBlur
BenchmarkBlur/libyuv/ARGBBlur-8       	    1843	    638517 ns/op	10182723 B/op	       3 allocs/op
BenchmarkBlur/blurry/Boxblur
BenchmarkBlur/blurry/Boxblur-8        	    3666	    355664 ns/op	     173 B/op	       2 allocs/op
BenchmarkBlur/blurry/Gaussianblur
BenchmarkBlur/blurry/Gaussianblur-8   	    5731	    216902 ns/op	     142 B/op	       2 allocs/op
BenchmarkBlur/blurry/Boxblur/D
BenchmarkBlur/blurry/Boxblur/D-8      	    3114	    367782 ns/op	  311361 B/op	       2 allocs/op
BenchmarkBlur/blurry/Gaussianblur/D
BenchmarkBlur/blurry/Gaussianblur/D-8 	    5107	    235022 ns/op	  311361 B/op	       2 allocs/op

Edge

goos: darwin
goarch: amd64
pkg: github.com/octu0/blurry
cpu: Intel(R) Core(TM) i7-8569U CPU @ 2.80GHz
BenchmarkEdge
BenchmarkEdge/bild/EdgeDetection
BenchmarkEdge/bild/EdgeDetection-8         	     679	   1794476 ns/op	  631299 B/op	      10 allocs/op
BenchmarkEdge/blurry/Edge
BenchmarkEdge/blurry/Edge-8                	    9400	    129556 ns/op	  311479 B/op	       3 allocs/op

Sobel

BenchmarkSobel
BenchmarkSobel/bild/Sobel
BenchmarkSobel/bild/Sobel-8         	     216	   5809142 ns/op	 2196756 B/op	      32 allocs/op
BenchmarkSobel/libyuv/ARGBSobel
BenchmarkSobel/libyuv/ARGBSobel-8   	   17019	     70557 ns/op	  311361 B/op	       2 allocs/op
BenchmarkSobel/blurry/Sobel
BenchmarkSobel/blurry/Sobel-8       	    6210	    199204 ns/op	  311488 B/op	       3 allocs/op

Other Benchmarks

See benchmark for benchmarks of other methods and performance comparison with libyuv.

Build

When building, create a docker container with Halide(clang, llvm, etc). installed as the build environment.

$ make build-generator

Compile libruntime.a and all kinds lib*_osx.a or lib*_linu.a to make static link.

$ make generate

Finally, generate a docker image if necessary.

$ make build

Develop

Set up configuration for macos to be able to run image filtering directly through Halide.

setup Halide on local

$ make setup-halide-runtime

generate and run

genrun package allows you to export images to temporary file and run image filtering directly.

$ go run cmd/genrun/main.go benchmark

License

MIT, see LICENSE file for details.