bugGNU Octave - Bugs: bug #45565, Using imwrite to write an 8-bit...

 
 

bug #45565: Using imwrite to write an 8-bit image to BMP creates a 24-bit image

Submitter:  Ian Journeaux <ijourneaux>
Submitted:  Thu 16 Jul 2015 10:10:29 PM UTC
   
 
Category:  Octave Function Severity:  3 - Normal
Priority:  5 - Normal Item Group:  Matlab Compatibility
Status:  Fixed Assigned to:  None
Originator Name:  Ian Journeaux Open/Closed:  * Closed
Release:  * dev Operating System:  * Any
Fixed Release:  None Planned Release:  None
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Mon 17 Aug 2015 01:59:17 PM UTC, comment #25: 

Done. Created a new but report.

Ian Journeaux <ijourneaux>
Mon 17 Aug 2015 01:31:37 PM UTC, comment #24: 

Can we keep this bug report on topic?

The fix that was made was to create uncompressed BMP files instead of RLE-compressed BMP files, and that is now working as you've confirmed when you specify a colormap to force the image to be an indexed image.

Your additional observation that the file should be an 8-bit indexed grayscale file when the input is a uint8 was not addressed by the fix made so far. That is an additional change where it appears that Matlab is creating indexed files depending on the image type and the input matrix type. Perhaps a new bug report to keep the discussion from getting confused?

There is nothing wrong with your compilation.

Mike Miller <mtmiller>
Group Member
Mon 17 Aug 2015 12:59:44 PM UTC, comment #23: 

It doesn't appear like the changes to _magick_read_.cc are in the file mxe-octave/pkg/octave-4.1.0+.tar.gz.

Is that normal? If it is, what might the procedure be to update the ...tar.gz files used in the MXE build?

Ian Journeaux <ijourneaux>
Mon 17 Aug 2015 07:34:43 AM UTC, comment #22: 


>I can see the changes to imwrite from this bug fix so I should have a good compile of Octave but this is a fresh compile so maybe there is a problem with the compilation.


If you want to check the sources that were complied in mxe build, you can get an archive file: mxe-octave/pkg/octave-4.1.0+.tar.gz.

Tatsuro MATSUOKA <tmacchant>
Mon 17 Aug 2015 03:40:02 AM UTC, comment #21: 

Carne
I was able to compile up Octave 4.1.0+ (MXE) so I could test the fix on my system.

This seems to work as it should, creating an 8-bit BMP file.

octave> img = uint8 (ones (100, 1) .* [0:255]);
octave> map = gray(256);
octave> imwrite (img, map, "foo-octave.bmp");

If I understand Matlab (maybe I am misinterpreting Matlab)
 
octave> img = uint8 (ones (100, 1) .* [0:255]);
octave> imwrite (img, "foo-octave.bmp");

should also work but, with Octave, still produces a 24-bit image.

I can see the changes to imwrite from this bug fix so I should have a good compile of Octave but this is a fresh compile so maybe there is a problem with the compilation.

Ian Journeaux <ijourneaux>
Tue 28 Jul 2015 04:49:23 PM UTC, comment #20: 

Small correction from my last message, Matlab only supports compressino option for HDF4 format.

Carnë Draug <carandraug>
Group Member
Tue 28 Jul 2015 04:48:33 PM UTC, comment #19: 

Fixed with http://hg.savannah.gnu.org/hgweb/octave/rev/5b8e4f668c53

This adds the compression option to imwrite while defaulting to none. It seems that Matlab only supports the compression method for the jpeg format but this change adds it for a bunch of other formats. If the GM coder does not support it, it defaults to whatever GM wants to do. For example, RLE compression of bmp files only works for indexed images.

Carnë Draug <carandraug>
Group Member
Sat 25 Jul 2015 04:18:41 AM UTC, comment #18: 

Thanks for confirming Mike

Ian Journeaux <ijourneaux>
Fri 24 Jul 2015 11:01:24 PM UTC, comment #17: 

Confirmed with Matlab that imwrite creates an uncompressed 8-bit-per-pixel BMP file when the array is of type uint8, no need to specify a colormap. Also confirmed that Matlab creates an uncompressed 1-bit-per-pixel BMP image when the array is logical. In both cases the file is an indexed image file with implicit grayscale colormaps.

Updating to confirmed and Matlab compatibility.

Mike Miller <mtmiller>
Group Member
Fri 24 Jul 2015 09:49:58 PM UTC, comment #16: 

So I analyzed the BMP header fields more closely and found that Octave creates a BMP using RLE compression by default, while the file you have attached that you say works is not using any compression. This agrees with the info I saw from PIL.

So my simple thought at this point is that Octave needs to tell GraphicsMagick to write uncompressed BMP files, if GraphicsMagick exposes that knob and allows a way for Octave to set that. This seems like a Matlab compatibility item, based on https://www.mathworks.com/help/matlab/ref/imwrite.html saying that BMP files are always uncompressed.

This is independent of whether imwrite with a uint8 argument should write 8-bit BMP files by default or whether it requires a colormap argument. I can't decipher Matlab's help page for imwrite to figure out if that's a separate compatibility issue.

