Message Boards Message Boards

0
|
8200 Views
|
11 Replies
|
4 Total Likes
View groups...
Share
Share this post:

Graphics dimensions unexpected in 12.1

Posted 4 years ago

A code for data analysis in use in version 12.0 throws errors in version 12.1. I tracked the issue to version 12.1 generating graphics which appear to have an incorrect dimension . Below are two code segments with the same code executed in the two versions.

Version 12.0 produces a 2048x2048 image as expected:

$Version

(* "12.0.0 for Microsoft Windows (64-bit) (April 6, 2019)" *)

disk = Graphics[{Black, Disk[{985, 1030}, 600]}, 
   ImageSize -> {2048, 2048}];

ImageDimensions[disk]

(* {2048,2048} *)

For some reason, the same code in 12.1 produces a 3414x3414 image:

$Version

(* "12.1.0 for Microsoft Windows (64-bit) (March 14, 2020)" *)

disk = Graphics[{Black, Disk[{985, 1030}, 600]}, 
   ImageSize -> {2048, 2048}];

ImageDimensions[disk]

(* {3414,3414} *)

Does anyone have any insight into this? I have reported the issue to tech support and reverted to 12.0 for this work.

POSTED BY: David Keith
11 Replies

In response to the large number of questions on this topic on the Wolfram Community, on StackExchange, and through Wolfram Technical Support, we have published a support article describing these changes, and their rationale, at

https://support.wolfram.com/50417

Thanks for the link! Of course the HiDPI support and proper ImageResolution support from Image are great improvements.

To be clear, my criticism was aimed at the fact that the default rasterization (Rasterize) resolution depends on the screen, so it will be different on every computer.

This means that the result "looks nice" if you're just playing around in a notebook, but things will break if you're trying to get work done, and e.g. take complex code you painstakingly developed and debugged on a laptop, and run it on a faster server.

The result of functions like Rasterize does not need to match what I see on the screen right now (because maybe that's different from what I'll see tomorrow). What I expect from such functions is to be dependable and predictable, and behave the same way every time.

POSTED BY: Szabolcs Horvát
Posted 4 years ago

I agree with Szabolcs. The last two releases have broken the same code for me. The first time it was due to changes in FITS image import. This time it’s changes to rasterization. I am trying to do real work and need more attention paid to quality assurance.

POSTED BY: David Keith

It is also depends on the OS. On my MacBook Pro

disk = Graphics[{Black, Disk[{985, 1030}, 600]}, 
   ImageSize -> {2048, 2048}];

ImageDimensions[disk]

returns

{4096, 4096}

So, different behaviors on different systems and different OSs certainly cause problems...

Posted 4 years ago

Thanks, Szabolcs. Makes perfect sense. And I agree about the automatic resolution. Things just work . . .until they don't.

POSTED BY: David Keith

What was a really bad design decision for M12.1, at least in my opinion, is that they made the default resolution dependent on the system on which Mathematica is running. The default resolution can change just because you plugged in a screen.

People who do things like what you describe (e.g. create image masks with Graphics, which I also do) will certainly run into problems. Code that runs on one machine will fail on another. Code that ran yesterday will not run today, and people will not know that it's because they just plugged in a screen. Sure, we can set $ImageResolution, but one has to know that this is possible. $ImageResolution is even Protected, which is usually an indication that "this thing should not be set".

Overall, it's just a very bad user experience, and it will make Mathematica look like an unreliable system.

What is ironic is that presumably the automatic resolution switching (to match your screen) was implemented to make things "just work", but it is having the opposite effect: it makes things not work, in a way that will certainly appear mysterious to many users.

BTW I did complain about this during the prerelease period.

POSTED BY: Szabolcs Horvát

I understand what you are doing, I am doing the same thing and adapting to this chance was annoying ...

You can set $ImageResolution = 72 at the beginning of the session.

Alternatively, you can make all rasterization explicit, and set ImageResolution -> 72. This is some trouble because I also used to do things like Binarize@Graphics[Disk[],...] instead of using Rasterize explicitly.

