Code Monkey home page Code Monkey logo

Comments (39)

cancan101 avatar cancan101 commented on May 24, 2024 3

Right now I am solving the problem by shelling out to dcmdjpeg using this:

def load_dicom(input_file, force_decode=False, no_decompress=False):
    assert not (force_decode and no_decompress)

    import dicom

    data = dicom.read_file(input_file)

    if no_decompress or (not force_decode
                         and data is not None
                         and data.file_meta.TransferSyntaxUID in dicom.dataset.NotCompressedPixelTransferSyntaxes):
        return data

    with tempfile.NamedTemporaryFile(suffix=".dcm") as f:
        # +cl   --conv-lossy           convert YCbCr to RGB if lossy JPEG
        # +cn   --conv-never           never convert color space
        # +px   --color-by-pixel       always store color-by-pixel
        subprocess.check_output(['dcmdjpeg', '+cl', '+px', input_file, f.name])
        data = dicom.read_file(f.name)
    return data

from pydicom.

darcymason avatar darcymason commented on May 24, 2024 1

In a post[1] on the pydicom google group, cardioninja shared some concise code which can decompress 8-bit jpeg, if libjpeg-turbo and its cffi interface jpeg4py are installed. This was confirmed to work on files from Philips Echocardiography machines - iE33 & Affinity. Cardioninja also comments that it would be trivial to use PIL or Pillow instead, but libjpeg-turbo was much faster. Cardioninja's code is replicated below. As a side note, it also uses mmap, which is related to #139.

I think it would be interesting to add "handlers" for various types of compressed images through a plug-in architecture -- in this case, if the code was registered as a handler for 8-bit jpeg, then anyone with the right libraries already installed could transparently read those images.

Handlers should check for their dependencies and only register for transfer syntaxes they can decompress given the libraries installed. Perhaps a call function could also determine which additional libraries could give more functionality, so that pydicom could point to them in the NotImplemented exception message. (e.g. 'pydicom cannot handle this image, but if you installed <name/hyperlink> then it should be able to via plugin <plugin-name>'). If multiple handlers could process the file, the message would list all such options, so that the user could choose the easiest one to install for their platform. Such a plugin framework could also work for @Korijn's gdcm-calling code.

Here is cardioninja's 8-bit jpeg code:

import os
import sys
import mmap

import numpy as np

import jpeg4py

def jpeg_extract(file_fl):
    frames = []
    with open(file_fl, "r+b") as dicom_f:
        with mmap.mmap(dicom_f.fileno(), 0) as dicom_m:
            i = 0
            while 1:
                start = dicom_m.find(b"\xff\xd8\xff\xe0", i)
                if start == -1:
                    break
                i = start
                end = dicom_m.find(b"\xff\xd9", i)
                if end == -1:
                    break
                try:
                    jpg_data = np.fromstring(dicom_m[start: end+2], dtype=np.uint8)
                    jpeg4py.JPEG.clear() #needed as if it ever fails, it won't decode another frame without a reset
                    image_data = jpeg4py.JPEG(jpg_data.copy()).decode()
                    frames.append(image_data)
                except Exception as e:
                    print(e)
                i = end
    return np.array(frames)

[1] https://groups.google.com/d/msg/pydicom/PJ9K37dsmBk/OXLJtprjCQAJ

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on October 11, 2008 17:17:50

More info: Most important ones to add first will be the ones that have not been
retired, and especially the default transfer syntaxes:

First, ultra-short first-line defaults list, then more details follow:

  • JPEG Lossless, Non-Hierarch, 1st-Order Prediction (Process 14 [Selection Value
    1]) -- Default for Lossless JPEG Image Compression
  • JPEG 2000 Image Compression (Lossless Only)
  • JPEG Baseline (Process 1) -- Default for Lossy JPEG 8 Bit
  • JPEG Extended (Process 4) -- Default for Lossy JPEG 12 Bit
  • JPIP and JPIP deflate
  • RLE

