fast, high peformance image processing libary.
blurry
provides image processing algorithms with halide-lang backend.
implements optimized processor for amd64 CPUs on Linux/macos
$ go get github.com/octu0/blurry
original image
rotation 0/90/180/270 clockwise
img, err := blurry.Rotate(input, blurry.Rotate90)
blurry.RotationMode |
Result |
---|---|
blurry.Rotate90 |
|
blurry.Rotate180 |
|
blurry.Rotate270 |
img, err := blurry.Grayscale(input)
img, err := blurry.Invert(input)
img, err := blurry.Brightness(input, 1.5)
img, err := blurry.Gamma(input, 2.5)
img, err := blurry.Contrast(input, 0.525)
img, err := blurry.Boxblur(input, 11)
img, err := blurry.Gaussianblur(input, 5.0)
img, err := blurry.Blockmozaic(input, 10)
img, err := blurry.Erosion(input, 5)
img, err := blurry.Dilation(input, 8)
Morphology repeats Erode and Dilate N times.
size := 5
N := 2
img, err := blurry.Morphology(input, MorphOpen, size, N)
blurry.MorphologyMode |
Result |
---|---|
blurry.MorphologyOpen |
|
blurry.MorphologyClose |
|
blurry.MorphologyGradient |
img, err := blurry.Emboss(input)
img, err := blurry.Highpass(input)
img, err := blurry.Laplacian(input)
img, err := blurry.Gradient(input)
a.k.a. Edge Detection
img, err := blurry.Edge(input)
img, err := blurry.Sobel(input)
a.k.a. Canny Edge Detection
img, err := blurry.Canny(input, 250, 100)
max:250 min:100 |
max:400 min:10 |
---|---|
img, err := blurry.CannyWithDilate(input, 250, 100, 3)
max:250 min:100 dilate:3 |
max:250 min:150 dilate:4 |
---|---|
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 |
|
blurry.CannyMorphologyClose |
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.
scores, err := blurry.MatchTemplateSAD(input, template, 1000)
filter | input | template | Result |
---|---|---|---|
none |
|||
grayscale |
|||
sobel |
|||
canny dilate:3 morph:open |
scores, err := blurry.MatchTemplateSSD(input, template, 1000)
filter | input | template | Result |
---|---|---|---|
none |
|||
grayscale |
|||
sobel |
|||
canny dilate:3 morph:open |
scores, err := blurry.MatchTemplateNCC(input, template, 0.1)
filter | input | template | Result |
---|---|---|---|
none |
|||
grayscale |
|||
sobel |
|||
canny dilate:3 morph:open |
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)
}
}
scores, err := blurry.MatchTemplateZNCC(input, template, 0.1)
filter | input | template | Result |
---|---|---|---|
none |
|||
grayscale |
|||
sobel |
|||
canny dilate:3 morph:open |
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)
}
}
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
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
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
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.
/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
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
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
See benchmark for benchmarks of other methods and performance comparison with libyuv.
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
Set up configuration for macos to be able to run image filtering directly through Halide.
$ make setup-halide-runtime
genrun
package allows you to export images to temporary file and run image filtering directly.
$ go run cmd/genrun/main.go benchmark
MIT, see LICENSE file for details.