Giter Club home page Giter Club logo

jimagehash's Introduction

JImageHash

Travis GitHub license Codacy Badge

JImageHash is a performant perceptual image fingerprinting library entirely written in Java. The library returns a similarity score aiming to identify entities which are likely modifications of the original source while being robust various attack vectors ie. color, rotation and scale transformation.

A perceptual hash is a fingerprint of a multimedia file derived from various features from its content. Unlike cryptographic hash functions which rely on the avalanche effect of small changes in input leading to drastic changes in the output, perceptual hashes are "close" to one another if the features are similar.

This library was inspired by Dr. Neal Krawetz blog post "kind of like that" and incorporates several improvements. A comprehensive overview of perceptual image hashing can be found in this paper by Christoph Zauner.

Maven

The project is hosted on maven central

<dependency>
	<groupId>dev.brachtendorf</groupId>
	<artifactId>JImageHash</artifactId>
	<version>1.0.0</version>
</dependency>

<!-- If you want to use the database image matcher you need to add h2 as well -->
<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
	<version>1.4.200</version>
</dependency>

Breaking Changes: migration guide to version 1.0.0

Please be aware that migrating from one major version to another usually invalidates created hashes in order to retain validity when persistently storing the hashes. The algorithm id of hashes is adjusted in order for the jvm to throw an error if the possibility exist that hashes generated for the same input image are not consistent throughout the compared versions.

Hashes generated with the following 2 algorithm have to be regenerated:

  • RotPAverage hash was fixed to correctly return hashes when the algorithm is used multiple times.
  • KernelAverageHash algorithm id changed due to JVMs internal hashcode calculation and the package name update. Hashes generated with this algorithm have to be regenerated.

The package is now published to maven central under a new group id. The internal package structure has been adjusted from com.github.kilianB to dev.brachtendorf.jimagehash. Adjust your imports accordingly.

Hello World

File img0 = new File("path/to/file.png");
File img1 = new File("path/to/secondFile.jpg");

HashingAlgorithm hasher = new PerceptiveHash(32);

Hash hash0 = hasher.hash(img0);
Hash hash1 = hasher.hash(img1);

double similarityScore = hash0.normalizedHammingDistance(hash1);

if(similarityScore < .2) {
    //Considered a duplicate in this particular case
}

//Chaining multiple matcher for single image comparison

SingleImageMatcher matcher = new SingleImageMatcher();
matcher.addHashingAlgorithm(new AverageHash(64),.3);
matcher.addHashingAlgorithm(new PerceptiveHash(32),.2);

if(matcher.checkSimilarity(img0,img1)) {
    //Considered a duplicate in this particular case
}

Examples

Examples and convenience methods can be found in the examples repository

Transparent image support

Support for transparent images has to be enabled specifically due to backwards compatibility and force users of the libraries to understand the implication of this setting.

The setOpaqueHandling(Color? replacementColor, int alphaThreshold) will replace transparent pixels with the specified color before calculating the hash.

Be aware of the following culprits:

  • the replacement color must be consistent throughout hash calculation for the entire sample space to ensure robustness against color transformations of the images.
  • the replacement color should be a color that does not appear often in the input space to avoid masking out available information.
  • when not specified Orange will be used as replacement. This choice was arbitrary and ideally, a default color should be chosen which results in 0 and 1 bits being computed in 50% of the time in respect to all other pixels and hashing algorithms.
  • supplying a replacement value of null will attempt to either use black or white as a replacement color conflicting with the advice given above. Computing the contrast color will fail if the transparent area of an image covers a large space and comes with a steep performance penalty.
HashingAlgorithm hasher = new PerceptiveHash(32);

//Replace all pixels with alpha values smaller than 0-255. The alpha value cutoff is taken into account after down scaling the image, therefore choose a reasonable value.  
int alphaThreshold = 253;
hasher.setOpaqueHandling(alphaThreshold)

Multiple types image matchers are available for each situation

The persistent package allows hashes and matchers to be saved to disk. In turn the images are not kept in memory and are only referenced by file path allowing to handle a great deal of images at the same time. The cached version keeps the BufferedImage image objects in memory allowing to change hashing algorithms on the fly and a direct retrieval of the buffered image objects of matching images. The categorize package contains image clustering matchers. KMeans and Categorical as well as weighted matchers. The exotic package features BloomFilter, and the SingleImageMatcher used to match 2 images without any fancy additions.

Image High Low Copyright Thumbnail Ballon
High Quality

Low Quality

Altered Copyright

Thumbnail

Ballon

Hashing algorithm

Image matchers can be configured using different algorithm. Each comes with individual properties