Full details
(clipped from UID_dict)

  • 1.2.840.10008.1.2.4.50: JPEG Baseline (Process 1) -- Default Transfer Syntax for
    Lossy JPEG 8 Bit Image Compression
  • 1.2.840.10008.1.2.4.51: JPEG Extended (Process 2 and 4) -- Default Transfer
    Syntax for Lossy JPEG 12 Bit Image Compression (Process 4 only)
  • 1.2.840.10008.1.2.4.57: JPEG Lossless, Non-Hierarchical (Process 14)
  • 1.2.840.10008.1.2.4.70: JPEG Lossless, Non-Hierarchical, First-Order Prediction
    (Process 14 [Selection Value 1]) -- Default Transfer Syntax for Lossless JPEG Image
    Compression
  • 1.2.840.10008.1.2.4.80: JPEG-LS Lossless Image Compression
  • 1.2.840.10008.1.2.4.81: JPEG-LS Lossy (Near-Lossless) Image Compression
  • 1.2.840.10008.1.2.4.90: JPEG 2000 Image Compression (Lossless Only)
  • 1.2.840.10008.1.2.4.91: JPEG 2000 Image Compression'
  • 1.2.840.10008.1.2.4.92: JPEG 2000 Part 2 Multi-component Image Compression
    (Lossless Only)
  • 1.2.840.10008.1.2.4.93: JPEG 2000 Part 2 Multi-component Image Compression
  • 1.2.840.10008.1.2.4.94: JPIP Referenced
  • 1.2.840.10008.1.2.4.95: JPIP Referenced Deflate
  • 1.2.840.10008.1.2.4.100:MPEG2 Main Profile @ Main Level
  • 1.2.840.10008.1.2.5': RLE Lossless

Summary: Provide PixelData decompression (JPEG, RLE, MPEG, etc)
Labels: -Priority-Medium -Milestone-Release1.5 Priority-High Milestone-Release1.0

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on October 15, 2008 05:57:03

Tried to find JPEG libraries to decode pixel data (tried using PIL and libjpeg
directly) -- can do it for lossy 8-bit but other images tried (lossless, lossy
12-bit) did not work in PIL.
An alternative is to incorporate C code, but am trying to keep to pure python or
installation of one other package like PIL. So at this point, the amount of work
involved is not worth it, and not core to what pydicom is meant to do. Postponing
jpeg decompression for now.

Status: WontFix

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on May 24, 2009 19:26:28

Reopening this issue. Medical image format FAQ has good info on libraries available. http://www.dclunie.com/medical-image-faq/html/part7.html#SourceJPEG PVRG looks good (note link to PDF documentation in section linked to above, else is
latex docs with the libraries themselves). Perhaps could create a separate package to
wrap PVRG for python, have it as an optional install that pydicom could use if
available, maybe eventually merge it in (but would ideally like to keep pydicom as
pure python package; much simpler!).

Status: New
Owner: ---
Labels: -Priority-High Priority-Medium Difficulty-Hard

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on May 25, 2009 20:44:57

Found pure python Huffman encoding/decoding (part of JPEG process) at http://pypi.python.org/pypi/huffman%20encoder%20%26%20decoder/0.3 . Has detailed
explanation [1] and walk through of optimizing the code [2]. But is GPL (on PyPI
page), so inclusion in pydicom would limit the more-free MIT license.
His optimization didn't seem to look into Numpy at all, maybe there is more there.
Maybe PVRG (very open license) could be "converted" to python (using Numpy in an
optimized way to get reasonable speed).
[1] http://gpolo.ath.cx:81/misc/huffman/ [2] http://gpolo.ath.cx:81/texts/opc

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on May 25, 2009 21:08:05

More research: code for DCT (also needed for JPEG I believe): http://projects.scipy.org/scipy/ticket/733 -- proposed code for DCT using numpy fft http://whiter4bbit.blogspot.com/2008/11/dct-python-implementation-warning-code.html -

  • DCT using Numpy; quite short.

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on January 05, 2010 07:46:54

