{"id":36656880,"url":"https://github.com/mandykoh/convolver","last_synced_at":"2026-01-12T10:20:51.766Z","repository":{"id":57537157,"uuid":"281842901","full_name":"mandykoh/convolver","owner":"mandykoh","description":"Extended parallel image convolution library for Go","archived":false,"fork":false,"pushed_at":"2020-08-18T22:09:03.000Z","size":6699,"stargazers_count":43,"open_issues_count":1,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-06-20T08:05:29.580Z","etag":null,"topics":["image-processing"],"latest_commit_sha":null,"homepage":"","language":"Go","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/mandykoh.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}},"created_at":"2020-07-23T03:41:15.000Z","updated_at":"2023-01-27T02:46:51.000Z","dependencies_parsed_at":"2022-09-04T13:50:18.652Z","dependency_job_id":null,"html_url":"https://github.com/mandykoh/convolver","commit_stats":null,"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/mandykoh/convolver","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandykoh%2Fconvolver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandykoh%2Fconvolver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandykoh%2Fconvolver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandykoh%2Fconvolver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mandykoh","download_url":"https://codeload.github.com/mandykoh/convolver/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandykoh%2Fconvolver/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28338166,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T06:09:07.588Z","status":"ssl_error","status_checked_at":"2026-01-12T06:05:18.301Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["image-processing"],"created_at":"2026-01-12T10:20:48.484Z","updated_at":"2026-01-12T10:20:51.755Z","avatar_url":"https://github.com/mandykoh.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# convolver\n\n![Convolver title](doc-images/title.png)\n\n[![PkgGoDev](https://pkg.go.dev/badge/github.com/mandykoh/convolver)](https://pkg.go.dev/github.com/mandykoh/convolver)\n[![Go Report Card](https://goreportcard.com/badge/github.com/mandykoh/convolver)](https://goreportcard.com/report/github.com/mandykoh/convolver)\n[![Build Status](https://travis-ci.org/mandykoh/convolver.svg?branch=main)](https://travis-ci.org/mandykoh/convolver)\n\n`convolver` is an image convolution library which extends classical convolution with aggregation operators beyond weighted averaging. This allows for the expression of more image processing operations. The convolution kernels also allow specifying values separately for R, G, B, and alpha channels so that per-channel operations can be supported.\n\nConvolution operations support parallel processing out of the box, allowing the degree of parallelism to be specified for mostly-linear acceleration on multi-core systems.\n\n`convolver` currently assumes that image data is sRGB encoded.\n\nSee the [API documentation](https://pkg.go.dev/github.com/mandykoh/convolver) for more details.\n\nThis software is made available under an [MIT license](LICENSE).\n\n\n## Example usage\n\nConvolution starts with defining a kernel. A kernel has a “radius” which defines the size of a rectangular patch in pixels. For example, for any given pixel, a kernel of radius 2 extends 2 pixels away in all four directions, for a total patch size of 5x5: \n\n```go\nkernel := convolver.KernelWithRadius(2)\n```\n\nThe above creates an empty 5x5 kernel, where all weights are zero. When applied to an image, each output pixel is the result of some aggregation of the pixels covered by the kernel, centred on the corresponding input pixel. The weights dictate how much each of those pixels contribute to the aggregated result. Weights are specified as floats, and may be specified separately for R, G, B, and alpha channels.\n\n\n### Channel extraction\n\nUsing the weights, we can define a kernel to extract individual colour channels. The following specifies a trivial kernel of radius 0 (meaning it only covers one pixel without consideration of the pixel’s neighbours) where the output is entirely influenced by the blue and alpha channels (weight 1) and where the red and green channels have no influence (weight 0). Because the kernel is 1x1, there is only one set of weights at the x(0),y(0) position.\n\n```go\nkernel := convolver.KernelWithRadius(0)\nx, y, r, g, b, a := 0, 0, 0.0, 0.0, 1.0, 1.0\nkernel.SetWeightRGBA(x, y, r, g, b, a)\n```\n\nOnce defined, a kernel can be applied using a given aggregation function (here, averaging, although it doesn’t really matter for a 1x1 kernel):\n\n```go\nresultImg := kernel.ApplyAvg(inputImg, parallelism)\n```\n\nThe `parallelism` parameter allows a kernel to be applied using parallel processing to take advantage of multiple CPU cores. Setting this to 1 means kernel processing is single threaded; setting it to 4 means the processing will be spread across four threads.\n\nThe result of extracting only the blue and alpha channels looks like this:\n\n![Example of blue and alpha channels extracted from image of an avocado](doc-images/example-colour-extract-1.png)\n\n\n### Gaussian blur\n\nThe following specifies a 5x5 kernel that expresses a Gaussian blur by using the `SetWeightsUniform` method, using a single uniform weight for each of the R, G, B, and alpha channels:\n\n```go\nweights := []float32{\n    1, 4, 6, 4, 1,\n    4, 16, 24, 16, 4,\n    6, 24, 36, 24, 6,\n    4, 16, 24, 16, 4,\n    1, 4, 6, 4, 1,\n}\n\nkernel := convolver.KernelWithRadius(2)\nkernel.SetWeightsUniform(weights)\n```\n\nThis kernel can be applied to an image with averaging as the aggregation operator like this:\n\n```go\nresultImg := kernel.ApplyAvg(inputImg, parallelism)\n```\n\nThe result looks like this:\n\n![Example of applying a Gaussian blur to an image of an avocado](doc-images/example-gaussian-blur-1.png)\n\nNotice that details of the original image have been softened by the blur.\n\nThe operations expressed by many kernels can be emphasised in effect by iteratively applying the kernel. For example, we could continue to apply the Gaussian blur kernel another seven times:\n\n```go\nfor i := 0; i \u003c 7; i++ {\n    resultImg = kernel.ApplyAvg(resultImg, parallelism)\n}\n```\n\nThe resulting eight passes would then look like this:\n\n![Example of iteratively applying a Gaussian blur eight times to an image of an avocado](doc-images/example-gaussian-blur-8.png)\n\n\n### Sharpening\n\nA simple sharpening kernel can be expressed like this. The weights emphasise contrast between a pixel and its four neighbours:\n\n```go\nweights := []float32{\n    0, -1, 0,\n    -1, 5, -1,\n    0, -1, 0,\n}\n\nkernel := convolver.KernelWithRadius(1)\nkernel.SetWeightsUniform(weights)\n```\n\nApplying this kernel (still using averaging) can be done in the same way as before:\n\n```go\nresultImg := kernel.ApplyAvg(inputImg, parallelism)\n```\n\nAnd the result looks like this:\n\n![Example of applying a sharpen filter to an image of an avocado](doc-images/example-sharpen-1.png)\n\n\n### Edge detection\n\nAn edge detection kernel might look like this. Note that—unlike sharpening—the weights around the edges sum to zero with the weight in the centre, which means that in areas without a contrasting edge, the output will be zero:\n\n```go\nweights := []float32{\n    -1, -1, -1,\n    -1, 8, -1,\n    -1, -1, -1,\n}\n\nkernel := convolver.KernelWithRadius(1)\nkernel.SetWeightsUniform(weights)\n```\n\nWhen applied:\n\n```go\nresultImg := kernel.ApplyAvg(inputImg, parallelism)\n```\n\nThe result looks like this:\n\n![Example of applying an edge detection filter to an image of an avocado](doc-images/example-edge-detect-1.png)\n\n\n### Dilation\n\nConvolution can also be performed using aggregation functions other than a weighted average.\n\nFor example, we can define a simple, uniformly weighted 5x5 “circle” for a kernel:\n\n```go\nweights := []float32{\n    0, 1, 1, 1, 0,\n    1, 1, 1, 1, 1,\n    1, 1, 1, 1, 1,\n    1, 1, 1, 1, 1,\n    0, 1, 1, 1, 0,\n}\n\nkernel := convolver.KernelWithRadius(2)\nkernel.SetWeightsUniform(weights)\n```\n\nHowever, instead of applying this using the `Avg` operator (which would yield something like a simple blur), we can apply it using a `Max` operator:\n\n```go\nresultImg := kernel.ApplyMax(inputImg, parallelism)\n```\n\nThe `Max` operator aggregates the pixels covered by the kernel and produces the maximum value for each channel. This means that transparent pixels (zero alpha) which are near opaque pixels (full alpha) as dictated by the coverage of the kernel will also become opaque. As always, weights of zero indicate that those pixels have no influence on the result.\n\nThe resulting image will be _dilated_ and thickened up, and looks like this:\n\n![Example of applying a dilation filter to an image of the word Convolver](doc-images/example-dilate-1.png)\n\nOf course, this kernel can also be applied in multiple passes. This is the result after applying a second pass (notice the increase in thickness over one pass):\n\n![Example of iteratively applying a dilation filter twice to an image of the word Convolver](doc-images/example-dilate-2.png)\n\n\n### Erosion\n\nAnother aggregation operator is `Min`. Where `Max` finds the maximum values covered by the kernel, `Min` finds the minimum. Using exactly the same kernel as with _Dilation_ above, we can apply a `Min` aggregation instead:\n\n```go\nresultImg := kernel.ApplyMin(inputImg, parallelism)\n```\n\nThis produces an _eroded_ effect, where the features of the original image are thinned down, and looks like this:\n\n![Example of applying an erosion filter to an image of the word Convolver](doc-images/example-erode-1.png)\n\nAnd again, additional applications of the kernel will emphasise the effect. This is the result after applying a second pass:\n\n![Example of iteratively applying an erosion filter twice to an image of the word Convolver](doc-images/example-erode-2.png)\n\n\n### Closing\n\nMore sophisticated operations can be produced by combining convolutions. For example, by performing a _dilation_, and following up with an _erosion_, we can produce a _closing_ effect:\n\n```go\nresultImg := kernel.ApplyMax(inputImg, parallelism)\nresultImg = kernel.ApplyMin(resultImg, parallelism)\n```\n\nThis has the effect of smoothing over sharp points, rounding off corners, and closing holes, and is useful for producing smooth “islands” in an image.\n\nWe can also iterate this operation to strengthen the effect, performing the dilation twice and then the erosion twice:\n\n```go\nresultImg := kernel.ApplyMax(inputImg, parallelism)\nresultImg = kernel.ApplyMax(resultImg, parallelism)\nresultImg = kernel.ApplyMin(resultImg, parallelism)\nresultImg = kernel.ApplyMin(resultImg, parallelism)\n```\n\nThis produces the following result:\n\n![Example of applying a two-pass closing filter to an image of the word Convolver](doc-images/example-close-2.png)\n\nNote the rounding of the sharp corners in the letters C, N, and V.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmandykoh%2Fconvolver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmandykoh%2Fconvolver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmandykoh%2Fconvolver/lists"}