GithubHelp home page GithubHelp logo

anthonynsimon / bild Goto Github PK

View Code? Open in Web Editor NEW
3.9K 74.0 215.0 9.06 MB

Image processing algorithms in pure Go

License: MIT License

Go 99.41% Makefile 0.35% Shell 0.24%
algorithm parallelism histogram image-processing signal-processing effects image-editing go concurrency resize

bild's People

Contributors

anthonynsimon avatar asadmshah avatar bluepsyduck avatar codacy-badger avatar crsdrw avatar defart avatar dvrkps avatar gunnsth avatar kirilldanshin avatar r2pgl avatar radarhere avatar roz3x avatar sanbornm avatar sbinet avatar yangwenmai avatar zhaojkun avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bild's Issues

Remove Black Dot

Can I remove black dot from image? Do you have any example? thanks

transform.Crop performance goes bad when rect size is small

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.

img

[bug] runtime panic when rotating some images

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?

blur.Gaussian: radius is non-standard and not commensurate with sigma

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
}

Add Scale functionality

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

Test failures on AArch64

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

Running bild with WASM

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.

From the ugly POC:
image

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.

image

Allow destruction

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.

Readme code example should mention the importance of gamma correction.

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.

Trim to edges

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!

Feature request: contours

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...

compare two histogram image

hello, I have a question: how to use your project to implement similarity comparison of two histogram images?

Morph blackhat & closing

Hi,
In your roadmap, have you taken into consideration, the morph transformation like blackhat, closing, etc ... ?

General Inquiry

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 :

  • create a blank image canvas
  • overlay a static background image over the canvas
  • add text over the canvas
  • stream the final canvas as an image and return it to clients

Does your library help accomplish this use case?

Matrix package

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.

Rotation of large images seems super slow.

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.

Switch fuzz to diff tolerance between colours

@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

Photoshop result:
ps

bild paint.FloodFill result (after switching to proposed method):
bild

[Feature]Perlin noise

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

  1. should i commit directly to master branch .
  2. is it necessary to write tests for noise functions

some of the function comment docs are out-of-date or incorrect

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

Canvas and layers feature

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:

  • Should the layers be applied in order or in reverse order?
  • How would we specify the position of the layer in respect to the other layers on the canvas?
  • Which settings for the flattening and canvas should we expose? interpolation, colorspace, BQ, etc...

But let's discuss if this would be useful in first place, and if so for which use cases :)

Flood fill

Hi, i'd like to contribute with a flood fill algorithm, would that fit within the project?

imgio.PNGEncoder() not working

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!

Feature: temperature and tint

Hello,

I would like to add these two feature. Would you find them any useful? Do you think they go well with the package?

Rotate() results in panic on some images

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!

Add Translation functionality

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

go get returns an error

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.