Algorithm FeatureNotes
AverageHash Average Luminosity Fast and good all purpose algorithm
AverageColorHash Average Color Version 1.x.x AHash. Usually worse off than AverageHash. Not robust against color changes
DifferenceHash Gradient/Edge detection A bit more robust against hue/sat changes compared to AColorHash
Wavelet Hash Frequency & Location Feature extracting by applying haar wavlets multiple times to the input image. Detection quality better than inbetween aHash and pHash.
PerceptiveHash Frequency Hash based on Discrete Cosine Transformation. Smaller hash distribution but best accuracy / bitResolution.
MedianHash Median Luminosity Identical to AHash but takes the median value into account. A bit better to detect watermarks but worse at scale transformation
AverageKernelHash Average luminosity Same as AHash with kernel preprocessing. So far usually performs worse, but testing is not done yet.
Rotational Invariant
RotAverageHash Average Luminosity Rotational robust version of AHash. Performs well but performance scales disastrous with higher bit resolutions . Conceptual issue: pixels further away from the center are weightend less.
RotPHash Frequency Rotational invariant version of pHash using ring partition to map pixels in a circular fashion. Lower complexity for high bit sizes but due to sorting pixel values usually maps to a lower normalized distance. Usually bit res of >= 64bits are preferable
Experimental. Hashes available but not well tuned and subject to changes
HogHash Angular Gradient based (detection of shapes?) A hashing algorithm based on hog feature detection which extracts gradients and pools them by angles. Usually used in support vector machine/NNs human outline detection. It's not entirely set how the feature vectors should be encoded. Currently average, but not great results, expensive to compute and requires a rather high bit resolution

Version 3.0.0 Image clustering

Image clustering with fuzzy hashes allowing to represent hashes with probability bits instead of simple 0's and 1's

1_fxpw79yoon8xo3slqsvmta

Algorithm benchmarking

See the wiki page on how to test different hashing algorithms with your set of images Code available at the example repo: https://github.com/KilianB/JImageHash-Examples/tree/main/src/main/java/com/github/kilianB/benchmark

jimagehash's People

Contributors

kilianb 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

jimagehash's Issues

Support fuzzy hashes in conjunction with image classification and clustering

With 3.0.0 a matcher will be introduced which clusters hashes into similarity groups allowing to perform further matching based on the overall structure of the category.

The resulting cluster is mapped to a centroid and possibly an adapted (kd tree?). The hashes describing the clusters now are not entirely 0 or 1 but a value in between indicating the uncertainty of a specific bit in the hash.

Sign bit and hash legnth

Hi,

I'm trying to understand the significance of this particular line. It seems that the final result, represented by BigInteger, is initialized by BigInteger.ONE just for the sign of the final value.
We're trying to generate a 64-bit hash value and then store it as a long. Unfortunately, the final bit size of this -> 'new PerceptiveHash(64)', is 65 bits.
Ignoring the sign bit, by calling 'getHashValue().longValue()' produces different accuracy results for the same two image.

Am I missing something? Or was this the intended behavior?

Thanks!

Can hog feature descriptor be used to create an efficient hash?

The hog feature descriptor pools gradient vectors based on their unsigned direction. It is successfully used in pedestrian detection.

So far a derived descriptor based on https://lear.inrialpes.fr/people/triggs/pubs/Dalal-cvpr05.pdf is implemented but we are still left with way to many numbers to encode them into a short hash.

hogtest

Images to compare normalized hamming distance
Similar images
HQ - HQ: 0.000
HQ - LQ: 0.292
HQ - Copy: 0.119
HQ - Thumb0.422
LQ - Copy0.319
LQ - Thumb0.396
Copy - Thumb0.424
Unlike Images
HQ - Ballon: 0.496
HQ - Lena: 0.491
LQ - Ballon0.484
LQ - Lena0.483
Copy - Ballon0.491
Copy - Lena0.493
Thumb - Ballon0.506
Thumb - Lena0.481

While similar images can be differentiated from unlike images it's rather expensive, the hash is long. A todo on figuring out if the approach can be tweaked to produce usable results.

License?

This looks like an interesting project, but a license would be nice.

Support for transparent images

I'm having a unusual problem in my project where I'm getting the same hash to two different images. Those are the mentioned images:
citroen
mini
The project is simply using the hash(BufferedImage image) method from the API and I'm not sure if there are different approaches to do that, but is there any possible solution to this problem? Thanks in advance!

Synk reports vulnerability for h2 dependency

