Re: [Matplotlib-users] imread() and PNGs
Tobias, I would like to apply your patch, but the test in examples/tests/pngsuite fails. If you can submit a new patch where this test passes, and, even better, if a small example 12-bit PNG of yours is added to the test, I will apply it. Apart from that, I would echo Eric's thanks for the patch and explanation. -Andrew Hi Andrew and Eric, Thanks for the responses. I was unaware of the png test suite. I have attached a new diff that passes this test correctly. It originally failed because I was not handling greyscale images with an alpha channel, but it also brought to light several other issues with my code that I have fixed. I have changed the structure of the code significantly - the if/else struct has gone and a single loop returns the different image matrices. Although this is more concise, it no longer informs the user if it hits an unsupported image type. Unfortunately I do not have a small test image available, all of ours are a minimum of 512x620. However the pngsuite page, http://libpng.org/pub/png/pngsuite.html, does have a set of suitable images labelled cs*n*.png. These have thrown up an interesting issue - to what maximum value should n-bit images be scaled when n is between 8 and 16? The png spec and test images suggest it should be (2^n - 1). This means that higher bit depths give higher precision over the same intensity range and the same maximum value. However for my particular camera and software this would be wrong, as the CCD has a fixed 12-bit dynamic range and the lower png bit depths are only used to save file space. Hence at the moment I have set my software to scale to (2^16 - 1) for 8 n 16, but it follows the png spec for n 8, so there are two contradictory behaviours and I am unsure which is the best approach. Personally I would prefer matplotlib to return raw integer values, not floats scaled between 0 and 1 and then I can apply the scaling myself, but I am aware that this is not particularly user friendly for anyone else. imshow() seems to handle integer values fine and correctly scales for display, provided that no alpha channel is present. Should I post another message to the developer list about this to see what people think? I'd very much like to discuss this with someone who has a lot more experience of pngs than me. Thanks, TobiasIndex: _png.cpp === --- _png.cpp(revision 7026) +++ _png.cpp(working copy) @@ -208,38 +208,37 @@ png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); - png_read_info(png_ptr, info_ptr); png_uint_32 width = info_ptr-width; png_uint_32 height = info_ptr-height; - bool do_gray_conversion = (info_ptr-bit_depth 8 - info_ptr-color_type == PNG_COLOR_TYPE_GRAY); int bit_depth = info_ptr-bit_depth; - if (bit_depth == 16) { -png_set_strip_16(png_ptr); - } else if (bit_depth 8) { + + // Unpack 1, 2, and 4-bit images + if (bit_depth 8) png_set_packing(png_ptr); - } - // convert misc color types to rgb for simplicity - if (info_ptr-color_type == PNG_COLOR_TYPE_GRAY || - info_ptr-color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { -png_set_gray_to_rgb(png_ptr); - } else if (info_ptr-color_type == PNG_COLOR_TYPE_PALETTE) { + // If sig bits are set, shift data + png_color_8p sig_bit; + if ((info_ptr-color_type != PNG_COLOR_TYPE_PALETTE) png_get_sBIT(png_ptr, info_ptr, sig_bit)) +png_set_shift(png_ptr, sig_bit); + + // Convert big endian to little + if (bit_depth == 16) +png_set_swap(png_ptr); + + // Convert palletes to full RGB + if (info_ptr-color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); - } + + // If there's an alpha channel convert gray to RGB + if (info_ptr-color_type == PNG_COLOR_TYPE_GRAY_ALPHA) +png_set_gray_to_rgb(png_ptr); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); - bool rgba = info_ptr-color_type == PNG_COLOR_TYPE_RGBA; - if ( (info_ptr-color_type != PNG_COLOR_TYPE_RGB) !rgba) { -std::cerr Found color type (int)info_ptr-color_type std::endl; -throw Py::RuntimeError(_image_module::readpng: cannot handle color_type); - } - /* read file */ if (setjmp(png_jmpbuf(png_ptr))) throw Py::RuntimeError(_image_module::readpng: error during read_image); @@ -255,37 +254,36 @@ npy_intp dimensions[3]; dimensions[0] = height; //numrows dimensions[1] = width; //numcols - dimensions[2] = 4; + if (info_ptr-color_type PNG_COLOR_MASK_ALPHA) +dimensions[2] = 4; //RGBA images + else if (info_ptr-color_type PNG_COLOR_MASK_COLOR) +dimensions[2] = 3; //RGB images + else +dimensions[2] = 1; //Greyscale images + //For gray, return an x by y array, not an x by y by 1 + int num_dims = (info_ptr-color_type PNG_COLOR_MASK_COLOR) ? 3 : 2; + + double max_value = (1 ((bit_depth 8) ? 8 :
Re: [Matplotlib-users] change hour format in date plotting
On Sat, Apr 4, 2009 at 06:37, C M cmpyt...@gmail.com wrote: I am pretty happy with the default for how dates ticks are updated with zooming the plot with the navigation toolbar...until it gets down to the level of hours. Hours are by default displayed in a format like: 23:00:00 UTC. How can I get it to display it in a more common way, such as 11:00 pm, or better, 11 pm, 3/15? something like: # init figures fig = figure() ax = fig.add_subplot(111) # plot the lines ax.plot_date(...) # x data (dates) formatter ax.xaxis.set_major_formatter( DateFormatter('PUT YOUR FORMAT HERE') ) Cheers, -- Sandro Tosi (aka morph, morpheus, matrixhasu) My website: http://matrixhasu.altervista.org/ Me at Debian: http://wiki.debian.org/SandroTosi -- ___ Matplotlib-users mailing list Matplotlib-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-users
Re: [Matplotlib-users] imread() and PNGs
Tobias Wood [...] These have thrown up an interesting issue - to what maximum value should n-bit images be scaled when n is between 8 and 16? The png spec and test images suggest it should be (2^n - 1). This means that higher bit depths give higher precision over the same intensity range and the same maximum value. However for my particular camera and software this would be wrong, as the CCD has a fixed 12-bit dynamic range and the lower png bit depths are only used to save file space. Hence at the moment I have set my software to scale to (2^16 - 1) for 8 n 16, but it follows the png spec for n 8, so there are two contradictory behaviours and I am unsure which is the best approach. Personally I would prefer matplotlib to return raw integer values, not floats scaled between 0 and 1 and then I can apply the scaling myself, but I am aware that this is not particularly user friendly for anyone else. imshow() seems to handle integer values fine and correctly scales for display, provided that no alpha channel is present. In the past I worked on a similar problem, saving and loading images from a 14bit monochrome CCD camera to a PNG file. The PNG specification gives precise recommondations how to handle such a case: for saving an n-bit image which is not directly supported by the PNG specs the image needs to be scaled up to one of the supported bit depths, i.e. 1,2,4,8 or 16. The original bit depth should be stored in the sBIT chunk to recover the original data. Explicitely, a 12 bit image needs to be scaled by a factor (2^16 - 1)/(2^12-1). The approach I have chosen is: I have png_save_image(filename, img, significant_bits) that behaves as specified in the specs, i.e., 14bit images are scaled up to 16bit. For loading an image I use img, metadata = png_load_image(filename) that returns the downscaled image as an integer array and a dict containing some metadata (which includes the original bit depth). I also noticed that neither pnglib, PIL nor matlab perform this downscaling. With this approach the loaded image data is identical to the original raw image. For further processing I typically normalize the image to the range 0 to 1.0, using the bit depth information. A float array is sufficiently precise, also for 16bit images. For your enhancements to imread, introducing a new keyword 'normalized' would allow to switch between both these possibilies.As I understand I have essentially chosen the same approach like you, at least for bitdepths 8. I didn't get the point what is different for bitdepth s=8. Another remark to your first posting: I didn't experience a problem with PIL to load 16bit PNG grayscale images. I also noticed you used C++ constructs in your code. I think this is not recommended. Gregor -- ___ Matplotlib-users mailing list Matplotlib-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-users
Re: [Matplotlib-users] imread() and PNGs
Gregor Thalhammer wrote: Tobias Wood [...] [...] I also noticed you used C++ constructs in your code. I think this is not recommended. Gregor, Would you elaborate, please, to satisfy my curiosity? The original file is C++, so use of C++ constructs in the patch would seem natural. Thank you. Eric -- ___ Matplotlib-users mailing list Matplotlib-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-users
Re: [Matplotlib-users] imread() and PNGs
Tobias Wood wrote: Tobias, I would like to apply your patch, but the test in examples/tests/pngsuite fails. If you can submit a new patch where this test passes, and, even better, if a small example 12-bit PNG of yours is added to the test, I will apply it. Apart from that, I would echo Eric's thanks for the patch and explanation. -Andrew Hi Andrew and Eric, Thanks for the responses. I was unaware of the png test suite. I have attached a new diff that passes this test correctly. It originally failed because I was not handling greyscale images with an alpha channel, but it also brought to light several other issues with my code that I have fixed. I have changed the structure of the code significantly - the if/else struct has gone and a single loop returns the different image matrices. Although this is more concise, it no longer informs the user if it hits an unsupported image type. Unfortunately I do not have a small test image available, all of ours are a minimum of 512x620. However the pngsuite page, http://libpng.org/pub/png/pngsuite.html, does have a set of suitable images labelled cs*n*.png. These have thrown up an interesting issue - to what maximum value should n-bit images be scaled when n is between 8 and 16? The png spec and test images suggest it should be (2^n - 1). This means that higher bit depths give higher precision over the same intensity range and the same maximum value. However for my particular camera and software this would be wrong, as the CCD has a fixed 12-bit dynamic range and the lower png bit depths are only used to save file space. Hence at the moment I have set my software to scale to (2^16 - 1) for 8 n 16, but it follows the png spec for n 8, so there are two contradictory behaviours and I am unsure which is the best approach. Personally I would prefer matplotlib to return raw integer values, not floats scaled between 0 and 1 and then I can apply the scaling myself, but I am aware that this is not particularly user friendly for anyone else. imshow() seems to handle integer values fine and correctly scales for display, provided that no alpha channel is present. Should I post another message to the developer list about this to see what people think? I'd very much like to discuss this with someone who has a lot more experience of pngs than me. Tobias, I went ahead and applied your patch to the svn trunk and the 0.98.5 maintenance branch -- the aspect of having grayscale images come in as 2d arrays brings the functionality inline with the docstring to imread(), so it qualifies as a bug fix. The rest is a nice feature addition (the ability to read high dynamic range PNGs) that I think is unlikely to break anything. As for your questions, I think they can be addressed later. (I hope you maintain your interest in this subject.) In particular, it would be good to get Michael Droetboom's responses on this -- he's the resident PNG expert. In terms of the 8 n 16 bit PNG issue, if they are to be stored as integers, they will have to be stored in 16 bits, thus there are two reasonable ways to do it -- left shifted and right shifted. There are arguments for both. Thus, my opinion is that adding keyword arguments to imread() that would modify the current behavior appropriately would be the best solution. In other words, something like return_as_integer=False, integer_shift='left' would be the defaults. Next time you submit patches, I do think it would be best to submit to the mpl-dev email list. Anyhow, thanks for the patch! -Andrew -- ___ Matplotlib-users mailing list Matplotlib-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-users