Mike Miller <mtmiller>
Group Member
Fri 24 Jul 2015 05:19:00 AM UTC, comment #15: 

When I open the attached images, I see the following from GraphicsMagick:


$ gm identify *bmp
D2801fullsize_Created by Octave.bmp BMP 480x480+0+0 DirectClass 8-bit 675.1Ki 0.000u 0:01
D2801fullsize_Saved by ImageJ.bmp[1] BMP 480x480+0+0 PseudoClass 256c 8-bit 226.1Ki 0.000u 0:01
foo-octave.bmp[2] BMP 256x100+0+0 PseudoClass 256c 8-bit 51.2Ki 0.000u 0:01


So GraphicsMagick sees D2801fullsize_Saved by ImageJ.bmp and foo-octave.bmp both as 8-bit 256-color indexed images.

But checking out these files with Python PIL gives differences:


D2801fullsize_Created by Octave.bmp: BMP 480x480 RGB {'dpi': (75, 75), 'compression': 0} [('raw', (0, 0, 480, 480), 54, ('BGR', 1440, -1))]
D2801fullsize_Saved by ImageJ.bmp: BMP 480x480 L {'dpi': (0, 0), 'compression': 0} [('raw', (0, 0, 480, 480), 1078, ('L', 480, -1))]
foo-octave.bmp failed: Unsupported BMP compression (1)


If I create a new BMP file with Octave the same size as the working D2801fullsize_Saved by ImageJ.bmp (480x480) with


octave:1> x = uint8 (randi ([0, 255], 480, 480));
octave:2> imwrite (x, gray (256), "foo.bmp");
octave:3> whos
Variables in the current scope:

   Attr Name        Size                     Bytes  Class
   ==== ====        ====                     =====  =====
        x         480x480                   230400  uint8

octave:4> system ("ls -l foo.bmp");
-rw-r----- 1 mike mike 461076 Jul 24 01:06 foo.bmp


Don't know why but the saved file is twice the size of the matrix in memory. The gm utility still claims that it contains 8-bit pixels.

Mike Miller <mtmiller>
Group Member
Mon 20 Jul 2015 04:00:41 PM UTC, comment #14: 

Attached foo-octave.bmp which , under Windows has a bit depth of 32

