{"id":18821614,"url":"https://github.com/octu0/blurry","last_synced_at":"2025-09-12T22:41:24.987Z","repository":{"id":39797888,"uuid":"350646646","full_name":"octu0/blurry","owner":"octu0","description":"fast, high peformance image processing library for golang","archived":false,"fork":false,"pushed_at":"2023-10-22T07:52:45.000Z","size":60083,"stargazers_count":36,"open_issues_count":2,"forks_count":5,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-06-21T23:02:12.374Z","etag":null,"topics":["blur","canny","canny-edge-detection","edge-detection","gamma","grayscale","halide","image-filtering","image-processing","morphology","ncc","object-detection","rgb2yuv","sobel","template-matching","ycbcr","yuv","yuv2rgb","yuv420","zncc"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/octu0/blurry","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/octu0.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-03-23T09:10:07.000Z","updated_at":"2024-06-05T22:06:26.000Z","dependencies_parsed_at":"2022-08-09T15:26:01.196Z","dependency_job_id":"5b68bd2d-d1b3-4164-989f-1826db829c33","html_url":"https://github.com/octu0/blurry","commit_stats":null,"previous_names":[],"tags_count":41,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/octu0%2Fblurry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/octu0%2Fblurry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/octu0%2Fblurry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/octu0%2Fblurry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/octu0","download_url":"https://codeload.github.com/octu0/blurry/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223612891,"owners_count":17173631,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blur","canny","canny-edge-detection","edge-detection","gamma","grayscale","halide","image-filtering","image-processing","morphology","ncc","object-detection","rgb2yuv","sobel","template-matching","ycbcr","yuv","yuv2rgb","yuv420","zncc"],"created_at":"2024-11-08T00:44:53.944Z","updated_at":"2024-11-08T00:44:54.552Z","avatar_url":"https://github.com/octu0.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `blurry`\n\n[![MIT License](https://img.shields.io/github/license/octu0/blurry)](https://github.com/octu0/blurry/blob/master/LICENSE)\n[![GoDoc](https://godoc.org/github.com/octu0/blurry?status.svg)](https://godoc.org/github.com/octu0/blurry)\n[![Go Report Card](https://goreportcard.com/badge/github.com/octu0/blurry)](https://goreportcard.com/report/github.com/octu0/blurry)\n[![Releases](https://img.shields.io/github/v/release/octu0/blurry)](https://github.com/octu0/blurry/releases)\n\n**fast**, high peformance image processing libary.\n\n`blurry` provides image processing algorithms with [halide-lang](https://halide-lang.org/) backend.  \nimplements optimized processor for amd64 CPUs on Linux/macos\n\n# Benchmarks\n\n## Halide JIT benchmarks\n\nThis is the result of using halide's [benchamrk](https://github.com/halide/Halide/blob/master/tools/halide_benchmark.h).  \ndarwin/amd64 Intel(R) Core(TM) i7-8569U CPU @ 2.80GHz\n\n```\nsrc 320x240\nBenchmarkJIT/cloneimg                      : 0.00788ms\nBenchmarkJIT/convert_from_argb             : 0.02375ms\nBenchmarkJIT/convert_from_abgr             : 0.03884ms\nBenchmarkJIT/convert_from_bgra             : 0.02470ms\nBenchmarkJIT/convert_from_rabg             : 0.03655ms\nBenchmarkJIT/convert_from_yuv_420          : 0.03168ms\nBenchmarkJIT/convert_from_yuv_444          : 0.02686ms\nBenchmarkJIT/convert_to_yuv_420            : 0.06742ms\nBenchmarkJIT/convert_to_yuv_444            : 0.07209ms\nBenchmarkJIT/rotate0                       : 0.00774ms\nBenchmarkJIT/rotate90                      : 0.02599ms\nBenchmarkJIT/rotate180                     : 0.00802ms\nBenchmarkJIT/rotate270                     : 0.02582ms\nBenchmarkJIT/crop                          : 0.06126ms\nBenchmarkJIT/scale                         : 0.13889ms\nBenchmarkJIT/scale_box                     : 0.20598ms\nBenchmarkJIT/scale_linear                  : 0.20440ms\nBenchmarkJIT/scale_gaussian                : 0.31444ms\nBenchmarkJIT/blend_normal                  : 0.08443ms\nBenchmarkJIT/blend_sub                     : 0.08398ms\nBenchmarkJIT/blend_add                     : 0.08364ms\nBenchmarkJIT/blend_diff                    : 0.08453ms\nBenchmarkJIT/grayscale                     : 0.03687ms\nBenchmarkJIT/invert                        : 0.03730ms\nBenchmarkJIT/brightness                    : 0.04703ms\nBenchmarkJIT/gammacorrection               : 0.08013ms\nBenchmarkJIT/contrast                      : 0.01549ms\nBenchmarkJIT/boxblur                       : 0.11211ms\nBenchmarkJIT/gaussianblur                  : 0.33058ms\nBenchmarkJIT/blockmozaic                   : 0.27455ms\nBenchmarkJIT/erosion                       : 0.11934ms\nBenchmarkJIT/dilation                      : 0.12013ms\nBenchmarkJIT/morphology_open               : 0.10370ms\nBenchmarkJIT/morphology_close              : 0.10435ms\nBenchmarkJIT/morphology_gradient           : 0.07684ms\nBenchmarkJIT/emboss                        : 0.04402ms\nBenchmarkJIT/laplacian                     : 0.03192ms\nBenchmarkJIT/highpass                      : 0.03847ms\nBenchmarkJIT/gradient                      : 0.03322ms\nBenchmarkJIT/edgedetect                    : 0.02705ms\nBenchmarkJIT/sobel                         : 0.06276ms\nBenchmarkJIT/canny                         : 0.29922ms\nBenchmarkJIT/canny_dilate                  : 0.35114ms\nBenchmarkJIT/canny_morphology_open         : 0.44488ms\nBenchmarkJIT/canny_morphology_close        : 0.40522ms\nBenchmarkJIT/match_template_sad            : 5.75482ms\nBenchmarkJIT/match_template_ssd            : 4.48363ms\nBenchmarkJIT/match_template_ncc            : 8.32420ms\nBenchmarkJIT/prepared_match_template_ncc   : 6.22423ms\nBenchmarkJIT/match_template_zncc           : 12.73780ms\nBenchmarkJIT/prepared_match_template_zncc  : 11.38906ms\nBenchmarkJIT/pcm16_decibel                 : 0.00257ms\n```\n\n## AOT benchmarks\n\nCalling a library compiled by AOT(ahead-of-time) via cgo.  \nIn [cgo](https://golang.org/cmd/cgo/), due to the overhead of ffi calls([e.g.](https://about.sourcegraph.com/go/gophercon-2018-adventures-in-cgo-performance/)), \nmore complex operations will be optimized for CPU and become faster.  \nAlso, the execution speed may be reduced by the overhead of multiple calls.\n\n### Blur\n\n`/D` is [DisablePool](https://pkg.go.dev/github.com/octu0/blurry#DisablePool), i.e. the benchmark when BufferPool is off.\n\n![graph](_benchmark/testdata/blur_bench.png)\n\n\n```\ngoos: darwin\ngoarch: amd64\npkg: github.com/octu0/blurry/benchmark\ncpu: Intel(R) Core(TM) i7-8569U CPU @ 2.80GHz\nBenchmarkBlur\nBenchmarkBlur/bild/blur/Box\nBenchmarkBlur/bild/blur/Box-8         \t     154\t   7812824 ns/op\t  640402 B/op\t      11 allocs/op\nBenchmarkBlur/bild/blur/Gaussian\nBenchmarkBlur/bild/blur/Gaussian-8    \t     333\t   3486751 ns/op\t 1262485 B/op\t      21 allocs/op\nBenchmarkBlur/imaging/Blur\nBenchmarkBlur/imaging/Blur-8          \t     786\t   1520193 ns/op\t  793698 B/op\t      45 allocs/op\nBenchmarkBlur/stackblur-go\nBenchmarkBlur/stackblur-go-8          \t     231\t   5147219 ns/op\t  925937 B/op\t  153609 allocs/op\nBenchmarkBlur/libyuv/ARGBBlur\nBenchmarkBlur/libyuv/ARGBBlur-8       \t    1861\t    642486 ns/op\t10182722 B/op\t       3 allocs/op\nBenchmarkBlur/blurry/Boxblur\nBenchmarkBlur/blurry/Boxblur-8        \t    7257\t    178086 ns/op\t      88 B/op\t       2 allocs/op\nBenchmarkBlur/blurry/Gaussianblur\nBenchmarkBlur/blurry/Gaussianblur-8   \t    5367\t    222615 ns/op\t     146 B/op\t       2 allocs/op\nBenchmarkBlur/blurry/Boxblur/D\nBenchmarkBlur/blurry/Boxblur/D-8      \t    6093\t    201573 ns/op\t  311361 B/op\t       2 allocs/op\nBenchmarkBlur/blurry/Gaussianblur/D\nBenchmarkBlur/blurry/Gaussianblur/D-8 \t    4629\t    257483 ns/op\t  311361 B/op\t       2 allocs/op\n```\n\n### Edge\n\n![graph](_benchmark/testdata/edge_bench.png)\n\n```\ngoos: darwin\ngoarch: amd64\npkg: github.com/octu0/blurry/benchmark\ncpu: Intel(R) Core(TM) i7-8569U CPU @ 2.80GHz\nBenchmarkEdge\nBenchmarkEdge/bild/EdgeDetection\nBenchmarkEdge/bild/EdgeDetection-8         \t     643\t   1858350 ns/op\t  631257 B/op\t      10 allocs/op\nBenchmarkEdge/blurry/Edge\nBenchmarkEdge/blurry/Edge-8                \t   10000\t    100695 ns/op\t  311513 B/op\t       3 allocs/op\n```\n\n### Rotate\n\n![graph](_benchmark/testdata/rotate_bench.png)\n\n```\ngoos: darwin\ngoarch: amd64\npkg: github.com/octu0/blurry/benchmark\ncpu: Intel(R) Core(TM) i7-8569U CPU @ 2.80GHz\nBenchmarkRotate\nBenchmarkRotate/bild/Rotate/90\nBenchmarkRotate/bild/Rotate/90-8         \t     612\t   2080543 ns/op\t 1237046 B/op\t  115685 allocs/op\nBenchmarkRotate/bild/Rotate/180\nBenchmarkRotate/bild/Rotate/180-8        \t     480\t   2355424 ns/op\t 1540311 B/op\t  153605 allocs/op\nBenchmarkRotate/bild/Rotate/270\nBenchmarkRotate/bild/Rotate/270-8        \t     520\t   2061518 ns/op\t 1236932 B/op\t  115685 allocs/op\nBenchmarkRotate/imaging/90\nBenchmarkRotate/imaging/90-8             \t    7918\t    130736 ns/op\t  314181 B/op\t       6 allocs/op\nBenchmarkRotate/imaging/180\nBenchmarkRotate/imaging/180-8            \t    9654\t    138252 ns/op\t  313542 B/op\t       6 allocs/op\nBenchmarkRotate/imaging/270\nBenchmarkRotate/imaging/270-8            \t    6972\t    163349 ns/op\t  314165 B/op\t       6 allocs/op\nBenchmarkRotate/libyuv/ARGBRotate/90\nBenchmarkRotate/libyuv/ARGBRotate/90-8   \t   13423\t     81131 ns/op\t  311360 B/op\t       2 allocs/op\nBenchmarkRotate/libyuv/ARGBRotate/180\nBenchmarkRotate/libyuv/ARGBRotate/180-8  \t   34771\t     34425 ns/op\t  311361 B/op\t       2 allocs/op\nBenchmarkRotate/libyuv/ARGBRotate/270\nBenchmarkRotate/libyuv/ARGBRotate/270-8  \t   15904\t     78290 ns/op\t  311361 B/op\t       2 allocs/op\nBenchmarkRotate/blurry/Rotate/90\nBenchmarkRotate/blurry/Rotate/90-8       \t   10000\t    109336 ns/op\t  311514 B/op\t       3 allocs/op\nBenchmarkRotate/blurry/Rotate/180\nBenchmarkRotate/blurry/Rotate/180-8      \t   13102\t     89067 ns/op\t  311514 B/op\t       3 allocs/op\nBenchmarkRotate/blurry/Rotate/270\nBenchmarkRotate/blurry/Rotate/270-8      \t   10000\t    124949 ns/op\t  311514 B/op\t       3 allocs/op\n```\n\n### Sobel\n\n![graph](_benchmark/testdata/sobel_bench.png)\n\n```\ngoos: darwin\ngoarch: amd64\npkg: github.com/octu0/blurry/benchmark\ncpu: Intel(R) Core(TM) i7-8569U CPU @ 2.80GHz\nBenchmarkSobel\nBenchmarkSobel/bild/Sobel\nBenchmarkSobel/bild/Sobel-8         \t     208\t   5707148 ns/op\t 2196784 B/op\t      32 allocs/op\nBenchmarkSobel/libyuv/ARGBSobel\nBenchmarkSobel/libyuv/ARGBSobel-8   \t   16557\t     72320 ns/op\t  311361 B/op\t       2 allocs/op\nBenchmarkSobel/blurry/Sobel\nBenchmarkSobel/blurry/Sobel-8       \t    9255\t    140586 ns/op\t  311515 B/op\t       3 allocs/op\n```\n\n### Other Benchmarks\n\nSee [_benchmark](https://github.com/octu0/blurry/tree/master/_benchmark) for benchmarks of other methods and performance comparison with [libyuv](https://chromium.googlesource.com/libyuv/libyuv/).\n\n\n# Installation\n\n```shell\n$ go get github.com/octu0/blurry\n```\n\n## Examples\n\noriginal image\n\n![original](testdata/src.png)\n\n### Rotate\n\nrotation 0/90/180/270 clockwise\n\n```go\nimg, err := blurry.Rotate(input, blurry.Rotate90)\n```\n\n| `blurry.RotationMode` | Result                             |\n| :-------------------: | :--------------------------------: |\n| `blurry.Rotate90`     | ![example](testdata/rotate90.png)  |\n| `blurry.Rotate180`    | ![example](testdata/rotate180.png) |\n| `blurry.Rotate270`    | ![example](testdata/rotate270.png) |\n\n### Flip\n\nflipV(vertically) flipH(horizontally)\n\n```go\nimg, err := blurry.Flip(input, blurry.FlipVertical)\n```\n\n| `blurry.FlipMode`     | Result                             |\n| :-------------------: | :--------------------------------: |\n| `blurry.FlipVertical` | ![example](testdata/flipv.png)  |\n| `blurry.FlipHorizon`  | ![example](testdata/fliph.png) |\n\n\n### Crop\n\ncrop x,y with crop_width,crop_height\n\n```go\nimg, err := blurry.Crop(input, image.Pt(175, 40), crop_width, crop_height)\n```\n\n| original                      | `x=175,y=40,cw=80,ch=50`      |\n| :---------------------------: | :---------------------------: |\n| ![original](testdata/src.png) | ![cropped](testdata/crop.png) |\n\n### Scale\n\na.k.a. Resize resampling\n\n```go\nimg, err := blurry.Scale(input, scale_width, scale_height, blurry.ScaleFilterNone)\n```\n\n| `blurry.ScaleFilter`         | Result                                  |\n| :--------------------------: | :-------------------------------------: |\n| `blurry.ScaleFilterNone`     | ![example](testdata/scale_none.png)     |\n| `blurry.ScaleFilterBox`      | ![example](testdata/scale_box.png)      |\n| `blurry.ScaleFilterLinear`   | ![example](testdata/scale_linear.png)   |\n| `blurry.ScaleFilterGaussian` | ![example](testdata/scale_gaussian.png) |\n\n### Grayscale\n\n```go\nimg, err := blurry.Grayscale(input)\n```\n\n![example](testdata/grayscale.png)\n\n### Invert\n\n```go\nimg, err := blurry.Invert(input)\n```\n\n![example](testdata/invert.png)\n\n### Brightness\n\n```go\nimg, err := blurry.Brightness(input, 1.5)\n```\n\n![example](testdata/brightness.png)\n\n### Gamma\n\n```go\nimg, err := blurry.Gamma(input, 2.5)\n```\n\n![example](testdata/gamma.png)\n\n### Contrast\n\n```go\nimg, err := blurry.Contrast(input, 0.525)\n```\n\n![example](testdata/contrast.png)\n\n### BoxBlur\n\n```go\nimg, err := blurry.Boxblur(input, 11)\n```\n\n![example](testdata/boxblur.png)\n\n### GaussianBlur\n\n```go\nimg, err := blurry.Gaussianblur(input, 5.0)\n```\n\n![example](testdata/gaussianblur.png)\n\n### BlockMozaic\n\n```go\nimg, err := blurry.Blockmozaic(input, 10)\n```\n\n![example](testdata/blockmozaic.png)\n\n### Erode\n\n```go\nimg, err := blurry.Erosion(input, 5)\n```\n\n![example](testdata/erosion.png)\n\n### Dilate\n\n```go\nimg, err := blurry.Dilation(input, 8)\n```\n\n![example](testdata/dilation.png)\n\n### Morphology\n\nMorphology repeats Erode and Dilate N times.\n\n```go\nsize := 5\nN := 2\nimg, err := blurry.Morphology(input, MorphOpen, size, N)\n```\n\n| `blurry.MorphologyMode`     | Result                                       |\n| :-------------------------: | :------------------------------------------: |\n| `blurry.MorphologyOpen`     | ![example](testdata/morphology_open.png)     |\n| `blurry.MorphologyClose`    | ![example](testdata/morphology_close.png)    |\n| `blurry.MorphologyGradient` | ![example](testdata/morphology_gradient.png) |\n\n### Emboss\n\n```go\nimg, err := blurry.Emboss(input)\n```\n\n![example](testdata/emboss.png)\n\n### HighPass\n\n```go\nimg, err := blurry.Highpass(input)\n```\n\n![example](testdata/highpass.png)\n\n### Laplacian\n\n```go\nimg, err := blurry.Laplacian(input)\n```\n\n![example](testdata/laplacian.png)\n\n### Gradient\n\n```go\nimg, err := blurry.Gradient(input)\n```\n\n![example](testdata/gradient.png)\n\n### Edge\n\na.k.a. Edge Detection\n\n```go\nimg, err := blurry.Edge(input)\n```\n\n![example](testdata/edge.png)\n\n### Sobel\n\n```go\nimg, err := blurry.Sobel(input)\n```\n\n![example](testdata/sobel.png)\n\n### Canny\n\na.k.a. Canny Edge Detection\n\n```go\nimg, err := blurry.Canny(input, 250, 100)\n```\n\n| `max:250 min:100`                | `max:400 min:10`                             |\n| :------------------------------: | :------------------------------------------: |\n| ![example](testdata/canny.png)   | ![example2](testdata/canny_max400_min10.png) |\n\n#### Canny with Dilate\n\n```go\nimg, err := blurry.CannyWithDilate(input, 250, 100, 3)\n```\n\n| `max:250 min:100 dilate:3`                           | `max:250 min:150 dilate:4`                            |\n| :--------------------------------------------------: | :---------------------------------------------------: |\n| ![example](testdata/canny_max250_min100_dilate3.png) | ![example2](testdata/canny_max250_min150_dilate4.png) |\n\n#### Morphology Canny with Dilate\n\nPre-process morphology before applying Canny process.\n\n```go\nmode := blurry.CannyMorphologyClose\nmorph_size := 5\ndilate_size := 3\nimg, err := blurry.MorphologyCannyWithDilate(input, 250, 100, mode, morph_size, dilate_size);\n```\n\n| `blurry.CannyMorphologyMode` | Result                                       |\n| :-------------------------:  | :------------------------------------------: |\n| `blurry.CannyMorphologyOpen` | ![example](testdata/canny_morphology_open_size5_max250_min100_dilate3.png) |\n| `blurry.CannyMorphologyClose` | ![example](testdata/canny_morphology_close_size5_max250_min100_dilate3.png) |\n\n### Template Matching\n\nSAD(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.\n\n#### SAD\n\n```go\nscores, err := blurry.MatchTemplateSAD(input, template, 1000)\n```\n\n| filter                       | input                                            | template                                         | Result                                              |\n| :--------------------------: | :----------------------------------------------: | :----------------------------------------------: | :-------------------------------------------------: |\n| `none`                       | ![example](testdata/src.png)                     | ![example](testdata/tpl.png)                     | ![example](testdata/mt_sad.png)                     |\n| `grayscale`                  | ![example](testdata/grayscale.png)               | ![example](testdata/tpl_gray.png)                | ![example](testdata/mt_sad_gray.png)                |\n| `sobel`                      | ![example](testdata/sobel.png)                   | ![example](testdata/tpl_sobel.png)               | ![example](testdata/mt_sad_sobel.png)               |\n| `canny dilate:3  morph:open` | ![example](testdata/src_canny_morph_open_d3.png) | ![example](testdata/tpl_canny_morph_open_d3.png) | ![example](testdata/mt_sad_canny_morph_open_d3.png) |\n\n#### SSD\n\n```go\nscores, err := blurry.MatchTemplateSSD(input, template, 1000)\n```\n\n| filter                       | input                                            | template                                         | Result                                              |\n| :--------------------------: | :----------------------------------------------: | :----------------------------------------------: | :-------------------------------------------------: |\n| `none`                       | ![example](testdata/src.png)                     | ![example](testdata/tpl.png)                     | ![example](testdata/mt_ssd.png)                     |\n| `grayscale`                  | ![example](testdata/grayscale.png)               | ![example](testdata/tpl_gray.png)                | ![example](testdata/mt_ssd_gray.png)                |\n| `sobel`                      | ![example](testdata/sobel.png)                   | ![example](testdata/tpl_sobel.png)               | ![example](testdata/mt_ssd_sobel.png)               |\n| `canny dilate:3  morph:open` | ![example](testdata/src_canny_morph_open_d3.png) | ![example](testdata/tpl_canny_morph_open_d3.png) | ![example](testdata/mt_ssd_canny_morph_open_d3.png) |\n\n#### NCC\n\n```go\nscores, err := blurry.MatchTemplateNCC(input, template, 0.1)\n```\n\n| filter                       | input                                            | template                                         | Result                                              |\n| :--------------------------: | :----------------------------------------------: | :----------------------------------------------: | :-------------------------------------------------: |\n| `none`                       | ![example](testdata/src.png)                     | ![example](testdata/tpl.png)                     | ![example](testdata/mt_ncc.png)                     |\n| `grayscale`                  | ![example](testdata/grayscale.png)               | ![example](testdata/tpl_gray.png)                | ![example](testdata/mt_ncc_gray.png)                |\n| `sobel`                      | ![example](testdata/sobel.png)                   | ![example](testdata/tpl_sobel.png)               | ![example](testdata/mt_ncc_sobel.png)               |\n| `canny dilate:3  morph:open` | ![example](testdata/src_canny_morph_open_d3.png) | ![example](testdata/tpl_canny_morph_open_d3.png) | ![example](testdata/mt_ncc_canny_morph_open_d3.png) |\n\n#### Prepared NCC\n\nImprove processing speed by pre-calculating part of NCC process.\n\n```go\np, err := blurry.PrepareNCCTemplate(template)\nif err != nil {\n  panic(err)\n}\ndefer blurry.FreePreparedNCCTemplate(p)\n\nfor _, img := range images {\n  scores, err := blurry.PreparedMatchTemplateNCC(img, p, 0.1)\n  if err != nil {\n    panic(err)\n  }\n}\n```\n\n#### ZNCC\n\n```go\nscores, err := blurry.MatchTemplateZNCC(input, template, 0.1)\n```\n\n| filter                       | input                                            | template                                         | Result                                              |\n| :--------------------------: | :----------------------------------------------: | :----------------------------------------------: | :-------------------------------------------------: |\n| `none`                       | ![example](testdata/src.png)                     | ![example](testdata/tpl.png)                     | ![example](testdata/mt_zncc.png)                     |\n| `grayscale`                  | ![example](testdata/grayscale.png)               | ![example](testdata/tpl_gray.png)                | ![example](testdata/mt_zncc_gray.png)                |\n| `sobel`                      | ![example](testdata/sobel.png)                   | ![example](testdata/tpl_sobel.png)               | ![example](testdata/mt_zncc_sobel.png)               |\n| `canny dilate:3  morph:open` | ![example](testdata/src_canny_morph_open_d3.png) | ![example](testdata/tpl_canny_morph_open_d3.png) | ![example](testdata/mt_zncc_canny_morph_open_d3.png) |\n\n#### Prepared ZNCC\n\nImprove processing speed by pre-calculating part of ZNCC process.\n\n```go\np, err := blurry.PrepareZNCCTemplate(template)\nif err != nil {\n  panic(err)\n}\ndefer blurry.FreePreparedZNCCTemplate(p)\n\nfor _, img := range images {\n  scores, err := blurry.PreparedMatchTemplateZNCC(img, p, 0.1)\n  if err != nil {\n    panic(err)\n  }\n}\n```\n\n### Contour\n\nExtract contours based on the sobel filter for binarization.  \nIn actual use, it is better to denoise the image before passing it through the sobel filter.\n\n```go\npoints, err := blurry.Contour(input, 100, 4)\n```\n\n| `threshold` | size | Result                               |\n| :---------: | :--: | :----------------------------------: |\n| 100         | 4 | ![example](testdata/contour_100_4.png)  |\n| 150         | 4 | ![example](testdata/contour_150_4.png)  |\n| 200         | 4 | ![example](testdata/contour_200_4.png)  |\n| 250         | 4 | ![example](testdata/contour_250_4.png)  |\n| 100         | 2 | ![example](testdata/contour_100_2.png)  |\n| 200         | 2 | ![example](testdata/contour_200_2.png)  |\n\n### Blend\n\nBlend input1 on input0.\n\n```go\nimg, err := blurry.Blend(input0, input1, image.Pt(76, 36), blurry.BlendNormal)\n```\n\n| `blurry.BlendMode`    | Result                                |\n| :-------------------: | :-----------------------------------: |\n| `blurry.BlendNormal`  | ![example](testdata/blend_normal.png) |\n| `blurry.BlendSub`     | ![example](testdata/blend_sub.png)    |\n| `blurry.BlendAdd`     | ![example](testdata/blend_add.png)    |\n| `blurry.BlendDiff`    | ![example](testdata/blend_diff.png)   |\n\n### Convert\n\nblurry supports reading ARGB, ABGR, BGRA, YUV420 and YUV444.  \nIt also supports YUV444 output.\n\n#### Read: RGBA Color Model\n\n```go\nimg, err := blurry.ConvertFromARGB(input)\n```\n\n| ColorModel  | Method                                |\n| :---------: | :-----------------------------------: |\n| ARGB        | `blurry.ConvertFromARGB(*image.RGBA)` |\n| ABGR        | `blurry.ConvertFromABGR(*image.RGBA)` |\n| BGRA        | `blurry.ConvertFromBGRA(*image.RGBA)` |\n| RABG        | `blurry.ConvertFromRABG(*image.RGBA)` |\n\n#### Read: YUV Chroma Subsampling\n\n```go\nimg, err := blurry.ConvertFromYUV420(ycbcr)\n```\n\n| Subsampling  | Method                                   |\n| :----------: | :--------------------------------------: |\n| 420          | `blurry.ConvertFromYUV420(*image.YCbCr)` |\n| 444          | `blurry.ConvertFromYUV444(*image.YCbCr)` |\n\nor byte slice can also be specified\n\n```go\nvar y,u,v []byte\nvar strideY,strideU,strideV int\nvar width, height int\n\nimg, err := blurry.ConvertFromYUV420Plane(y, u, v, strideY, strideU, strideV, width, height)\n```\n\n| Subsampling  | Method                                                              |\n| :----------: | :-----------------------------------------------------------------: |\n| 420          | `blurry.ConvertFromYUV420Plane(y,u,v []byte, int,int,int, w,h int)` |\n| 444          | `blurry.ConvertFromYUV444Plane(y,u,v []byte, int,int,int, w,h int)` |\n\n#### Write: YUV Chroma Subsampling\n\n```go\nycbcr, err := blurry.ConvertToYUV444(rgba)\n```\n\n| Subsampling  | Method                                |\n| :----------: | :-----------------------------------: |\n| 420          | `blurry.ConvertToYUV420(*image.RGBA)` |\n| 444          | `blurry.ConvertToYUV444(*image.RGBA)` |\n\n### PCM16 Decibel\n\nGets the decibel of given PCM16.\n\n```go\nvar data []byte\ndecibel, err := blurry.PCM16Decibel(data, length)\n\nor\n\nvar input []int16\ndecibel, err := blurry.PCM16DecibelFromInt16(input)\n```\n\n## CLI usage\n\nRun it via docker.  \nUse `docker run -v` to specify where to load the images and where to output them (`/tmp` will be used as a temporary file).\n\n```shell\n$ mkdir myimagedir\n$ mkdir myimageout\n$ cp /from/img/path.png myimagedir/src.png\n\n# grayscale\n$ docker run --rm -it \\\n  -v $PWD/myimagedir:/img \\\n  -v $PWD/myimageout:/tmp \\\n  blurry:1.0.0 grayscale -i /img/src.png\n```\n\n#### Help\n\n```\nNAME:\n   blurry\n\nUSAGE:\n   blurry [global options] command [command options] [arguments...]\n\nVERSION:\n   1.20.1\n\nCOMMANDS:\n     blend             \n     blockmozaic       \n     boxblur           \n     brightness        \n     canny             \n     clone             \n     contour           \n     contrast          \n     convert           \n     convert_from_yuv  \n     convert_to_yuv    \n     crop              \n     dilation          \n     edge              \n     emboss            \n     erosion           \n     flip              \n     gamma             \n     gaussianblur      \n     gradient          \n     grayscale         \n     highpass          \n     invert            \n     laplacian         \n     morphology        \n     match_template    \n     pcm16             \n     rotate            \n     scale             \n     sobel             \n     help, h           Shows a list of commands or help for one command\n\nGLOBAL OPTIONS:\n   --debug, -d    debug mode\n   --verbose, -V  verbose. more message\n   --help, -h     show help\n   --version, -v  print the version\n```\n\n# Build\n\nWhen building, create a docker container with Halide(clang, llvm, etc).\ninstalled as the build environment.\n\n```shell\n$ make build-generator\n```\n\nCompile `libruntime.a` and all kinds `lib*_osx.a` or `lib*_linu.a` to make static link.\n\n```shell\n$ make generate\n```\n\nFinally, generate a docker image if necessary.\n\n```\n$ make build\n```\n\n# Develop\n\nSet up configuration for macos to be able to run image filtering directly through Halide.\n\n## setup Halide on local\n\n```shell\n$ make setup-halide-runtime\n```\n\n## generate and run\n\n`genrun` package allows you to export images to temporary file and run image filtering directly.\n\n```shell\n$ go run cmd/genrun/main.go benchmark\n```\n\n# License\n\nMIT, see LICENSE file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foctu0%2Fblurry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foctu0%2Fblurry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foctu0%2Fblurry/lists"}