According to Synk a critical vulnerability for h2 exists: https://snyk.io/vuln/SNYK-JAVA-COMH2DATABASE-31685?utm_medium=Partner&utm_source=RedHat&utm_campaign=Code-Ready-Analytics-2020&utm_content=vuln/SNYK-JAVA-COMH2DATABASE-31685

Please see the issue ticket in the original repository here as well as the developers comment: h2database/h2database#3012

TLDR: The default configuration prevents a RCE, the library is not used in such a capability in JImage hash and is only an optional dependency. No patch version from h2 is and will be made available. The report is a false positive and can be ignored if you do not manually open up the h2 to the web and alter the settings manually.

Comparing different size image

How do we manage to utilize the ImageHashing when the image sizes are different? What would the result when we try to compare the same image of different sizes? If we can implement it, which algorithm do I need to utilize?

Rethink image matcher interface

We deal with configured image matchers that have a float value associated when adding algorithms (Single Image Matcher , Database Image matcher) and matchers that do not have a preset in the same sense (cumulative image matcher and random forest matchers).

Maybe it's time to refactor the image matchers and introduce a new abstract class in between the interface and the implementations.

also move from float threshold to double precision, This will be yet another breaking change. Bump version to 3.0.0

#16 should be resolved in the same patch if major version is bumped.

Logging

Can you remove this log message or at least set it to debug level instead of info? It's clogging up the log files when we process lots of images. Is there actually any action that we can take when a BufferedImage has an unrecognized type?

"com.github.kilianB.graphics.FastPixel create
INFO: No fast implementation available for 13. Fallback to slow default variant."

Allow even size filter kernels

Currently only odd sized kernels are allowed e.g.

[1 0 1
 0 1 0 
 1 0 2]

If a kernel is evenly sized the computed pixel falls between 2 "buckets". The intermediary value has to be computed.

3.0.0 conflicts with Spring Boot 2.1.1 Release

When adopting 3.0.0 release on a SPRING BOOT 2.1.1 RELEASE based project, it failed during web container start up with an error of - " org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultValidator' defined in class path resource [org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.class]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager
". It seemed like a conflict with hibernate validator while I have no idea why JImageHash would have any side affect of hibernate validator.

When I switched JImageHash version from 3.0.0 to 2.1.1, it all passed. Is it because JImageHash version aligns with SPRING BOOT version?

Thanks.

Hash class to implement Compareable

Hey,

I use a HashMap object to store key, value pairs where the Hash object of each photo is used as a key.
I tried switching to TreeMap object as it provides automatic sorting of the entries it stores, but because the Hash class does not implements Compareable, I cant use Hash as key anymore and I have to workaround using BigInteger (using the getHashValue) or converting the Hash to string object.

If possible, I would like Hash class to implement Compareable so it can be used directly in a TreeMap.

Unsupported Image Formats

Hi,

I'm facing an issue with about ~4% of the images I'm trying to generate a hash value for are not supported.
The majority of the errors I get are 'UnsupportedOperationException'. I get either:
java.lang.UnsupportedOperationException: The image type is currently not supported: 10
at com.github.kilianB.graphics.FastPixel.create(FastPixel.java:38)
at com.github.kilianB.hashAlgorithms.PerceptiveHash.hash(PerceptiveHash.java:44)
at com.github.kilianB.hashAlgorithms.HashingAlgorithm.hash(HashingAlgorithm.java:122)
Example of an image that gets this error: https://console.brax-cdn.com/creatives/b86bbc0b-1fab-4ae3-9b34-fef78c1a7488/5_1200x800_ee7df89490d518b2f6fb8c739cbbfa30.png

Or:
java.lang.UnsupportedOperationException: The image type is currently not supported: 13
at com.github.kilianB.graphics.FastPixel.create(FastPixel.java:38)
at com.github.kilianB.hashAlgorithms.PerceptiveHash.hash(PerceptiveHash.java:44)
at com.github.kilianB.hashAlgorithms.HashingAlgorithm.hash(HashingAlgorithm.java:122)
Example of an image that generated this error: http://scd.pt.rfi.fr/sites/portugues.filesrfi/dynimagecache/0/42/337/190/1024/578/sites/images.rfi.fr/files/aef_image/dog2.gif

Also, for a small percentage of images I get an 'IllegalArgumentException':
java.lang.IllegalArgumentException: Unknown image type 0
at java.awt.image.BufferedImage.(BufferedImage.java:501)
at com.github.kilianB.graphics.ImageUtil.getScaledInstance(ImageUtil.java:40)
at com.github.kilianB.hashAlgorithms.PerceptiveHash.hash(PerceptiveHash.java:44)
at com.github.kilianB.hashAlgorithms.HashingAlgorithm.hash(HashingAlgorithm.java:122)
For example: https://ocdn.eu/pulscms-transforms/1/xkZktkpTURBXy9iZDgyYWY0YWNmNWRhY2NlZTA1OTZkYTVmNDcwYWUyNC5wbmeSlQMCAM0DTs0B3JMFzQNSzQG9

