anthonynsimon / bild Goto Github PK
View Code? Open in Web Editor NEWImage processing algorithms in pure Go
License: MIT License
Image processing algorithms in pure Go
License: MIT License
Can I remove black dot from image? Do you have any example? thanks
my result is below.
goos: linux
goarch: amd64
pkg: test
cpu: AMD Ryzen 7 3700X 8-Core Processor
BenchmarkMyCrop-16 14307 79645 ns/op
BenchmarkResizeCrop-16 134 8771603 ns/op
my test code is below.
const size = 50
func BenchmarkMyCrop(b *testing.B) {
f, err := ioutil.ReadFile("img.png")
if err != nil {
panic(err)
}
dImage, _, err := image.Decode(bytes.NewReader(f))
if err != nil {
panic(err)
}
rect := image.Rect(0, 0, size, size)
SubImage := func (img image.Image, r image.Rectangle) image.Image {
var bgSize = image.Rect(0, 0, r.Dx(), r.Dy())
var bg = image.NewNRGBA(bgSize)
draw.Draw(bg, bg.Bounds(), img, r.Min, draw.Src)
return bg
}
for i := 0; i < b.N; i++ {
SubImage(dImage, rect)
}
}
func BenchmarkResizeCrop(b *testing.B) {
f, err := ioutil.ReadFile("img.png")
if err != nil {
panic(err)
}
dImage, _, err := image.Decode(bytes.NewReader(f))
if err != nil {
panic(err)
}
rect := image.Rect(0, 0, size, size)
for i := 0; i < b.N; i++ {
transform.Crop(dImage, rect)
}
}
my test image is below.
Hi there,
this issue might be related to #60 (coming back to this later). I'm running go1.13.7 linux/amd64 using go modules and wrote some example code (pyrox777/transform-example) to ease reproducibility. When rotating an image, represented in RGBA, with dimensions of 5535x3690 pixels (source) by 270° clockwise with ResizeBounds
set to true
, the panic is triggered. Here is the output:
~/.../pyrox777/transform-example >>> go run main.go ~/Downloads/erwan-hesry-IqB5MPcQp6k-unsplash.jpg /tmp/out.png
reading from /home/xxx/Downloads/erwan-hesry-IqB5MPcQp6k-unsplash.jpg
rotating image by 270.000000° clockwise
panic: runtime error: slice bounds out of range [:81696604] with capacity 81696600
goroutine 23 [running]:
github.com/anthonynsimon/bild/transform.Rotate.func1(0xd37, 0xe6a)
/home/xxx/go/pkg/mod/github.com/anthonynsimon/[email protected]/transform/rotate.go:111 +0x37d
github.com/anthonynsimon/bild/parallel.Line.func1(0xc000018110, 0xc000020240, 0xd37, 0xe6a)
/home/xxx/go/pkg/mod/github.com/anthonynsimon/[email protected]/parallel/parallel.go:33 +0x6a
created by github.com/anthonynsimon/bild/parallel.Line
/home/xxx/go/pkg/mod/github.com/anthonynsimon/[email protected]/parallel/parallel.go:31 +0x104
exit status 2
This is not the case when ResizeBounds
is false, but I could not point out yet if this branch is the culprit.
Additionally, as started above, I was able to reproduce the panic with the image linked in #60:
~/.../pyrox777/transform-example >>> go run main.go ~/Downloads/41zcu25h98b0rquu.jpg /tmp/out.png
reading from /home/xxx/Downloads/41zcu25h98b0rquu.jpg
rotating image by 270.000000° clockwise
panic: runtime error: slice bounds out of range [:1223044] with capacity 1223040
goroutine 8 [running]:
github.com/anthonynsimon/bild/transform.Rotate.func1(0x1b8, 0x1e0)
/home/xxx/go/pkg/mod/github.com/anthonynsimon/[email protected]/transform/rotate.go:111 +0x37d
github.com/anthonynsimon/bild/parallel.Line.func1(0xc000018120, 0xc000020360, 0x1b8, 0x1e0)
/home/xxx/go/pkg/mod/github.com/anthonynsimon/[email protected]/parallel/parallel.go:33 +0x6a
created by github.com/anthonynsimon/bild/parallel.Line
/home/xxx/go/pkg/mod/github.com/anthonynsimon/[email protected]/parallel/parallel.go:31 +0x104
exit status 2
So, thanks for this project and also having a look at this! :)
Edit: I have changed the title because the second image is not considered huge by me. But it has uneven dimensions as well (637x480). So maybe this could be a hint?
The Gaussian kernel used in blur.Gaussian
, in blur/blur.go
, is computed using a radius value which is non-standard relative to e.g., the scipy image blurring code, and doesn't map onto the sigma (standard deviation) parameter that defines a Gaussian.
The code uses:
math.Exp(-(x * x / 4 / radius))
But a standard gaussian is defined in terms of sigma, where sigma^2 goes in the denominator, and there is a 1/2 factor, not 1/4: https://en.wikipedia.org/wiki/Gaussian_blur
sigma2 := sigma * sigma
...
math.Exp(-(x * x) / 2 / sigma2))
And in the scipy implementation, you use a radius that is some multiple, default 4, of the sigma value, not sigma^2. Thus, there is no way to "square" the single radius parameter used in the current implementation with other standard implementations. It would be better to have an explicit radius multiplier, in addition to the sigma parameter.
Here's an alternative implementation (in a separate codebase, not a fork) that reproduces the scipy test results from here: https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.gaussian_filter.html (except for apparent edge / rounding issues), and splits out the kernel for independent inspection during tests. If you'd accept a PR with this, I could do that. However, this would be a breaking change, so it is not clear how best to handle that?
// scipy impl:
// https://github.com/scipy/scipy/blob/4bfc152f6ee1ca48c73c06e27f7ef021d729f496/scipy/ndimage/filters.py#L136
// #L214 has the invocation: radius = Ceil(sigma)
// bild uses:
// math.Exp(-0.5 * (x * x / (2 * radius))
// so sigma = sqrt(radius) / 2
// and radius = sigma * sigma * 2
// GaussianBlurKernel1D returns a 1D Gaussian kernel.
// Sigma is the standard deviation,
// and the radius of the kernel is 4 * sigma.
func GaussianBlurKernel1D(sigma float64) *convolution.Kernel {
sigma2 := sigma * sigma
sfactor := -0.5 / sigma2
radius := math.Ceil(4 * sigma) // truncate = 4 in scipy
length := 2*int(radius) + 1
// Create the 1-d gaussian kernel
k := convolution.NewKernel(length, 1)
for i, x := 0, -radius; i < length; i, x = i+1, x+1 {
k.Matrix[i] = math.Exp(sfactor * (x * x))
}
return k
}
// GaussianBlur returns a smoothly blurred version of the image using
// a Gaussian function. Sigma is the standard deviation of the Gaussian
// function, and a kernel of radius = 4 * Sigma is used.
func GaussianBlur(src image.Image, sigma float64) *image.RGBA {
if sigma <= 0 {
return clone.AsRGBA(src)
}
k := GaussianBlurKernel1D(sigma).Normalized()
// Perform separable convolution
options := convolution.Options{Bias: 0, Wrap: false, KeepAlpha: false}
result := convolution.Convolve(src, k, &options)
result = convolution.Convolve(result, k.Transposed(), &options)
return result
}
Apply a scale transformation that operates similar to the rotation one with regards to the viewport/canvas (i.e fill blanks, crop out-of-canvas data).
It's exceedingly useful when thinking about processing that applies steps in an automated pipeline, such as rotate -> scale -> translate -> crop.
Use case example: http://codepen.io/lloeki/pen/BzoyNJ
How can I insert a cut image using a library?
hi,
Thanks for this project. I'd like to request a feature to do lens distortions on parts of the image similar to http://www.imagemagick.org/Usage/distorts/#barrel
thanks
Hi,
I've observed a few failures in the test suite when running on AArch64:
...
=== RUN TestRotate
--- FAIL: TestRotate (0.00s)
rotate_test.go:175: Rotate angle 45.0 at center, don't preserve bounds:
expected:
Bounds: (0,0)-(5,5)
Stride: 20
0X5C, 0X5C, 0X5C, 0X87, 0X85, 0X85, 0X85, 0XF7, 0X81, 0X81, 0X81, 0XFF, 0X8C, 0X8C, 0X8C, 0XD1, 0X33, 0X33, 0X33, 0X33,
0XF0, 0XF0, 0XF0, 0XF7, 0XD3, 0XD3, 0XD3, 0XFF, 0XAD, 0XAD, 0XAD, 0XFF, 0XEF, 0XEF, 0XEF, 0XFD, 0X95, 0X95, 0X95, 0X95,
0XDF, 0XDE, 0XDE, 0XDE, 0XFD, 0XDA, 0XDA, 0XDB, 0XFC, 0XB3, 0XB3, 0XB7, 0XF6, 0XEC, 0XEC, 0XEC, 0X7E, 0X7E, 0X7E, 0X7E,
0X35, 0X2B, 0X2B, 0X2B, 0XC9, 0X6F, 0X6F, 0X6F, 0XF5, 0X7C, 0X7C, 0X7C, 0X82, 0X54, 0X54, 0X54, 0XA, 0XA, 0XA, 0XA,
0X0, 0X0, 0X0, 0X0, 0X35, 0X1B, 0X1B, 0X1B, 0X79, 0X3D, 0X3D, 0X3D, 0XA, 0X5, 0X5, 0X5, 0X0, 0X0, 0X0, 0X0,
actual:
Bounds: (0,0)-(5,5)
Stride: 20
0X57, 0X57, 0X57, 0X87, 0X7E, 0X7E, 0X7E, 0XF7, 0X81, 0X81, 0X81, 0XFF, 0X8C, 0X8C, 0X8C, 0XD1, 0X33, 0X33, 0X33, 0X33,
0XE9, 0XE9, 0XE9, 0XF7, 0XC8, 0XC8, 0XC8, 0XFF, 0XAD, 0XAD, 0XAD, 0XFF, 0XEF, 0XEF, 0XEF, 0XFD, 0X95, 0X95, 0X95, 0X95,
0XDF, 0XDE, 0XDE, 0XDE, 0XFD, 0XDA, 0XDA, 0XDB, 0XFC, 0XB3, 0XB3, 0XB7, 0XF6, 0XEC, 0XEC, 0XEC, 0X7E, 0X7E, 0X7E, 0X7E,
0X35, 0X2B, 0X2B, 0X2B, 0XC9, 0X6F, 0X6F, 0X6F, 0XF5, 0X7C, 0X7C, 0X7C, 0X82, 0X54, 0X54, 0X54, 0XA, 0XA, 0XA, 0XA,
0X0, 0X0, 0X0, 0X0, 0X35, 0X1B, 0X1B, 0X1B, 0X79, 0X3D, 0X3D, 0X3D, 0XA, 0X5, 0X5, 0X5, 0X0, 0X0, 0X0, 0X0,
=== RUN TestFlipH
--- PASS: TestFlipH (0.00s)
=== RUN TestFlipV
--- PASS: TestFlipV (0.00s)
=== RUN TestShearH
--- FAIL: TestShearH (0.01s)
shear_test.go:146: ShearH:
expected:
Bounds: (0,0)-(16,8)
Stride: 64
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X5, 0X5, 0X5, 0X5, 0X64, 0X64, 0X64, 0X64, 0XF1, 0XF1, 0XF1, 0XF1, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFA, 0XFA, 0XFA, 0XFA, 0XB1, 0XB1, 0XB1, 0XB1,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X4, 0X4, 0X4, 0X4, 0X58, 0X58, 0X58, 0X58, 0XE3, 0XE3, 0XE3, 0XE3, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XFB, 0XFB, 0XFB, 0XA8, 0XA8, 0XA8, 0XA8, 0X20, 0X20, 0X20, 0X20,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X4, 0X4, 0X4, 0X4, 0X58, 0X58, 0X58, 0X58, 0XE3, 0XE3, 0XE3, 0XE3, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XFB, 0XFB, 0XFB, 0XA8, 0XA8, 0XA8, 0XA8, 0X1C, 0X1C, 0X1C, 0X1C, 0X0, 0X0, 0X0, 0X0,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X4, 0X4, 0X4, 0X4, 0X58, 0X58, 0X58, 0X58, 0XE3, 0XE3, 0XE3, 0XE3, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XFB, 0XFB, 0XFB, 0XA8, 0XA8, 0XA8, 0XA8, 0X1C, 0X1C, 0X1C, 0X1C, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X4, 0X4, 0X4, 0X4, 0X58, 0X58, 0X58, 0X58, 0XE3, 0XE3, 0XE3, 0XE3, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XFB, 0XFB, 0XFB, 0XA8, 0XA8, 0XA8, 0XA8, 0X1C, 0X1C, 0X1C, 0X1C, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0X0, 0X0, 0X0, 0X0, 0X4, 0X4, 0X4, 0X4, 0X58, 0X58, 0X58, 0X58, 0XE3, 0XE3, 0XE3, 0XE3, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XFB, 0XFB, 0XFB, 0XA8, 0XA8, 0XA8, 0XA8, 0X1C, 0X1C, 0X1C, 0X1C, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0X5, 0X5, 0X5, 0X5, 0X58, 0X58, 0X58, 0X58, 0XE3, 0XE3, 0XE3, 0XE3, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XFB, 0XFB, 0XFB, 0XA8, 0XA8, 0XA8, 0XA8, 0X1C, 0X1C, 0X1C, 0X1C, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0X4E, 0X4E, 0X4E, 0X4E, 0XDF, 0XDF, 0XDF, 0XDF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XBB, 0XBB, 0XBB, 0XBB, 0X20, 0X20, 0X20, 0X20, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
actual:
Bounds: (0,0)-(15,8)
Stride: 60
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X8, 0X8, 0X8, 0X8, 0X8A, 0X8A, 0X8A, 0X8A, 0XFD, 0XFD, 0XFD, 0XFD, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XE2, 0XE2, 0XE2, 0XE2, 0X52, 0X52, 0X52, 0X52,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X7, 0X7, 0X7, 0X7, 0X74, 0X74, 0X74, 0X74, 0XF3, 0XF3, 0XF3, 0XF3, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XE9, 0XE9, 0XE9, 0XE9, 0X60, 0X60, 0X60, 0X60, 0X5, 0X5, 0X5, 0X5,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X6, 0X6, 0X6, 0X6, 0X6F, 0X6F, 0X6F, 0X6F, 0XF0, 0XF0, 0XF0, 0XF0, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XEB, 0XEB, 0XEB, 0XEB, 0X65, 0X65, 0X65, 0X65, 0X5, 0X5, 0X5, 0X5, 0X0, 0X0, 0X0, 0X0,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X60, 0X60, 0X60, 0X60, 0XEE, 0XEE, 0XEE, 0XEE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XF7, 0XF7, 0XF7, 0XF7, 0X70, 0X70, 0X70, 0X70, 0X6, 0X6, 0X6, 0X6, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X6, 0X6, 0X6, 0X6, 0XA5, 0XA5, 0XA5, 0XA5, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XE6, 0XE6, 0XE6, 0XE6, 0X2A, 0X2A, 0X2A, 0X2A, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0X0, 0X0, 0X0, 0X0, 0X5, 0X5, 0X5, 0X5, 0X65, 0X65, 0X65, 0X65, 0XEB, 0XEB, 0XEB, 0XEB, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XF0, 0XF0, 0XF0, 0XF0, 0X6F, 0X6F, 0X6F, 0X6F, 0X6, 0X6, 0X6, 0X6, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0X5, 0X5, 0X5, 0X5, 0X60, 0X60, 0X60, 0X60, 0XE9, 0XE9, 0XE9, 0XE9, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XF3, 0XF3, 0XF3, 0XF3, 0X74, 0X74, 0X74, 0X74, 0X7, 0X7, 0X7, 0X7, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0X52, 0X52, 0X52, 0X52, 0XE2, 0XE2, 0XE2, 0XE2, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFD, 0XFD, 0XFD, 0XFD, 0X8A, 0X8A, 0X8A, 0X8A, 0X8, 0X8, 0X8, 0X8, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
=== RUN TestShearV
--- FAIL: TestShearV (0.03s)
shear_test.go:298: ShearH:
expected:
Bounds: (0,0)-(8,16)
Stride: 32
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X5, 0X5, 0X5, 0X5, 0X4E, 0X4E, 0X4E, 0X4E,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X4, 0X4, 0X4, 0X4, 0X58, 0X58, 0X58, 0X58, 0XDF, 0XDF, 0XDF, 0XDF,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X4, 0X4, 0X4, 0X4, 0X58, 0X58, 0X58, 0X58, 0XE3, 0XE3, 0XE3, 0XE3, 0XFF, 0XFF, 0XFF, 0XFF,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X4, 0X4, 0X4, 0X4, 0X58, 0X58, 0X58, 0X58, 0XE3, 0XE3, 0XE3, 0XE3, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X4, 0X4, 0X4, 0X4, 0X58, 0X58, 0X58, 0X58, 0XE3, 0XE3, 0XE3, 0XE3, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
0X0, 0X0, 0X0, 0X0, 0X4, 0X4, 0X4, 0X4, 0X58, 0X58, 0X58, 0X58, 0XE3, 0XE3, 0XE3, 0XE3, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
0X5, 0X5, 0X5, 0X5, 0X58, 0X58, 0X58, 0X58, 0XE3, 0XE3, 0XE3, 0XE3, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
0X64, 0X64, 0X64, 0X64, 0XE3, 0XE3, 0XE3, 0XE3, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
0XF1, 0XF1, 0XF1, 0XF1, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XFB, 0XFB, 0XFB, 0XBB, 0XBB, 0XBB, 0XBB,
0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XFB, 0XFB, 0XFB, 0XA8, 0XA8, 0XA8, 0XA8, 0X20, 0X20, 0X20, 0X20,
0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XFB, 0XFB, 0XFB, 0XA8, 0XA8, 0XA8, 0XA8, 0X1C, 0X1C, 0X1C, 0X1C, 0X0, 0X0, 0X0, 0X0,
0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XFB, 0XFB, 0XFB, 0XA8, 0XA8, 0XA8, 0XA8, 0X1C, 0X1C, 0X1C, 0X1C, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XFB, 0XFB, 0XFB, 0XA8, 0XA8, 0XA8, 0XA8, 0X1C, 0X1C, 0X1C, 0X1C, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0XFF, 0XFF, 0XFF, 0XFF, 0XFB, 0XFB, 0XFB, 0XFB, 0XA8, 0XA8, 0XA8, 0XA8, 0X1C, 0X1C, 0X1C, 0X1C, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0XFB, 0XFB, 0XFB, 0XFB, 0XA8, 0XA8, 0XA8, 0XA8, 0X1C, 0X1C, 0X1C, 0X1C, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0XB1, 0XB1, 0XB1, 0XB1, 0X20, 0X20, 0X20, 0X20, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
actual:
Bounds: (0,0)-(8,15)
Stride: 32
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X5, 0X5, 0X5, 0X5, 0X52, 0X52, 0X52, 0X52,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X5, 0X5, 0X5, 0X5, 0X60, 0X60, 0X60, 0X60, 0XE3, 0XE3, 0XE3, 0XE3,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X6, 0X6, 0X6, 0X6, 0X65, 0X65, 0X65, 0X65, 0XE9, 0XE9, 0XE9, 0XE9, 0XFF, 0XFF, 0XFF, 0XFF,
0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X6, 0X6, 0X6, 0X6, 0X60, 0X60, 0X60, 0X60, 0XA5, 0XA5, 0XA5, 0XA5, 0XEB, 0XEB, 0XEB, 0XEB, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
0X0, 0X0, 0X0, 0X0, 0X7, 0X7, 0X7, 0X7, 0X6F, 0X6F, 0X6F, 0X6F, 0XEE, 0XEE, 0XEE, 0XEE, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
0X8, 0X8, 0X8, 0X8, 0X74, 0X74, 0X74, 0X74, 0XF0, 0XF0, 0XF0, 0XF0, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
0X8A, 0X8A, 0X8A, 0X8A, 0XF3, 0XF3, 0XF3, 0XF3, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF,
0XFD, 0XFD, 0XFD, 0XFD, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFD, 0XFD, 0XFD, 0XFD,
0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XF3, 0XF3, 0XF3, 0XF3, 0X8A, 0X8A, 0X8A, 0X8A,
0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XF0, 0XF0, 0XF0, 0XF0, 0X74, 0X74, 0X74, 0X74, 0X8, 0X8, 0X8, 0X8,
0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XF7, 0XF7, 0XF7, 0XF7, 0XE6, 0XE6, 0XE6, 0XE6, 0X6F, 0X6F, 0X6F, 0X6F, 0X6, 0X6, 0X6, 0X6, 0X0, 0X0, 0X0, 0X0,
0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XEB, 0XEB, 0XEB, 0XEB, 0X70, 0X70, 0X70, 0X70, 0X2A, 0X2A, 0X2A, 0X2A, 0X6, 0X6, 0X6, 0X6, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0XFF, 0XFF, 0XFF, 0XFF, 0XE9, 0XE9, 0XE9, 0XE9, 0X65, 0X65, 0X65, 0X65, 0X5, 0X5, 0X5, 0X5, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0XE3, 0XE3, 0XE3, 0XE3, 0X60, 0X60, 0X60, 0X60, 0X5, 0X5, 0X5, 0X5, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
0X52, 0X52, 0X52, 0X52, 0X5, 0X5, 0X5, 0X5, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0, 0X0,
=== RUN TestTranslate
--- PASS: TestTranslate (0.00s)
FAIL
FAIL github.com/anthonynsimon/bild/transform 0.085s
=== RUN TestRGBToHSV
--- PASS: TestRGBToHSV (0.00s)
...
I wonder if this is related to this issue:
https://github.com/fogleman/gg/issues/79
Hello;
First off, I would like to say that bild has been a pleasure to develop with. I have been preparing a demo of WebAssembly using Go (basically running Go in the browser via WebAssembly, or GoWasm) and as a proof of concept, we compiled bild to wasm to perform image manipulation in the browser. It has been working fantastically. (browser manipluated image of our mascot below)
This issue is half positive feedback, but also half issue report. In our proof of concept, we load an image and have 12 buttons that invoke 12 different bild image transforms. All of them run without issue and can be run repeatedly.... except for shearh and shearv. We can run those 4 to 5 times and then the heap gets full and we get memory allocation errors. The invocation of shear-x operations are identical in flow as all the other operations, but none of the others exhaust the heap.
So I was wondering if there was anything special about shear operations that might cause this. Definitely seems like there's a memory leak there.
Thanks again for your great library.
Is there any way, I can have the above functionality using this library
Resizing interpolation should be configurable.
What do you think about adding the possibility to allow original image destruction in spite of using clone.AsRGBA() ?
It can result in better performance.
Gamma correction is among the things most often done wrong by graphics programming novices. It's almost as bad as missing scene-related color transforms and linear volume sliders in the average video game. The code example in the readme should definitely mention to adjust.Gamma(img, 1/2.2)
before doing any color mixing and adjust.Gamma(img, 2.2)
before saving back to file (for as long as bild does not implicitly handle this, anyway) and link to some recommended reading.
Does bild support for draw now? Strongly recommend add drawing module such as draw a simple rectangle on image.
The Unsharp
filter is a standard tool to enhance images. This is very helpful with OCR.
https://en.wikipedia.org/wiki/Unsharp_masking#Digital_unsharp_masking
Hi!
Thanks for this amazing library!
I saw that effect
pkg support both Sobel and EdgeDetection.
It is possible to use one of them to trim to the edges?
Basically I have an image, I want to find the edges and trim the images close to its borders.
Thanks so much!
any chance to add an half-tone filter to produce images like :
I'm currently looking to see how to compute such images and may give it a try, but maybe you'll be faster than me to add it ?
https://en.wikipedia.org/wiki/Dither
Thanks
It's very commonly needed for image processing. We can get edges in several ways, but no contours, nor their bounding boxes that I can see...
hello, I have a question: how to use your project to implement similarity comparison of two histogram images?
Is it possible to take a square or rectangle image and crop it to a circle with this library?
Hi,
In your roadmap, have you taken into consideration, the morph transformation like blackhat, closing, etc ... ?
Hello, I'm looking for a library that would help me build an image manipulation service in Go.
A common use case of the service is :
Does your library help accomplish this use case?
Right now all treatment of matrices is via the image.Image interface and frequently a utility function is used to convert the image.Image to an RGBA image.
Would it be useful to have an internal matrix type? The matrix could be created from an Image instance. Mathematial matrix operations could be applied to it. Matrix multiplication, Scalar multiplication, etc.
That could be very powerful for other image processing operations. Having used Matlab, Octave quite a bit in the past, I could see that this could allow some very powerful use.
For instance, being able to apply transformation matrices to images by simple matrix multiplication can be easy to use and powerful with many use cases.
I was just trying a basic example:
package main
import (
"github.com/anthonynsimon/bild/imgio"
"github.com/anthonynsimon/bild/transform"
)
func main() {
img, err := imgio.Open("PW2_8123.JPG")
if err != nil {
panic(err)
}
rotated := transform.Rotate(img, 90, nil)
if err := imgio.Save("filename", rotated, imgio.PNG); err != nil {
panic(err)
}
}
And it took super long:
$ time ./main
real 0m26.787s
user 0m41.122s
sys 0m0.958s
The image is a 10mb photo.
@defart would it make sense to switch from fuzz (distance based) to color difference tolerance?
This way setting the tolerance would allow the algorithm to fill pixels by similarity instead of by distance from point. So for example if tolerance is set to 12 (uint8 range 0...255), then all colours that are within a diff of +-12 will be matched.
After some quick research it seems like most photo editing software, including Photoshop, use a version of this setting.
I created a branch with the proposal, check it out here
bild paint.FloodFill result (after switching to proposed method):
I have added few files in my local repo , that enables noise package to give images with coherent noise .Yes , using parallel implementation , like as of other noise functions . I wanted to know about
Here's a few I noticed.
imgio/io.go:
// Open loads and decodes an image from a file and returns it.
//
// Usage example:
// // Encode an image to a writer in PNG format,
// // returns an error if something went wrong
// img, err := Open("exampleName")
func Open(filename string) (image.Image, error) {
that comment describes Save, not Open..
transform/resize.go:
// Resize returns a new image with its size adjusted to the new width and height. The filter
// param corresponds to the Resampling Filter to be used when interpolating between the sample points.
//
//
// Usage example:
//
// result := bild.Resize(img, 800, 600, bild.Linear)
//
func Resize(img image.Image, width, height int, filter ResampleFilter) *image.RGBA {
usage should be s/bild/transform/g
transform/rotate.go:
// Rotate returns a rotated image by the provided angle using the pivot as an anchor.
// Parameters angle is in degrees and it's applied clockwise.
// Default parameters are used if a nil *RotationOptions is passed.
//
// Usage example:
//
// // Rotate 90.0 degrees clockwise, preserving the image size and the pivot point at the top left corner
// result := bild.Rotate(img, 90.0, &bild.RotationOptions{PreserveSize: true, Pivot: &image.Point{0, 0}})
//
func Rotate(img image.Image, angle float64, options *RotationOptions) *image.RGBA {
same as above, and options now is ResizeBounds not PreserveSize
Would it be useful to have the functionality to layer changes on top of a canvas? Something like what most visual image editors do.
For example:
result := layer.Flatten(
layer.Canvas(width, height, backgroundColor),
layer.Layer(image, blendMode, opacity),
...
)
Or more concrete:
result := layer.Flatten(
layer.Canvas(1280, 720, bg.Black),
layer.Layer(img1, blend.Normal, 1.0),
layer.Layer(blur.Gaussian(img1, 0.1), blend.Multiply, 0.5),
layer.Layer(effect.Sharpen(img2), blend.SoftLight, 0.25),
)
This would require thinking about how to handle things like:
But let's discuss if this would be useful in first place, and if so for which use cases :)
We would benefit from using this awesome library if it had perspective transform support (i.e. homogeneous matrix transform).
Similar to: https://docs.opencv.org/4.x/da/d54/group__imgproc__transform.html#gaf73673a7e8e18ec6963e3774e6a94b87
The current implementation uses 0.3R + 0.6G + 0.1B as the heuristic which produces choppy results on certain images. I've found that 0.299R + 0.587G + 0.114B produces much better results. There should be a way to set this heuristic.
Hi, i'd like to contribute with a flood fill algorithm, would that fit within the project?
https://github.com/anthonynsimon/bild/blob/master/imgio/io.go
io github.com/anthonynsimon/bild/imgio
is missing a webp function
The imgio.Encode()
function uses a hard coded jpg quality value of 95 when saving an image. This value should be configurable.
Sorry, I don't understand the method clearly. I want to know which method or module is need for my requirement. Who can help me?
After using go get github.com/anthonynsimon/bild
(go mod file shows it getting v0.10.0) and pasting the readme example, VSCode shows that imgio.PNGEncoder()
doesn't exist. After looking into the /pkg/mod/github.com/anthonynsimon/[email protected]/imgio/io.go file, I only have the Open, Encode, Save
functions. I'm running go 1.13, currently on a Windows 10 host.
I had to change the line: imgio.Save("output.png", rotated, imgio.PNGEncoder())
to imgio.Save("output.png", rotated, imgio.PNG)
Not sure if there's a problem with the copy served to me, or the README file is out of date, but would love some clarification if possible. Thanks!
Hello,
I would like to add these two feature. Would you find them any useful? Do you think they go well with the package?
I've encountered some images for which the Rotate() function results in:
runtime error: slice bounds out of range
The error seems to be happening on rotate.go:111:
copy(dst.Pix[dstPos:dstPos+4], src.Pix[srcPos:srcPos+4])
An image that can reproduce the error: https://static.thumbtackstatic.com/pictures/61/41zcu25h98b0rquu.jpg
FWIW, opening that image in an editor (e.g. Preview on mac) and simply re-saving it seems to resolve the issue. Unsure what to make of that.
Please let me know if I can provide any more info!
Apply a translation transformation that operates similar to the rotation one with regards to the viewport/canvas (i.e fill blanks, crop out-of-canvas data).
It's exceedingly useful when thinking about processing that applies steps in an automated pipeline, such as rotate -> zoom -> translate -> crop.
Use case example: http://codepen.io/lloeki/pen/BzoyNJ
Doing go get returns the error:
can't load package: package github.com/anthonynsimon/bild: no buildable Go source files in $GOPATH/src/github.com/anthonynsimon/bild
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.