Just a suggestion -- libjpeg is widely installed in Unix/Linux land and is available
for Windows (although it's not installed by default). Why not make pydicom JPG
decompression conditional on libjpeg?

The same goes for PNG/libpng.

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on January 05, 2010 16:28:23

Just a suggestion -- libjpeg is widely installed in Unix/Linux land and is available
for Windows (although it's not installed by default). Why not make pydicom JPG
decompression conditional on libjpeg?

I'd be happy to use it if it would work. I did look at this a long time ago (see
comment from Oct 15, 2008), and only got it to work for 8-bit lossy images which
isn't very complete given that 12 or 16 bit images are common, and there are many
lossless techniques. It's a long time ago that I looked at this, but IIRC there were
some newsgroup discussions about many issues that other libraries such as dcmtk
and PVRG have had to deal with. I believe dcmtk started with libjpeg but had to
modify it and add in other codes for the various JPEG flavours allowed by DICOM. It
may make more sense to adopt their C code if any.

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on September 12, 2010 19:02:59

For JPEG, how about the Jasper library? I believe that OsiriX (Mac OS X DICOM viewer) uses it, and it's licensed under the MIT license. http://www.ece.uvic.ca/~mdadams/jasper/

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on September 12, 2010 19:25:07

OsiriX also uses OpenJPEG, which is BSD licensed. Not sure why the need for both. http://www.openjpeg.org/

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on March 06, 2014 14:54:27

Any updates on this? I'm currently using pydicom mixed with GDCM, looking to help incorporate a purely python way to decompress JPG images within DICOM.

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on March 07, 2014 15:36:26

No sorry, no update. I wonder, though ... IIRC I looked at GDCM once (or was it dcmtk?) and i remember seeing that they handled compressed images by calling a command line routine to convert to non-compressed in a temporary file, and then load that.

It would be fairly easy to add a "hook" in pydicom to call something like dcmtk to convert the file and then load it in. Would that be helpful?

And ... I'd be interested to know which specific compressed files (transfer syntax) people are encountering in the real world.

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on March 07, 2014 15:39:56

I've used dcmtk in conjunction with pydicom. I frequently run into JPEG-LS and JPEG2000 variants. A downside to dmctk is that there is no free module for encoding/decoding JPEG2000. That being said, OsiriX ( https://github.com/pixmeo/osirix ) uses dcmtk and they have their own way of handling JPEG2000 which you can look at in the source.

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on March 07, 2014 16:32:05

I'll try to have a look at OsiriX and see if there might be a way to build a C extension. If so, I could see that as a separate pydicom library (to keep the core pydicom pure python).

Just by way of explanation for anyone stumbling on this thread...my take on this issue (as in issue 16 ) is that it seems like a large amount of work to try to add decompression into pydicom (or related package), which has always had the philosophy of being light and very easy to install. This is why I've avoided it and recommend people pre-process compressed files with dcmtk or others.

To me, if the pydicom user has to go through the work of a complex installation with multiple dependencies, compiling C extensions, etc., then they might as well do so with one of the existing packages that already have that all worked out.

If there were a way to provide decompression in pure python or with minimal C, then I think that would be more in the spirit of pydicom. My hope was to perhaps handle a few of the most common compression formats that way.

I welcome anyone's thoughts on this subject.

Having said all that, on a more positive note: the various comments in this issue do seem to be converging on OsiriX as a good source to model, if anyone had the ambition to try to take this on. Realistically, it's not something I can see getting around to anytime soon.

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on March 09, 2014 07:48:53

Darcy, I'm using pydicom and GDCM for my prototype webservice dcmdb ( http://dcmdb.org ), so you can see I'm attempting to capture as many transfer syntaxes as possible ( http://dcmdb.org/main/transfer_syntax ). Using GDCM I have not have a transfer syntax issue as of yet.

I really want a pure python way to get images out of DICOM files, I know Ruby DICOM ( http://dicom.rubyforge.org/ ) was able to accomplish that goal, so I'm going to start really investigating solutions to this problem ... if you have any documentation that would be helpful on this journey, please let me know.

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on March 09, 2014 11:50:00

Eric,

I'm a bit confused. you're already using GDCM. are you using its Python extension? if so, what is the reason for a "pure Python" implementation?

in any case, OpenJPEG is really the best library out there, so you would need to do one of two things

  • link to it, and then wrap an extension around it. which is what GDCM does. this is not pure Python, but is still usable from Python.
  • compile it for Python, similar to how kripken has compiled it to JS ( https://github.com/kripken/j2k.js ). this would be pure Python

HTH

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on March 09, 2014 14:57:30

First, thank you to everyone for the discussion. It's good to get these ideas out there and see what we can come up with.

@neurosnap: I found this comment on ruby dicom: https://groups.google.com/forum/#!topic/comp.protocols.dicom/NMdlfkzpaII in which the author says it relies on ImageMagick but it only handles a subset of the JPEG variants. That comment is almost a year old though, so perhaps it has changed?

@mjpan: do you know any more about how the conversion to JS? It mentions using Emscripten, which I see is an LLVM to JS compiler. Is there a similar package to convert for python? And is there any hope of any of this working at an acceptable speed?

To all: I've toyed with some ideas on pure python implementations, but if you start reading through libjpeg (libijg)code (which dcmtk's jpeg is based on) it is incredibly intertwined. It is so heavily optimized for speed (and memory use) that it is very difficult to follow or translate to another language. It has been around a long time, so it comes from an era where speed and memory were very important. Plus (IIRC) there were many workarounds for known poor implementations and such. It would be very hard to replicate this in other code; I think that is why no one (very few?) have succeeded in doing so. Everywhere I looked, I just saw the same libijg code copied and pasted and minimally modified. In terms of difficulty, Jpeg2000 may be a different situation; I haven't really looked into those codes.

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on March 09, 2014 18:06:30

Thanks for the response, ideally I would like a better mechanism to deploy my server, something that would be easier to install besides GDCM, but I may be out of luck. I'll investigate openJPEG.

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on March 10, 2014 13:48:20

Darcy,

I'm sure that compiling OpenJPEG to pure Python can be done via LLVM, but I don't think anyone has had the motivation to do so, as it's possible to run C/C++ code in Python via an extension, as opposed to Javascript, which requires JS code to run in the browser.

for anyone looking for Python -> OpenJPEG, I'd suggest checking out Glymur. https://glymur.readthedocs.org/en/latest/introduction.html although I can't imagine it being any easier than building the GDCM Python extension-- CMake really makes things easy, especially as you go across operation systems

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From [email protected] on March 17, 2014 17:40:30

I just had a go at using Glymur to try to get pixel data out of a 1.2.840.10008.1.2.4.91: JPEG 2000 Image Compression'. I suspect that I am going about the problems that I have encountered incorrectly. However I am posting this comment here in case anyone can point out my mistake, or it is of help to anyone else investigating Glymur.

From the initial error messages it seemed that there was no header data. This seems consistent with, Part 5 of the DICOM standard section A.4.4 (p77) http://medical.nema.org/Dicom/2011/11_05pu.pdf staes:

"The optional JP2 file format header shall NOT be included. "

So far I have found Annex I of ISO15444-1 http://www.jpeg.org/public/15444-1annexi.pdf . Hoping DICOM pixel data contained a Contiguous Codestream, I attempted to create the relevant headings such that it could be simply read by the Glymur command for opening JPEG2000 files.

import dicom
d = dicom.read_file("/usr/lib/python2.7/dist-packages/dicom/testfiles/JPEG2000.dcm")
pd = d.PixelData
f = open("jp2000.jp2", "w+b")

f.write(struct.pack(">I4s4s", 12, "jP ", "\r\n\x87\n"))
f.write(struct.pack(">I4s4sI4s", 20, "ftyp", "jp2 ", 0, "jp2 "))
f.write(struct.pack(">I4s", 45, "jp2h"))
f.write(struct.pack(">I4sIIHBbBB", 22, "ihdr", d.Rows, d.Columns, d.SamplesPerPixel, d.BitsAllocated - 1, 7, 1, 0))#Need to add 128 d.BitsAllocated - 1 if pixel data is signed
f.write(struct.pack(">I4sBBBI", 15, "colr", 1, 0, 0, 16))
f.write(struct.pack(">I4s", len(pd), "jp2c"))
f.write(pd)
f.flush()
f.close()

jp2 = glymur.Jp2k("jp2000.jp2")
/home/martin/.virtualenvs/anat/local/lib/python2.7/site-packages/glymur/jp2box.py:135: UserWarning: Unrecognized box (����) encountered.
warnings.warn(msg)
/home/martin/.virtualenvs/anat/local/lib/python2.7/site-packages/glymur/jp2box.py:147: UserWarning: ���� box has incorrect box length (2822332288)
warnings.warn(msg)
jp2.read()
Traceback (most recent call last):
File "", line 1, in
File "/home/martin/.virtualenvs/anat/local/lib/python2.7/site-packages/glymur/jp2k.py", line 672, in read
img = self._read_openjpeg(**kwargs)
File "/home/martin/.virtualenvs/anat/local/lib/python2.7/site-packages/glymur/jp2k.py", line 713, in _read_openjpeg
self._subsampling_sanity_check()
File "/home/martin/.virtualenvs/anat/local/lib/python2.7/site-packages/glymur/jp2k.py", line 684, in _subsampling_sanity_check
dxs = np.array(codestream.segment[1].xrsiz)
IndexError: list index out of range

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

From agrothberg on July 02, 2014 16:31:22

If the image is showing a TransferSyntaxUID=1.2.840.10008.1.2.4.50 ( http://www.dicomlibrary.com/dicom/transfer-syntax/ ) is there any way I can get access to the raw data and just hand it to PIL to decode?

A naive call to: dicom.contrib.pydicom_PIL.show_PIL(dataset) did not work.

from pydicom.

neurosnap avatar neurosnap commented on May 24, 2024

If you have the python wrappers installed for GDCM, you can use
http://mudicom.dcmdb.org/ which has some helper functions for GDCM for
reading, writing, and extracting images from DICOM files.

On Wed Jan 14 2015 at 12:39:29 AM Alex Rothberg [email protected]
wrote:

Right now I am solving the problem by shelling out to dcmdjpeg using this:

def load_dicom(input_file, force_decode=False, no_decompress=False):
assert not (force_decode and no_decompress)

import dicom

data = dicom.read_file(input_file)

if no_decompress or (not force_decode
                     and data is not None
                     and data.file_meta.TransferSyntaxUID in dicom.dataset.NotCompressedPixelTransferSyntaxes):
    return data

with tempfile.NamedTemporaryFile(suffix=".dcm") as f:
    # +cl   --conv-lossy           convert YCbCr to RGB if lossy JPEG
    # +cn   --conv-never           never convert color space
    # +px   --color-by-pixel       always store color-by-pixel
    subprocess.check_output(['dcmdjpeg', '+cl', '+px', input_file, f.name])
    data = dicom.read_file(f.name)
return data


Reply to this email directly or view it on GitHub
#18 (comment).

from pydicom.

cancan101 avatar cancan101 commented on May 24, 2024

Here is some relevant discussion on what can and cannot be done from Python with GDCM:

from pydicom.

neurolabusc avatar neurolabusc commented on May 24, 2024

I have a few comments on this.
1.) As noted, the simplest solution is to call the dcmtk tool "dcmdjpeg" whenever you encounter a compressed image. You then load the decompressed version. In my experience dcmdjpeg is very robust, and handles all the formats well. This is what many of the professional solutions do (e.g. Osirix). The only disadvantage is making this a lighter tool that is more portable. The dcmtk code is very robust but is quite complicated (they compile the same JPEG libraries multiple times for different precisions, etc)

2.) You could also use my dcm2niix (also on Github). This is written in C, but is much less complicated than dcmtk. This uses the following libraries:
a.) lossy JPEG: nanoJPEG (already ported to Python)
b.) lossless JPEG: my own code - this is only Huffman coding so should be easy to adapt the Python NanoJPEG to do this. Note that this lossless JPEG is arcane and specific to medical imaging - my implementation provides 8, 16 (and 3*8 = RGB) bit precision. The downside here is that it is probably not a good idea to use a lookup table (which is very efficient for 8bit data. The 16-bit support is required for DICOM. This is not a very efficient compression scheme, but is very popular in CT (the default output of dcmcjpeg).
c.) OpenJPEG for lossy and lossless JPEG2000. The OpenJPEG API has changed a lot between versions and is really very complex. Unfortunately, the easier to implement JasPer appears to have some issues with high precision medical images (see Wiki for an example).
I have simpler executables that I am happy to send you to demonstrate each standard. In theory, you could hive these off one at a time as you add Python support, or use them as test references for building Python versions.

from pydicom.

neurolabusc avatar neurolabusc commented on May 24, 2024

One other comment - in many cases you can decompress images by using the operating system APIs. This tends to be very efficient. However, at the moment these do not seem sufficient for medical imaging, for example OS X 10.10 (Yosemite) the command "imageRepsWithContentsOfFile" will open JPEG2000 images but they are ALWAYS down sampled to 8-bit precision. This is different from TIFF images where the precision is preserved. Therefore, we really need custom libraries.

from pydicom.

Korijn avatar Korijn commented on May 24, 2024

How about using Pillow? It seems to support the full list of formats? Or imageio wich also seems to support them all?

from pydicom.

neurolabusc avatar neurolabusc commented on May 24, 2024

I have not tried these libraries, but I assume they would need to be extended to support DICOM's very arcane lossless JPEG (again, not hard - this is the Huffman decoding without the DCT). Also, make sure they do not decode 16-bit precision to 8-bit.

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

Unless something has changed, PIL (or pillow AFAIK) did not support 16-bit, which is what most dicom grayscale images would be.

For imageio (http://imageio.readthedocs.org/en/latest/format_dicom.html#dicom):

This format borrows some code (and ideas) from the pydicom project, and (to the best of our knowledge) has the same limitations as pydicom with regard to the type of files that it can handle.

from pydicom.

jrkerns avatar jrkerns commented on May 24, 2024

The discussion here may help: python-pillow/Pillow#625

from pydicom.

Korijn avatar Korijn commented on May 24, 2024

I think Pillow actually does support 16-bit currently: python-pillow/Pillow#730 (from @jrkerns link, thanks!).

from pydicom.

Korijn avatar Korijn commented on May 24, 2024

See #232!

from pydicom.

mshunshin avatar mshunshin commented on May 24, 2024

Thanks. Thats my code (cardioninja) - I only saw your reply and issue just now.

Agree it would be nice to add to pydicom. Would you be happy including ctypes wrapper (jpeg4py) in the pydicom code; that way to utilise the helper the user would only have to drop in the dll/dylib/so downloaded from the website in the application directory?

Sketching out the code - with the simplest boiler plate:


####This is an example class###
class jpeg_ninja():

    @staticmethod
    def check_works()
        ##Check if libraries are present etc.
        return 1

    @staticmethod
    def get_formats()
        return [“jpeg”]

    @staticmethod
    def convert_pixels(link_to_pixel_data)
        return np.array([[1,2],[2,3]])

###Generate this from DICOM specifications / known formats
pixel_formats = [“jpeg”, “jpeg_2000”, “fancy_new_format_200”]

###This bit makes a look-up dictionary to associate formats with pixel_handlers

###These are the classes
pixel_handlers = [jpeg_ninja, fancy_ninja]

pixel_lookup = dict.fromkeys(pixel_formats)

for handler in pixel_handlers:
    try:
        flag = handler.check_works()
        if flag:
            formats = handler.get_formats()
            for format in formats:
                pixel_lookup[‘format’] = handler
    except Exception as e:
        print(e)


#Having read a dicom file and worked out the format.
#It is nice if either a mmaped handle is passed (with the caller to close).
#Or a sequence of bytes that has the find method on it is passed to it.

if pixel_lookup[format] is not None:
    pixels = pixel_lookup[format].convert_pixels(link_to_pixel_data)


I guess you could have a init on the handler classes so that they can initialise and return success from the, and re-use the instance each time you need to decode a dicom file. May save a few ms.

How does this sound?

BW

Matt

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

I've mentioned in a couple of issues some old code I had tinkered with before, but I never tracked it down or explained it. I thought I'd do that here because I had discussed the concepts in an earlier comment in this issue.
I tried this because dataset.py was getting quite complex and more decompression codes were coming in, so I started looking at a general system of 'plug-in' image handlers:

The config idea can be seen in https://github.com/pydicom/pydicom/blob/feaIture/image-handlers/pydicom/config.py#L63
From line 63 to 83 to about line 83 sets up a system to allow the user to choose at run-time, which handler routines to try, and in which order.

image_handlers = ['standard_handler', 'gdcm_handler']  # jpgls_handler, pil_handler
"""Image handlers for converting pixel data.  These are tried in order
until one can provide the pixel data.  The code is in the 'handlers' subdir.
Change the order if needed to force using a specific handler, e.g. for speed.
Handlers may require installation of dependencies.  If dependencies are not
installed, the handler will not attempt conversion, and the next handler
would be called.  If none can convert, the handlers will provide messages
on what dependencies are needed.
"""

Each handler should be split out into its own importable file.
I started that at
https://github.com/pydicom/pydicom/tree/feature/image-handlers/pydicom/handlers, but it was left in a mess.
I was trying a couple of different 'api's of sorts, looking back now the easier one is a process' method, as in standard_handler.py`:

def process(ds):
    """Return a numpy array of pixel data for the given data.
    Returns:
    -------
    pixel_array: None, or numpy array
                 If unable to process the pixel data, returns None.
    message: str
             If unable to process, a message explaining libraries to install,
             or reason it cannot be processed.

So each handler "answers" back with either the pixel data, or with None and a message. Note that even non-compressed images are handled this way -- so if someone wants, e.g. to use gdcm for all images, compressed or not, they can do so by changing the config order.

I think I had started trying to refactor pixel_array() to use these modules, but can't find that code right now. Basically it called load_image_handler_modules() to get the plugins, then called them in order until one worked. As they were called, messages were collected in a list. If none worked, then the list of messages was raised in an Exception.

from pydicom.

qile11 avatar qile11 commented on May 24, 2024

i try use python install model
pip install PyExecJS to run js,exp jpeg file,My English is bad sorry!

https://github.com/rii-mango/JPEGLosslessDecoderJS

I try to export the dicom file as a jpeg or other picture。
my dicom file is :
MediaStorage is 1.2.840.10008.5.1.4.1.1.6.1 [Ultrasound Image Storage]
TransferSyntax is 1.2.840.10008.1.2.4.70 [JPEG Lossless, Non-Hierarchical, First-Order Prediction (Process 14 [Selection Value 1]): Default Transfer Syntax for Lossless JPEG Image Compression]

from pydicom.

darcymason avatar darcymason commented on May 24, 2024

@qile11, I don't understand your request. Have you been using pydicom, or are you looking for a way to use pydicom for converting dicom files to an image?

from pydicom.

mrbean-bremen avatar mrbean-bremen commented on May 24, 2024

I think this one has been implemented now by @darcymason and can be closed.

@qile11 - please check the documentation, especially the parts about "Working with Pixel Data" and "Handling of compressed image data" for getting started.

from pydicom.

qile11 avatar qile11 commented on May 24, 2024

Thank you
i look about "Working with Pixel Data" and "Handling of compressed image data" 。not found EXAMPLES!
i try #738 (comment)
is not work

    from pydicom.encaps import encapsulate
ImportError: cannot import name 'encapsulate'

try:

import numpy
import PIL
import pydicom
from pydicom import dcmread
# from pydicom.encaps import encapsulate
dicom_file=r"D:\pythontest\simpleiktdemo\dcmfile\bc.dcm"
dicom = pydicom.read_file(dicom_file, force=False)
print(dicom.PixelData )
if dicom.file_meta.TransferSyntaxUID.is_compressed is True:
    dicom.decompress()

Traceback (most recent call last):
File "D:/pythontest/simpleiktdemo/pydcmtest11.py", line 10, in
dicom.decompress()
File "C:\Users\85447\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pydicom\dataset.py", line 768, in decompress
self.convert_pixel_data()
File "C:\Users\85447\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pydicom\dataset.py", line 743, in convert_pixel_data
raise NotImplementedError(msg)
NotImplementedError: No available image handler could decode this transfer syntax JPEG Lossless, Non-Hierarchical, First-Order Prediction (Process 14 [Selection Value 1])

print(dicom.PixelData ) is:

8\xd8\xc6" \x0f{\xe4\x92G\xbd\xe05\xad\x8e8\xda\xd6\xb5\xad\x01\xadh\x08\x88\x88\x8a\xaa\xaa\xa0I$\x92\xcb,\xd3M4\xd3=\xefs\x9c\x03Z\xd6\xb5\xa0\x00\xaa\xa8\x88\xc61\xadk\x18\xc4D\x00\x05UD@\x15VI${\xde\x03\x18\xc8 \x828\xe3kZ\x88\x88\x88\x02\xaa\xb9\xce\x96Y^\xf7\xc9$\x8a\xaa\xe78\x061\x8cc\x11\x11U^\xf7\xc9$\x8f{\xd5U\xadk\x18\xc8 \x82\x08 \x82\x08+\xd7\xae\xc61\x11\x18\xc6C\x0c5j\xd5\xadZ\xb4\x10@\xc61UQ\x11Ue\x96Ye\x96Ye\xe4\xf9>L\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdc\xdc\xdc\x96Yg\x9eye\x95\xef{\x9c\xe9$\x92I$DJ\xd5\xabQ\xa3F\xa5J\x95\xeb\xd7\x02I$\x96YlX\xb1$\x92\x00\xd6\xb4\x079\xca\xaa\xf7\xbd\xcer\xaa\xa2 \x009\xceUP\x18\xc65\xadkZ\x88\x88\x88\xaa\xaa\xaa\xaa\xa8\x88\xd6\xb5\x11\x18\xc61\x8c\x01\xadkZ\xd4Ds\x9c\xe7:\xcd\x9b7\xaf^\xbf~\xfe\x9e\x9e\x9e\x86\x86\x85\xabV\xa5\x96[\x16,[\xb7m\xces\x9c\xe8\xa2\x8a\x18a\x8e8\xda\xd6\x80\x88\x8a\xaa\x88\x88\x88\x88\x8a\xaa\x88\x8cc!\x86\x18 \x82\x08 \xadZ\xb4\x10A\x1cq\xc5\x14Q\xc7\x1c\x10A\x0c0\xc5\x14Q\xc7\x1a"*\xab\x9c\xe4D\x8e8\xe2\x8a&\xb5\xa8\x88\xaa\xaa\xaa\x00\x08\x88\xd6\xb5\x8cb"" \x00*\xaa\xaa\xb9\xce\x01\xadj"5\xadkZ\xf7\xbdUe\x96W9\xces\x91\x11\x11\x11\x10\x05U\x01\xcer\xaa\xaa\xa8\x0es\xa4\x92EUUP\x11\x11\x11\x1a\xd6\xb5\xad\x01\xef{\x9c\xe9$\x91\xcer"5\xad\x01\xef{\xde\xf5UUP\x00\x00\x00\x00UW\xbd\xees\x9c\xe7*\xaa\xaa\xb9\xce{\xde\xf7\xbd\xef{\xde\xf9e\x95\xcesZ\xd61\x91\xc7\x1bZ\xd61\x80\x00\xf7\xbei\xa6\xb9r\xe5\xabV\xac\xd9\xb3$\x92\x00\x88\x8a\xaa\x03Z\xd8\xe3\x8e\x18a\x86\x18c\x8e0\x1e\xf7\xcb,\xb2\xcb,\xb2\xca\x88\x91E\x15Z\xb5j\xd5\xabZ\xb5h\xa2\x89\x8ccZ\xd0\x1a\xd6\xb5\xadkZ\x88\x8dkQ\x11\xadj""#Z\xd4D\x01\x11\x18\xc6G\x1cqE\x14q\xc6\xd6\xb5\xces\xde\xf9e\x96Ye\x92I$\x92EUs\x9c\xf7\xbd\xef{\x9c\xe9$\x92I$\x96Y\\\xe7*\xacQE\x14QC\x0c,c\x18\xc65\xad\x01\xadh\x08\x88\x00\x005\xadkZ\xd6\xb5\x8ccZ\xd61\x88\x88\xd6\xb5\xadh\x08\x88\x02\xaa\x80\xaa\xa05\xadDEU{\xde\xe79\xcer\xaa\xb5\xadc\x19\x1cq\xb5\xadc\x18\xaa\xaes\x9e\xf7\xbd\xef\x01\xadk\x18\xc4DkZ\x02"\x00\x02\xaa\xa2#Z\xd0\x00\x01\xcer\xaa\x80\x88\x80*\xaa\xaa\xaa\xa8\x0es\x80\x92I\x1e\xf7\xcf<\xf3\xcf=\x8b\x16.\xdd\xbb~\xfd\xfd\x1d\x1d\x1d==;\xd7\xafh\xe8\xe8\xc5\x14T\xe9\xd3\xc7\xc7\xc7\xc5\xc5\xc5\xca\xca\xca\xa1B\x85z\xf5\xe0\x82\x06\xb5\xa8\x88\xc61\xadlq\xc6\xd6\xb5\x11\x11\x11UUUU@{\xdf$\x92=\xef{\xde\xf7\xbd\xadkZ\xd8\xa2\x89\xadlq\xc6\x88\x80" 

....Omit.............
\x08\x88\xaa\xa0\x00\xe79\xces\xde\xf79\xca\xaa\xaa\xadkZ\xd6\xa2""\x00\x03\x9c\xe7\xbd\xea\xaa\x02"1\x8ckZ\x88\x805\xadDEUUW9\xca\xaa\xaa\xa0\x00\x02"*\xa8\rkb\x8a(\xe3\x8dU^\xf7\xcf<\xf2\xcb*\xaa\xa2""5\xadkZ\x02\xaa\xaa\xa8\n\xaa\xaa\xa0G\x1cq\xc7\x1cQE\x14Q1\x8cUW9\xcf{\xde\xf7\xb1\x8cc\x18\x03\xde\xf9$\x91\xcer\xaa\xb5\xad\x01\x11\x00\x028\xe3k[\x1cq\x80\xf7\xbeYes\x9c\x04q\xc6\xc628\xe3kZ\xe7:I$s\x9c\x88\x88\x88\x88\x8a\xaa\xe79\xef{\x9c\xe0\x11\x11\xadlq\xc6\xd6\xb5\xadj\xaa\xaa\xab\xde\xf7\xbd\xef{\xdc\xe7```\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\xff\xd9 '
Traceback (most recent call last):

Is there a specific example file?
show me

from pydicom.

scaramallion avatar scaramallion commented on May 24, 2024

From the Handling of Compressed Images page in the docs you need to install GDCM or possibly Pillow to handle that transfer syntax.

If you want encapsulate you should upgrade to the latest version.

from pydicom.

Related Issues (20)

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.