Is this an expected behavior and will not be fixed? Or is it a bug?

Thank you!

Error Using Nexus repository (Resolved)

Hi, we are with the error below:

[ERROR] Failed to execute goal on project images: Could not resolve dependencies for project br.com.auto:images:jar:0.0.2-SNAPSHOT: Failure to find com.github.kilianB:JImageHash:jar:3.0.0 in https://nexus.internal.com.br/repository/maven-group/ was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced -> [Help 1]

Our Nexus this makes the download of others dependencies (ok).

Help me???

Breaking hash values when moving to version 3.0.0

Hi,

I have tests that generate hash values and check for distance for several couples of images. They are there to guard for breaking changes in your lib when I move to a new version.
When trying to move to version 3.0.0 from 2.1.1 these tests seem to break. The images get different hash values than what we expect. The last time you moved from version 1.x.x to version 2.x.x, you specified in the changelog that something changed in the algorithm and there are breaking changes that will impact the hash values. This time, I can't seem to find anything like that.
Was this your intention? Or is it a bug?

Thanks!

HashValue as zero.

Hi Kilian,
While generating a hash value for the attached file using the below parameters, resulting in 0.
With the same file, we got hash value: 20282409603651670423947251810304 a few days back.
The same file with different formats[PNG, BMP, GIF, TIFF] also resulting in the hash value 0.
Please let me know if you require additional information.

        HashingAlgorithm hasher = new DifferenceHash(256, Simple);
        Hash hash = hasher.hash(bufferedImage );
        BigInteger hashValue = hash.getHashValue();

image

Android Usage

I'm trying to use this library in my app but the app wont compile with this error

    hash = hasher.hash(getFile());
                         ^
  class file for java.awt.image.BufferedImage not found

Any way too fix this?

Can't Find MathUtil or ArrayUtil

Hi KilianB,

I am try to install and build JimageHash under Eclipse. However, many of the imports (for MathUtil and others) are failing. What am I doing wrong? Where would I find MathUtil (actually com.github.kilianB.MathUtil)? Should I already have these packages?

Thank you

Peter Schaeffer

Problems with equals method

Hello,

I have an issue, not really a bug but maybe an improvement.
Here is the use case:

  • I create a hash from a picture, then I store it on the disk as a String.
  • I retrieve this string and I create a new Hash object.
  • I run the equals method on hash from step 1 and 2, it returns false.

After investigation, I found it is because the following part in equals method:
if (getClass() != obj.getClass())
return false;
My Hash from step 1 is of class: com.github.kilianB.hashAlgorithms.DifferenceHash$DHash while the second one is of class: com.github.kilianB.hash.Hash.

I tried to cast the first one in (Hash) but it doesn't seems to view the object as it.

One way to solve this migh be to do something like this in equals method intead of using the .getClass():
if (!(obj instanceof Hash))
return false;

Cheers.
Matt

JRE 1.8?

Hi,

would it be possible to build (and deploy to maven) with Java 1.8?

Using CategoricalMatcher on massive amounts of Hashes

Hey, first of all, awesome lib.
I'm currently tinkering on a database to collect Minecraft Skins (64x64 images). Before adding them I clean them up (upgrade older 64x32 skins to 64x64 and remove data from un-seen/used areas), and then save them with a sha256 hash in order to deduplicate them. Now I'm trying to use the CategoricalMatcher to group together visually simular skins. To speed things up I precalculate my used JImageHash(PerceptiveHash(128) seems to work really good for this usecase) and save them as json(Using gson for conversion) to the database. I created a tiny fork of JImageHash to add a "categorizeImageAndAdd(Hash[] hash, String id)" method that just skips the BufferedImage -> Hash[] conversion. It's also noteworthy that all that data is unlabeled, but normalized.
Now to my problem: The first ~20k hashes can be added rellativly fast, but the further along I get, the slower everything becomes. The current test database has 111.000 skin = 111.000 Hashes inside, and together with recomputeCategories() the process takes about 3 hours. The goal is to have millions of Skin in that database, so this approach won't work anymore.
Is there a better way of doing this? It just comes to mind test a newly added hash against all other hashes, which doesn't sound too practical, or useing chunks of the database and match against them. Maybe the Database can be split up into 10-100k clusters that can be computed, and where only the categories fuzyHash gets stored. Then hashes could be compared against these fuzyHashes.

