14
$\begingroup$

Bug persisting through 13.0.0 [CASE:4896512]


If I upload this image (originally this img was generated by EdgeDetect) by normal workflow here, this phenomenon will disappear. So I had to wrap all img information in code to make sure the problem would be reproduced.

img=Uncompress[FromCharacterCode[Flatten[ImageData[Import["https://i.stack.imgur.com/SOOi1.png"],"Byte"]]]];
Show[img,Axes->True]

enter image description here

But note the dimensions:

ImageDimensions[img]

{709, 251}

Apparently, I got a wrong coordinate system, which will cause a scaling effect on the coordinates of the results identified by some functions (such as ComponentMeasurements). I had to do this to avoid this mistake:

Show[Image[ImageData[img]], Axes -> True]

enter image description here

I am currently on version 13, why do I have this problem? Is this a bug?

$\endgroup$
1
  • 1
    $\begingroup$ It gives the same in 12.3.1 $\endgroup$
    – Rom38
    Jan 15 at 10:48

1 Answer 1

16
$\begingroup$

I reproduce the issue with version 13.0.0 on Windows 10 x64.

Apparently, the issue arises due to a non-default value of ImageResolution option of img:

Options[img, ImageResolution]
{ImageResolution -> {96., 96.}}

Setting this option to Automatic:

Show[Image[img, ImageResolution -> Automatic], Axes -> True]

output

Options[%, PlotRange]
{PlotRange -> {{0, 709.}, {0, 251.}}}

According to "Details" section of the Documentation page for ImageResolution,

The default setting ImageResolution->Automatic typically uses a resolution of 72 dpi for bitmap graphics formats.

Let us check:

Show[Image[img, ImageResolution -> {72, 72}], Axes -> True]
Options[%, PlotRange]

output

{PlotRange -> {{0, 709.}, {0, 251.}}}

We have got exactly the same data inside of the Graphics object. The only exception is that inside of Raster now we have explicit value of the ImageResolution option (which isn't a documented option for Raster!):

Show[Image[img, ImageResolution -> {72, 72}], Axes -> True] // 
 ResourceFunction["ShortInputForm"]

screenshot

But for what this options is kept inside of Raster? Let us check how the backward conversion to Image works:

Show[Image[img, ImageResolution -> {72, 72}], Axes -> True] // First // Image // Options
{ColorSpace -> "RGB", ImageResolution -> {72, 72}, Interleaving -> True}

We see that the backward conversion algorithm uses this option and sets it for produced Image object.

The same happens for the original img:

Show[img] // First // Image // Options
{ColorSpace -> "RGB", ImageResolution -> {96., 96.}, Interleaving -> True}

Hence what you have found seems to be an undocumented feature of the Image to Graphics conversion algorithm. Whether this behavior is justified, I'm not sure.

As you show, this feature results in inconsistency when combining the results of image-processing functions like ComponentMeasurements with Graphics obtained by the above conversion method:

cm = ComponentMeasurements[Binarize[img], {"BoundingDiskCenter", "BoundingDiskRadius"}];
Show[img, Graphics[{Red, Circle @@@ Values[cm]}]]

output

This inconsistency is worth reporting to Wolfram. The above-described feature (I mean exactly PlotRange change upon ImageResolution change) is completely unnecessary for both Image to Graphics and Raster to Image conversion algorithms. I'm not sure for what it is introduced at all. In any case, worth reporting to Wolfram.

But notice that high-level HighlightImage doesn't have this feature:

hi = HighlightImage[img, Graphics[{Red, Circle @@@ Values[cm]}]]
Options[hi, {PlotRange, ImageSize, ImageSizeRaw}]

output

{PlotRange -> {{0, 709}, {0, 251}}, ImageSize -> {222., Automatic}, 
 ImageSizeRaw -> {531.75, 188.25}}
Image[hi] // Options
{ColorSpace -> "RGB", ImageResolution -> 96., Interleaving -> True}

As we see, HighlightImage not only correctly understands img coordinates, but also sets the option ImageSizeRaw for produced Graphics object. This option may be used later when converting the result back into Image for computing the original ImageResolution. Here is how it can be used:

ImageResolution -> (72 *#[[1, All, 2]]/#[[2]]) &@
 Values[Options[hi, {PlotRange, ImageSizeRaw}]]
ImageResolution -> {96., 96.}

(But currently, it isn't used and ImageResolution is taken directly from the Image embedded in produced Graphics as Inset! Notice also that the original ImageSize is lost when converting backward to Image!)

From these considerations we find another workaround:

HighlightImage[img, {}, Axes -> True]

output

Options[%, {PlotRange, ImageSize, ImageSizeRaw}]
{PlotRange -> {{0, 709}, {0, 251}}, ImageSize -> {222., Automatic}, 
 ImageSizeRaw -> {531.75, 188.25}}

But again, I don't think that this justifies the PlotRange change when converting an Image with non-default ImageResolution into a Graphics object using Show. I see no reason for this feature. Even HighlightImage doesn't change PlotRange, which seems more consistent than the current behavior of Show.


I've wrote a suggestion for improvement on this issue to the support [CASE:4896512]. Here is the response:

From your description, I gather you are noticing a regression with PlotRange getting changed per ImageResolution specifications for Image.

I checked and reproduced your issue, and have passed along a report to our developers on the same. We are always interested in improving Mathematica and wish to thank you for bringing this issue to our attention.

If you run into any other unexpected behavior with Mathematica, please do not hesitate to contact us in the future.

Hence the Wolfram support identifies this issue as a regression bug (I hadn't used such a term in my report).

$\endgroup$
13
  • $\begingroup$ Do you think I should add a bug tag to this post? $\endgroup$
    – yode
    Jan 15 at 11:54
  • $\begingroup$ @yode I don't think it is a bug. Looks like just an undocumented feature of the Image to Graphics (and backward) conversion algorithm. $\endgroup$ Jan 15 at 12:01
  • 1
    $\begingroup$ So do you think this is in line with the expected behavior? Show[img,Graphics[{Red,Circle@@@Values[ComponentMeasurements[Binarize[img],{"BoundingDiskCenter","BoundingDiskRadius"}]]}]] $\endgroup$
    – yode
    Jan 15 at 12:29
  • $\begingroup$ @yode This is a good example. I updated the answer with further thoughts. $\endgroup$ Jan 15 at 12:59
  • 2
    $\begingroup$ @yode As a side note and supplement, I'd like to point out that both the numbers 72 and 96 are kind of "hard-coded" into Windows, but they are meant for different concepts. Quote MSDN: "One logical inch equals 96 pixels. Using this scaling factor, a 72-point font is rendered as 96 pixels tall." Also note on Windows, because of compatibility, applications using different GUI frameworks end up having different scalings, which is a huge mess. $\endgroup$
    – Silvia
    Jan 17 at 20:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.