(file #34469)

Ian Journeaux <ijourneaux>
Mon 20 Jul 2015 03:26:15 PM UTC, comment #13: 

Can you also attach foo-octave.bmp that doesn't work for you, as created with imwrite(img, map, "foo-octave.bmp")?

Mike Miller <mtmiller>
Group Member
Mon 20 Jul 2015 03:19:33 PM UTC, comment #12: 

Thanks Carne for looking at this.

It seem that this must be related to Octave under Windows.

When I execute ( I am not sure how to insert of code block in the comment)

octave> img = uint8 (ones (100, 1) .* [0:255]);
octave> map = gray(256);
octave> imwrite (img, map, "foo-octave.bmp");
octave> exit

The resulting image has a bit depth of 32 and when I try and open it in ImageJ I get a "Compression Not Supported" error. 32 is an odd bit depth.

Executing

octave> imwrite (img, "foo-octave.bmp");

produces and image with a bit depth of 24.

Ian Journeaux <ijourneaux>
Mon 20 Jul 2015 09:27:20 AM UTC, comment #11: 

Also, I have reported the bug I mentioned on comment #5 against bioformats.

Carnë Draug <carandraug>
Group Member
Fri 17 Jul 2015 02:38:35 PM UTC, comment #10: 

Mike Miller solution works for me:


$ gm identify foo-8.bmp
foo-8.bmp BMP 256x100+0+0 PseudoClass 256c 8-bit 26.1Ki 0.000u 0:01

$ octave
octave> img = uint8 (ones (100, 1) .* [0:255]);
octave> map = gray(256);
octave> imwrite (img, map, "foo-octave.bmp");
octave> exit

$ gm identify foo-octave.bmp
foo-octave.bmp BMP 256x100+0+0 PseudoClass 256c 8-bit 51.2Ki 0.000u 0:01


Carnë Draug <carandraug>
Group Member
Fri 17 Jul 2015 02:31:41 PM UTC, comment #9: 

Here are a couple of images I am actually working work.

The file "D2801fullsize_Saved by Octave" was an 8bit image saved by Octave using imwrite with a gray map.

The file "D2801fullsize_Saved by ImageJ" was the same file opened in ImageJ converted to 8bit and saved.

In the application I am using, the Octave image gives and Image Size Error while the ImageJ version works correctly.

(file #34458, file #34459)

Ian Journeaux <ijourneaux>
Fri 17 Jul 2015 02:16:53 PM UTC, comment #8: 

Certainly. Appreciate the help.

I have uploaded 2 image a "correct" 8-bit BMP image (created by ImageJ) and RGB image created by imwrite in Octave using

imwrite (ind2gray (a, map), "foo.bmp");

It looks like the imwrite is creating all three channels even when there is only one.

(file #34456, file #34457)

Ian Journeaux <ijourneaux>
Fri 17 Jul 2015 01:34:04 PM UTC, comment #7: 

Ian, can you post an example of an 8-bit BMP that works with the application you are targeting? That may help give an idea of what you're trying to achieve.

Do you know if the application expects each 8-bit pixel to represent a color (or grayscale) value or rather an index into a color table? That would also be useful information.

Mike Miller <mtmiller>
Group Member
Fri 17 Jul 2015 01:25:03 PM UTC, comment #6: 

Although that allows it to be opened in ImageJ, the image, when opened in ImageJ, is an RGB Image. The application I an trying to use the images in requires a 8 bit BMP file.

I was just using ImageJ to test the image.

Ian Journeaux <ijourneaux>
Fri 17 Jul 2015 01:11:59 PM UTC, comment #5: 

Actually, if you enable ImageJ's SCIFIO2, or use the bioformats importer, then ImageJ will open the file.

However, you can use the following which works fine in ImageJ, even when using plain ImageJ 1.


octave> a = repmat (uint8 (0:255), 100, 1);
octave> img = uint8 (ones (100, 1) .* [0:255]);
octave> map = rainbow (256);
octave> imwrite (ind2rgb (img, map), "foo.bmp");


Carnë Draug <carandraug>
Group Member
Fri 17 Jul 2015 12:59:59 PM UTC, comment #4: 

The program that the images are destined for requires 8bit bmp files

I was hoping the solution proposed by Mike would work but when I try to open the saved image in ImageJ, I get a "Compression Not Supported" error so there is something wrong with the file created that way.

Although I wouldn't know for sure that BMP files are always supposed to be indexed images, I have always been able to save the images as 8bit bitmpas in other programs.


Ian Journeaux <ijourneaux>
Fri 17 Jul 2015 10:21:51 AM UTC, comment #3: 

This bug (or lack of it), may be dependent on the version of Graphics Magick installed.

I can see a bug with it but different from the one originally reported:


octave> a = repmat (uint8 (0:255), 100, 1);
octave> imwrite (a, "test.bmp");
octave> [b, c, d] = imread ("test.bmp");
octave> whos
Variables in the current scope:

   Attr Name        Size                     Bytes  Class
   ==== ====        ====                     =====  =====
        a         100x256                    25600  uint8
        b         100x256                    25600  uint8
        c           0x0                          0  double
        d           0x0                          0  double


If a bmp file is always an indexed image (is this true?), then it should have returned a colormap.

Carnë Draug <carandraug>
Group Member
Fri 17 Jul 2015 02:50:27 AM UTC, comment #2: 

Thanks for your bug report. AFAICT this is working correctly. If I understand the BMP file format correctly, 8-bit BMP files are indexed images. To create an indexed image with imwrite, you must specific a colormap (palette) argument.

For example, this creates an 8-bit BMP file for me:


octave:1> img = uint8 (ones (100, 1) .* [0:255]);
octave:2> map = rainbow (256);
octave:3> imwrite (img, map, "foo.bmp");


Am I understanding this correctly?

Mike Miller <mtmiller>
Group Member
Thu 16 Jul 2015 10:15:57 PM UTC, comment #1: 

When trying to write an 8-bit image to a BMP file,  the image ends up as a 24-bit image. This is not a problem with jpg and tif file format.

a = repmat (uint8 (0:255), 100, 1);
imwrite (a, "test.jpg");
imwrite (a, "test.tif");
imwrite (a, "test.bmp");

Ian Journeaux <ijourneaux>
Thu 16 Jul 2015 10:10:29 PM UTC, original submission:  


Ian Journeaux <ijourneaux>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

Attached Files
file #34469:  foo-octave.bmp added by ijourneaux (51KiB - image/bmp)
file #34456:  foo 8bit.bmp added by ijourneaux (26KiB - image/bmp)
file #34457:  foo 24bit.bmp added by ijourneaux (75KiB - image/bmp)

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by tmacchant (Posted a comment)
  • -email is unavailable- added by mtmiller (Posted a comment)
  • -email is unavailable- added by ijourneaux (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only group members can vote.

     

    Follow 14 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2015-07-28 carandraug StatusConfirmed Fixed
        Open/ClosedOpen Closed
    2015-07-24 mtmiller Item GroupIncorrect Result Matlab Compatibility
        StatusWorks For Me Confirmed
        SummaryUsing imwrite to write an 8-bit iamge to BMP creates a 24 bit image Using imwrite to write an 8-bit image to BMP creates a 24-bit image
    2015-07-20 ijourneaux Attached File- Added foo-octave.bmp, #34469
    2015-07-17 ijourneaux Attached File- Added D2801fullsize_Saved by ImageJ.bmp, #34458
        Attached File- Added D2801fullsize_Created by Octave.bmp, #34459
    2015-07-17 ijourneaux Attached File- Added foo 8bit.bmp, #34456
        Attached File- Added foo 24bit.bmp, #34457
    2015-07-17 carandraug Release4.0.0 dev
    2015-07-17 mtmiller CategoryNone Octave Function
        StatusNone Works For Me
        Operating SystemMicrosoft Windows Any

    Back to the top

    Powered by Savane 3.13-02a9.
    Corresponding source code