I have not refactored all my code for this, but I was thinking of using something similar to the following:

rast[im_?ImageQ][gr_Graphics] :=
 Module[{w, h},
  {w, h} = ImageDimensions[im];
  Rasterize[
   Style[
    Show[gr, PlotRange -> {{0, w}, {0, h}}, ImageSize -> {w, h}],
    Antialiasing -> False
    ],
   "Image",
   ImageResolution -> 72
   ]
  ]

Then if we have an image image = RandomImage[{0.9, 1}, {100, 100}], we can rasterize corresponding masks as mask = rast[image][Graphics[Disk[{50, 50}, 50]]].

I am curious how others handle this.

POSTED BY: Szabolcs Horvát
Posted 4 years ago

Dear @Szabolcs and others,

I really would like a simple method of using drawing graphics primitives within an image of fixed size, where the image size and the dimensions of the primitives can be given in pixels -- not printed size. It would be nice if there were a simple built in method for working in pixels.

But here is a method I think might work with the tool as it is:

Use the white rectangle to force the graphic to set the bounds for the graphic, then write objects within those bounds.

g = Graphics[{White, Rectangle[{1, 1}, {100, 100}], Black, 
    Disk[{50, 50}, 30]}, AspectRatio -> Automatic];

r = Rasterize[g, ImageResolution -> 72, ImageSize -> {100, 100}]

disk

In[3]:= r // ImageData // Dimensions

Out[3]= {100, 100, 3}

In[4]:= (* {100,100,3} *)
POSTED BY: David Keith

I understand what you are doing, I am doing the same thing and adapting to this chance was annoying ...

You can set $ImageResolution = 72 at the beginning of the session.

Alternatively, you can make all rasterization explicit, and set ImageResolution -> 72. This is some trouble because I also used to do things like Binarize@Graphics[Disk[],...] instead of using Rasterize explicitly.

I have not refactored all my code for this, but I was thinking of using something similar to the following:

rast[im_?ImageQ][gr_Graphics] :=
 Module[{w, h},
  {w, h} = ImageDimensions[im];
  Rasterize[
   Style[
    Show[gr, PlotRange -> {{0, w}, {0, h}}, ImageSize -> {w, h}],
    Antialiasing -> False
    ],
   "Image",
   ImageResolution -> 72
   ]
  ]

Then if we have an image im = RandomImage[{0.9, 1}, {100, 100}], we can rasterize corresponding masks as mask = rast[image][Graphics[Disk[{50, 50}, 50]]].

I am curious how others handle this.

POSTED BY: Szabolcs Horvát

See my answer here:

https://mathematica.stackexchange.com/questions/219227/unexpected-behaviour-of-imagesize-and-imagedimensions-in-12-1/

Note that ImageDimensions works on Image and not on Graphics. When you apply it to graphics, they get implicitly Rasterized. 12.1 may rasterize at higher resolution, depending on the screen you have connected.

POSTED BY: Szabolcs Horvát
Posted 4 years ago

Thank you, @Szabolcs. I clearly did not understand how image dimensions relate to graphics in this case. Let me ask, please, if there is a good way to do what I am trying accomplish. I want to extract the data from a target image which corresponds to pixels identified by a convenient to construct mask having the same dimensions as the target image data. In the method which is broken (and perhaps it only worked accidentally), I try to construct the mask by generating an image using graphics primitives. I then use that mask to extract data from the target image. In this case I find the positions of all pixels having value 1, and use that list of positions with Extract to extract the data.

This worked before because my use of Graphics did generate an image of the needed dimensions. But that appears to have been an accident. It there a way to design an image with specific dimensions. For example, an image which would have ImageData dimensions 2048x2048 with a filled disk centered at {1000,1000} with a disk radius of 500, All dimensions being in pixels of ImageData. I can picture ways to do this with direct calculations for the value of each element in an array, but that is not as convenient as working with graphics primitives.

Best regards, David

POSTED BY: David Keith
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract