Coder Social home page Coder Social logo

imagej-ops's Introduction

developer chat

ImageJ Ops

ImageJ Ops is an extensible Java framework for algorithms, particularly image processing algorithms. Ops seeks to be a unifying library for scientific image processing. See the Motivation page for details.

Getting started

Each op has a list of typed input and output parameters on which it operates. You can think of an op as a (potentially multi-variable) function:

sum = math.add(a, b)
(phase, amplitude) = fft(image)

In many cases you can also pass a pre-allocated output which will be populated:

math.add(sum, a, b)

Some ops take other ops as inputs, which allows for things like "execute this op on every pixel of that image":

add_op = op("math.add", 5)
output_image = map(input_image, add_op)

For more details, see the "Introduction to ImageJ Ops" tutorial notebook:

https://imagej.github.io/tutorials

Working example

Try this Jython script in ImageJ's Script Editor!

#@ ImageJ ij

# create a new blank image
from jarray import array
dims = array([150, 100], 'l')
blank = ij.op().create().img(dims)

# fill in the image with a sinusoid using a formula
formula = "10 * (Math.cos(0.3*p[0]) + Math.sin(0.3*p[1]))"
sinusoid = ij.op().image().equation(blank, formula)

# add a constant value to an image
ij.op().math().add(sinusoid, 13.0)

# generate a gradient image using a formula
gradient = ij.op().image().equation(ij.op().create().img(dims), "p[0]+p[1]")

# add the two images
composite = ij.op().create().img(dims)
ij.op().math().add(composite, sinusoid, gradient)

# display the images
ij.ui().show("sinusoid", sinusoid)
ij.ui().show("gradient", gradient)
ij.ui().show("composite", composite)

The output:

sinusoid gradient composite

How to contribute

We welcome pull requests!

imagej-ops's People

Contributors

angrauma avatar apal4 avatar awalter17 avatar axtimwalde avatar bnorthan avatar ctrueden avatar djniles avatar dscho avatar eczech avatar eikeheinz avatar etadobson avatar firetiti avatar frauzufall avatar gab1one avatar gselzer avatar haesleinhuepf avatar hinerm avatar imagejan avatar kephale avatar lnyng avatar maarzt avatar mdoube avatar michaelzinsmaier avatar rimadoma avatar simonschmid avatar squareys avatar stelfrich avatar tibuch avatar tinevez avatar tpietzsch 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

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

imagej-ops's Issues

Auto-Generate Functions

Hi all,

yesterday I took the chance and started to implement some more ops and refactored some existings ones. I figured, that the "Function" Interface we are actually always follows the same (and inconsistent pattern): Define one arbitrary input parameter and one arbitary output parameter of an Op and make it a function, which updates it directly. We do that, such that we don't have to update these two parameters using reflection all the time (which is really good, as e.g. pixel wise operations would have super low performance if not).

Anyway, I was thinking how we can avoid this more or less arbitrary definitions of functions, while still haveing performant ops. My (very rough) idea was, that we could implement a FunctionService which automatically decorated an Op with the Function interface based on two predefined input parameters. The FunctionService would return a function. Of course this would involve JavaAssist stuff. So @dscho, do you think this is doable? Does this make sense at all?

Unify approach to toplevel interfaces

With 1880558, all toplevel base interfaces (those corresponding to a particular String name) were unified in the autogenerated Ops class as inner classes.

However, there are still some outliers which need to be unified similarly:

That way, future work on other sorts of ops—particularly autogenerated ops—can follow the same pattern without needing to edit the central Ops.list.

Support region sampling code

PointSets grew out of a few needs but one being the ability to sample a region at integral spacings. In implementing the code for #1523 it occurred to me that this might be the relationship between RegionOfInterest and PointSet.

It would be nice to specify Samplings which can return sets of coordinates in either real or integer coordinate spaces as needed.

Our current HyperVolumePointSet could instead be a RegularGridSampling at integral coordinates. Samplings could be composites (so they could support the complement, intersection, union, difference operations). They may refer to a RegionOfInterest but maybe instead to a space (with some default spaces defined and at least one class that treats a RegionOfInterest as a space).

Migrated-From: http://trac.imagej.net/ticket/1528

Automatically apply map op when matching

For an op such as tan which operates on eg. a RealType, we want to support using that op across an entire image transparently. The matcher and possibly other parts of the framework will need to be enhanced to accommodate this requirement.

Functions

Hi,

we are currently going on with our work on the firstorderstatistics branch and we are having some questions about functions.