Make h2 dependency optional?

To work the database image requires a driver. Currently this project depends on h2 for convenience. To my best knowledge (without testing) no specific functionality was used therefore, the driver could be swapped out for any arbitrary database engine.

The h2 dependency is the sole big dependency in this project. Maybe make it optional to get back the lightweight properties and throw an error if the database image matcher is used without an appropriate driver.

Create hashes using string builder instead of big integers

During hash creation a bigInteger object will be created for each bit present. Currently no fancy operation take place during it's creation process that justify this overhead.
Afterwards the xor operation on arbitrary hashes is required for the hamming distance calculation.

Benchmark if it's more performant to use a stringbuilder.

BigInteger hash = BigInteger.ZERO;
for (int x = 0; x < width; x++) {
	for (int y = 0; y < height; y++) {
		if (pixelValue[x][y] < compareAgainst) {
			hash = hash.shiftLeft(1);
		} else {
			hash = hash.shiftLeft(1).add(BigInteger.ONE);
		}
	}
}
return hash;

vs new

StringBuilder sb = new StringBuilder(hashResolution);
for (int x = 0; x < width; x++) {
	for (int y = 0; y < height; y++) {
		if (pixelValue[x][y] < compareAgainst) {
			sb.append(0);
		} else {
			sb.append(1);
		}
	}
}
return new BigInteger(sb.toString(),2);

In cooperation with #18

Dockerfile/API implementation?

Hi @KilianB
I stumbled upon your project as I was looking for a image similarity service that saves & compares the images using elasticsearch. Unfortunately, I don't have any experience with Java. That's why I wanted to ask you about your opinion on creating a Docker based service out of your project or if you could just estimate, how much effort this would mean. Packing everything up a Dockercontainer, maybe even with a HTTP API would maybe also improve the development process.
Thanks!

Consider using different edit distances (cyclic and rotational variant to counter translation for location aware hashes)

Most of the non frequency based hashes encode a subset of the image into a single bit (the hash maps 1 bit of information to specific location).
For motion tracking we use sliding windows to compare hashes. The hamming distance might be off due to simply being translated a bit. Try to find a new edit distance accounting for bigger swaps in the binary string.

Maybe:

  1. naive levenshtein distance
  2. N-Grams (https://www.researchgate.net/publication/237107253_Using_q-grams_in_a_DBMS_for_Approximate_String_Processing) ?
  3. cosine similarity
  4. https://ieeexplore.ieee.org/document/4708948 Edit distance with block swapping

Difficulty Building on Linux

Unable to build under current openjdk + javafx (openjfx), producing

[ERROR] /home/me/development/JImageHash/src/main/java/com/github/kilianB/hash/Hash.java:[18,26] cannot access javafx.scene.paint.Color
[ERROR]   bad class file: /home/me/.m2/repository/org/openjfx/javafx-graphics/12-ea+8/javafx-graphics-12-ea+8-linux.jar(javafx/scene/paint/Color.class)
[ERROR]     class file has wrong version 55.0, should be 52.0
[ERROR]     Please remove or make sure it appears in the correct subdirectory of the classpath.

Fedora 28
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-b13)
OpenJDK 64-Bit Server VM (build 25.191-b13, mixed mode)

Windows build was successful after getting the Oracle Java JDK and Maven to play nice with each other, but only from within Eclipse for some reason (likely local default maven config missing some things).

RotAverageHash returns the different results for the same object

I m using the static instance private static final HashingAlgorithm ROT_AVERAGE_HASH = new RotAverageHash(32);of a hash

//given

I m using the same bufferImage (the same object reference) to calculate the hash a few times.

//expect

the same result for every calculation

//current result

the 1st calculation returns a different result than the others

I in each invocation we are using the same object: BufferedImage@2f6bcf87, but the 1st generated value: 00000000000101110001010000000000 is different (2nd, and 3rd one are the same: 00000000000101110001010101100000)
look at the details:

--first:

input: BufferedImage@2f6bcf87: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 612 height = 792 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0

rot_hash: Hash: 00000000000101110001010000000000 [algoId: 2087538531]

--second:

input: BufferedImage@2f6bcf87: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 612 height = 792 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0

rot_hash: Hash: 00000000000101110001010101100000 [algoId: 2087538531]

--third

input: BufferedImage@2f6bcf87: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 612 height = 792 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0

rot_hash: Hash: 00000000000101110001010101100000 [algoId: 2087538531]

dHash tripple precision padding issue?

The example image suggests that the hash of the diagonal dHash always represents a 0 at the last right and bottom buckets. Take a look at it and see if indices are messed up.

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.