The most important one is: What about introducting two new interfaces: SingleOutputOp and SingleInputOp. Function<I,O> extends SingleInputOp, SingleOutputOp. Actually we need this for our descriptors (which are nearly always SingleOutputOp but only sometimes also SingleInputOp<?>>.

Why we need that? Well, we of course could also introduce two very specific interfaces which are named "Descriptor and Feature" which would simply SingleOutputOps of different types. Thats I wondered if the above mentioned interfaces might be useful in general.

Cheers,

Christian

Add mechanism to "reduce" an op to another op

Given a set of "op parameters" (name, type and args), the OpMatchingService works in multiple stages:

  1. Find the op candidate implementations with matching name and/or type.
  2. Narrow down the candidates to exact matches:
    • Filter down to those with the same number of arguments
    • Filter down to those with compatible types of arguments
    • Exclude those that implement Contingent and reject the specific args given

Note that "compatible" above means "able to be converted using the SJC ConvertService."

We will add another phase of the matching process, as follows:

  • Define an OpParams class (tentative name) that encapsulates the (name, type, args) as a single object.
  • Define some SJC Converter implementations that know how to "reduce" from certain OpParams to other OpParams. This is very useful in the case when an op ends up being a simple wrapper around another op, which is very common.

For example: these converters could define the following reduction path:

  • normalize(outputImgPlus, imgPlus, axisTypes)
  • ➡️ normalize(outputImg, img, axisIndices)
  • ➡️ slicewise(outputImg, img, op(normalize), axisIndices)
  • ➡️ map(...)

Then the OpMatchingService would need to—when an exact match is not found—attempt to apply a reduction then repeat the matching algorithm, repeating as needed until no more reductions can be found (excluding cycles).

See the match-conversion branch to follow progress on this issue.

Create position-sensitive map operation

Would it make sense to create a map operation where the position within the Interval (or RealInterval) is known to the nested function? We would probably need a new subtype of Function that has the position (maybe as a double[]) as an additional argument to the compute method.

I recently created an equation op that illustrates why such a map would be nice. The implementation currently uses an IterableInterval as its output, but the actual operation is completely independent pixel-wise. However, the value of each pixel is defined by an equation which operates on the Interval position, so that you can generate stuff like gradients, sinusoidal shapes, or whatever your mathy brain can dream up. So at the moment, it is not possible to use the current mappers to create an equation op that operates on a single pixel only.

I think this new mapper would end up being quite useful; it is sort of analogous to ImgLib2's distinction between "cursor" and "localizing cursor". Some operations need to localize at every pixel, some occasionally, and some never. Shall OPS support all of these cases, too?

/cc @dietzc

Build fails with EnforceByteCodeVersion error

When attempting to build from a fresh clone, the build fails with this error:

Downloaded: http://maven.imagej.net/content/groups/public/org/scijava/junit-benchmarks/0.7.3-scijava/junit-benchmarks-0.7.3-scijava.jar (74 KB at 252.6 KB/sec)
[INFO]
[INFO] --- maven-enforcer-plugin:1.3.1:enforce (enforce-rules) @ imagej-ops ---
[INFO] Adding ignorable dependency: null:jcodings:null
[INFO] Adding ignore: org/jcodings/*
[INFO] Adding ignorable dependency: null:jnr-constants:null
[INFO] Adding ignore: com/kenai/constantine/*
[INFO] Adding ignore: jnr/constants/*
[INFO] Adding ignorable dependency: null:jnr-ffi:null
[INFO] Adding ignore: jnr/ffi/*
[INFO] Restricted to JDK 1.6 yet com.sun:tools:jar:1.4.2:system contains sun/tools/asm/ArrayData.class targeted to JDK 1.7
[WARNING] Rule 1: org.apache.maven.plugins.enforcer.EnforceBytecodeVersion failed with message:
Found Banned Dependency: com.sun:tools:jar:1.4.2
Use 'mvn dependency:tree' to locate the source of the banned dependencies.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.068 s
[INFO] Finished at: 2014-11-23T12:00:49-05:00
[INFO] Final Memory: 30M/185M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-enforcer-plugin:1.3.1:enforce (enforce-rules) on project imagej-ops: Some Enforcer rules have failed. Look above for specific messages explaining why the rule failed. -> [Help 1]

Add morphological ops

This includes dilate, erode, open and close.

And we want them to work on arbitrary structuring elements.

Add convolution/deconvolution ops

It would be awesome to provide a permissively licensed, high performance, general purpose deconvolution implementation in OPS. This entails work on several different constituent ops:

Milestones:

  • FFT, FHT, etc. – We can leverage ImgLib2's FFTMethods code (see also #12).
  • base classes for linear and iterative FFT filters.
  • FFT Version of Convolve
  • Richardson Lucy Deconvolution algorithm
  • Kernels – see also #48
  • Laplacian of Gaussian – in order to implement a complete segmentation pipeline.
  • Separable-ND, Non-Separable-ND, NaiveConvolve – can leverage ImgLib2's SeparableSymmetricConvolution
  • Fast, regularized version of Richardson Lucy with boundary conditions. See [1] for possible approach (also @StephanPreibisch SPIM paper goes over some approaches [2])
  • Diffraction based Point Spread Function Kernel (possibly wrap Icy plugin [3] or COSMOS, this would have to be licensed as gpl)
  • Measured Point Spread Function Kernel (extract kernel from bead image)
  • Common GPU infrastructure for above ops (covered separately by #60)

Considerations:

  • Ops need to be "set" aware. For example x-y-channels would be handled differently then x-y-z. Need to read meta data (from ImgPlus?)
  • Usability. Go over previous FFT and deconvolution questions on the listserv(s) and ensure above ops address community needs.

See also:

[1] http://link.springer.com/chapter/10.1007%2F978-3-540-93860-6_81
[2] http://www.nature.com/nmeth/journal/v11/n6/full/nmeth.2929.html
[3] http://icy.bioimageanalysis.org/plugin/PSF_Generator

Smarter numeric type matching

Numeric type matching is not as magical as we would like. E.g.:

import net.imagej.ImageJ;
import net.imglib2.img.array.ArrayImgs;
import net.imglib2.meta.ImgPlus;
import net.imglib2.type.numeric.integer.ShortType;

public class Sandbox {

    public static void main(String[] args) {
        short[] shorts = {1,2,3,4,5};
        ImgPlus<ShortType> img = new ImgPlus<ShortType>(ArrayImgs.shorts(shorts, new long[]{5}));
        ImageJ ij = new ImageJ();

        // this works
        ShortType copy = img.firstElement().copy();
        copy.setReal(25);
        ij.op().add(img, copy);

        // this also works
        ij.op().add(img, (short) copy);

        // But this does not work
        // ij.op().add(img, 25);

        for (int i=0; i<shorts.length; i++) System.out.println(shorts[i]); 
    }
}

In general, this might get quite tricky, but we can certainly do more:

  • First look for sigs that do not require a numeric downcast.
  • Then look for sigs that do, but would not lose any information. Since we have the value of the instance, we can verify that the downcast (e.g., of an int 25 to short) will not cause actual loss of information.
    Gets tricky with the fact that we then need to convert from the number to a NumericType.

The best general solution is a ConversionService that supports conversion plugins. This makes the conversion extensible, so we could begin special casing support for e.g. ImgLib2 numeric types without polluting the ConversionUtils#convert method with case logic. See also scijava/scijava-common#95

Naming of Ops

Hi,
we are currently implementing a lot of stuff related to features and we don't know how to actually name the classes. Example: We have an Op (Interface) which calculates the Area for several types (Iterable, Polygon, ...) and we have an Op which calculates the SmallestEnclosingRectangle based on something else.

How would you name the ops?

CalculateSmallestEnclosingRectangle and CalculateArea or rather SmallestEnclosingRectangle and Area. The second option would imply that our Mean would also be called CalculateMean (replace Calculate with whatever you want). However if we would just use SmallestEnclosingRectangle one could think, that this is the class which is the SME itself. In the case of Area, the class also doesn't represent the Area, but for the sake of simplicity and short-names Area seems to be the better choice.

Any ideas @ctrueden @hinerm @dscho @bnorthan ?

Edit: We also have a class CreateHistogram, another case.

Velocity Templates: Map and List

Hello @ctrueden @dscho,

I had a look at velocity templates which support amazing features e.g. foreach, maps and arraylists.
Since the groovy script parses all variable values from the .list as Strings, I didn't find a way to access theses features, though.

A line like this list = [1, 2, 3] would be set in the velocity context as literally "[1, 2, 3]" and therefore can't be iterated via foreach.

I modified the groovy script to parse Maps and Lists and Maps in Lists manually.
See https://github.com/Squareys/imagej-ops/tree/velocity-types
Left to do is maybe parsing numerical values? I tried to find a way to let velocity do the parsing, I hope I didn't miss anything.

Also, there is a nifty $foreach.hasNext feature, which is only available with velocity 1.7 and upward, maybe we could use that instead?

Greetings,
Jonathan (Squareys)

Move deprecated packages into folder: deprecated

Would it be possible to move all deprecated packages (net.imglib2, net.imagej.* which is not ops) into a dedicated folder? There are several reasons why this would make sense from my point of view

  • Developers are somehow puzzled where the actual ops development takes place (even if marked as deprecated in the file itself).
  • Some packages have the same name as packages in other bundles (OSGi doesn't like this).

I suggest to move them to the base package "deprecated", but I'm not sure what the consequences for other, depending projects might be?!

Improve prime OPS example script

The OPS library is focused on image processing, and as such it would be best if the front-facing example script did more than gimmicky operations. Rather, it should perform a really common and useful—but simple—image analysis workflow. We want something succinct that elegantly performs some powerful image processing.

We need to update both the README.md as well as the using-ops tutorial.

Better generic parameter type matching

When generics are involved, OPS does decent parameter type matching when deciding which op is the most appropriate for a given list of arguments. The reason it is decent, and not just crappy, is thanks to the great gentyref library, which helps tremendously for resolving when an object will actually safely fit into a given parameter field.

However, due to runtime generic type erasure, there are still cases where we cannot figure out whether the match is safe. For example:

public class AddConstantToArrayByteImage implements Op {
    @Parameter(type = ItemIO.BOTH)
    private ArrayImg<ByteType, ByteArray> image;

And:

public class AddConstantToArrayDoubleImage implements Op {
    @Parameter(type = ItemIO.BOTH)
    private ArrayImg<DoubleType, DoubleArray> image;

In this case, we cannot distinguish between an argument (i.e., object instance) of type ArrayImg<ByteType, ByteArray> and ArrayImg<DoubleType, DoubleArray> because at runtime, all that is known is that the argument is of type ArrayImg. But in practice it is backed by a particular type, e.g. ByteType, meaning that if it erroneously matches to the AddConstantToArrayDoubleImage, there will later be a ClassCastException when attempting to work with the object as though it were an ArrayImg<DoubleType, DoubleArray> (in this case, maybe when trying to assign the result of Cursor#get() to a DoubleType).

The currently proposed solution is to create a GenericTyped interface in SciJava Common with method Type[] getGenericTypes() that returns a list of Type objects matching the generic parameters. Or maybe it should return Class<?>[]... further thought and testing is needed. But the idea is to provide generically typed objects with a mechanism to "unerase" their types. Then the OPS matcher can check if the object implements this interface in order to glean its generic types and hence match to the op's inputs more precisely.

Discard optional "both" parameters preferentially to "input" parameters

We want the out parameter of OutputFunction implementations to be discarded preferentially to later optional inputs, if any. We can accomplish this in a general way by preferring optional "both" parameters (also from right to left) to pure "input" parameters, when deciding the order of optional inputs to discard.

The alternative would be to check against every possible combination of missing optional parameters, but that is exponential (e.g., twenty missing optional inputs would be 2^20 > 1 million combinations already...). So let's stick to right-to-left, but do "both" parameters first followed by "input" parameters.

Cooccurrence Matrix

Our Cooccurrence Matrix has completely different values than the Matlab Implementation.

Test Image:
lenna_grey

Easy way of browsing and selecting from available ops

As things stand, it is a little challenging to quickly see the available/relevant ops. We have the OpService#help(String) command, but that gives you all signatures for operations of that name. There is no instant gratification "auto-complete" style thing available in Eclipse, since OPS works its magic at runtime rather than compile time. It would be great to remedy that situation somehow.

One option would be a UI allowing for the browsing and selection of ops, for the purposes of search, filtering and execution. This would essentially be a Command Finder for OPS. Since an Op is already a command, the IJ2 Command Finder actually already displays all ops, but not the list of input parameters nor descriptions where available. So the UI proposed here would be slightly different than just another Command Finder.

A second possibility would be an Eclipse plugin for OPS that gives you code completion from within the IDE. This would be incredibly slick and useful, and is the option I am leaning toward at the moment.

Threadable Interface for Ops

Hi all,

I already sent this mail to some of you, but I think here is a better place to discuss, as others also may take part at the discussion.

Here the mail:

we came to a point where we think it would be nice to have a "Threadable" Interface. Assume you have a function which e.g. uses temporary, globally declared, variables (fields) like buffers or something else which makes this function "stateful". An Example would be LoopFunctions or simple JoinFunctions. Here you can't use one LoopFunction in several threads, as the buffer wouldn't be copied.

We thought about the following, which additionally has some nice side-effects:

Very important:
(a) Introduce Threadable interface with a method like "F getIndependentInstance()", which returns another instance of F for multi-threading. Note: This is not "copy" as we don't need to copy the state of e.g. a function.
(b) Introduce ThradableFunction and ThreadableInplaceFunction

Having this interface, an algorithm which want to do multi-threading using e.g. a function, may only accept ThreadableFunctions or ThreadableInplaceFunctions as Parameters (which is nice).

Additionally:
(C) Introduce AbstractThreadableFunction and AbstractThreadableIInplace which both already implement the corresponding interfaces and simply return "this" when getIndependentInstance() was called.

Nice side-effect:
Assume a Map which parallelizes the mapping using a ThreadableFunction. The Map itself is not a ThreadableFunction, this means, it can't be used by an algorithm which needs ThreadableFunctions. Like this we automatically avoid to nest the multi-threading too much.

What do you think?

Christian

Remove FFTConvolution class

The FFTConvolution class was copied from ImgLib2 wholesale. This class was taken from imglib2-algorithms-gpl, which is licensed under the GPL. Hence, this class is incompatible with ImageJ OPS's BSD-2 licensing.

To address this issue in the short to medium term, we can split the imagej.ops.convolve package into its own component, ij-ops-gpl, which depends on imglib2-algorithms-gpl. But ideally, we don't want any part of OPS to be licensed under the GPL; better would be to find a way to do convolution without that code.

See also imglib/imglib2#61

Migrate more operations from ImgLib2 OPS

In #24, the RealUnaryOperation classes of ImgLib2 OPS were migrated to ImageJ OPS. We want to do the same thing for RealBinaryOperation, ComplexUnaryOperation and ComplexBinaryOperation.

Automatic Creation of Interfaces

@dscho: Thank you for working on the automatic interface creation for ops. This issue is just to state, that we (especially @Squareys who doesn't know yet about his luck) will play with it and start to create some interfaces.

Autogenerate methods for built-in ops

The OpService provides a method signature for each operation name. They all take Object... args for the parameters. Instead, we could code generate the OpService class using a template, so that it has compile-safe signatures for all built-in ops. It would be slick if it was feasible (though I have my reservations).

Decide how to handle exceptions

The OPS framework uses Runnable#run() which throws no checked exceptions. Do we need any checked exceptions in the OPS framework?

One very common case, invalid arguments, is easily handled via IllegalArgumentException, since it is a runtime exception. And furthermore, the problem can essentially always be avoided via use of the Contingent interface, which will reject invalid parameter values as non-matches anyway.

But what about errors during computation? Should there be an unchecked OpException which can potentially be thrown during run()? I have mixed feelings—but this is definitely something easy to introduce at any point in the future without breaking any backwards compatibility.

Personally I'd like to wait to introduce any dedicated exception handling code until we have a concrete use case for it. But I'm filing this issue to invite those interested (@dietzc? @dscho?) to present arguments and use cases in favor of any work needing to be done here. And if no one has anything to add with the next few weeks, I'll close out this issue.

Add progress monitoring API

OPS need to be able to report their current progress. Each OP is its own task, which may be composed of subtasks. We can achieve this using the SciJava Common TaskService.

  • Want to be able to pause or cancel ops
  • Want to know how close they are to done
  • Want to avoid negative performance impact

Add supporting code for GPU-based ops

We want to make implementing GPU-based ops as easy as possible. The glue code to execute GPU-based processing from Java is usually the same. The two main flavors to consider supporting are OpenCL and CUDA.

We can start by implementing a couple of GPU-based ops, and then factoring out common code into a shared type hierarchy. Due to the addition of dependencies for working with OpenCL and/or CUDA, we will likely need to create a new imagej-ops-gpu project (and/or imagej-ops-cuda and/or imagej-ops-opencl projects) which extend imagej-ops.

Implement needed SciJava Converters

Need to think about exactly which are needed, but here is a non-exhaustive list:

  • long[] ➡️ Dimension
  • int ➡️ Shape
  • RandomAccessibleInterval ➡️ Iterable (Interval)
  • Iterable ➡️ Histogram
  • RandomAccessibleInterval ➡️ IterableInterval
  • ImagePlus ↔️ ImageDisplay
  • ImagePlus ↔️ Dataset
  • Dataset ↔️ ImgPlus
  • Img ↔️ ImgPlus
  • ImgView and LabelingView
  • Any other converters using Views
  • Use TypeConverter for images and type elements

Then we can remove tons of Map operations!

See the convert_numbers branch for current progress.

Implement RangeCondition using set operations

Although net.imglib2.RangeCondition is used by PointSetParser, we do not need those classes yet in imagej-ops. RangeCondition is not used anywhere else, so it may be better to hold off on its implementation till more set functions exist within ImageJ OPS.

RangeCondition is fundamentally a set inclusion test, but limited to a linear set defined by start, end, step parameters. Generalizing this logic to have "element" and "contains" set operations, together with a linear set implementation, would solve the RangeCondition use case in a far more general way.

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.