tongong.net

personal website
git clone https://tongong.net/git/tongong.net.git
Log | Files | Refs

index.html (10286B)


      1 <link rel="stylesheet" href="./styles.css"/>
      2 
      3 
      4 <h1>Interference effects on image zoom</h1>
      5 <p class="page-intro">
      6     A playful exploration into the world of image rendering.
      7 </p>
      8 <p>
      9     I recently discovered that pixel interference effects can occur by zooming
     10     in on gray image areas. This got me thinking: Can we construct an image
     11     that initially looks uniformly gray but reveals information on specific
     12     zoom levels? Is it maybe even possible to show different grayscale images
     13     depending on the zoom level?
     14 </p>
     15 <p>
     16     The following tests show client-side generated images using the
     17     <code>&lt;canvas&gt;</code> element. However the image data is not manipulated
     18     during zoom - just the CSS <code>transform: scale()</code> property changes.
     19     The demos need pixel perfect sizes to work. Therefore the images could be too
     20     small or too big on some devices - I apologize.
     21 </p>
     22 <p>
     23     Please also note that I do not have any prior knowledge in the field of
     24     image rendering. I was just playing around and documenting things I found
     25     interesting. I hope you find this little tour interesting as well :).
     26 </p>
     27 
     28 
     29 <h2>The interference effect</h2>
     30 <p>
     31     The first image is just a checkerboard pattern on pixel scale (this is
     32     clearly visible on <a class="demo1-checker">2x</a>). When zooming in the
     33     image pixel grid and the screen pixel grid are misaligned creating
     34     interference effects in both dimensions. They are especially strong in the
     35     area of
     36     <a class="demo1-checker">0.5x</a>,
     37     <a class="demo1-checker">0.25x</a>,
     38     <a class="demo1-checker">0.1667x</a> and
     39     <a class="demo1-checker">0.125x</a>.
     40     These turn out to be the whole number parts of 1/2. This makes sense: For
     41     two adjacent screen pixels the distance of the image pixels is a multiple
     42     of 2 which locally creates a uniformly colored area.
     43 </p>
     44 <!-- demo1-checker -->
     45 <div class="js-container">
     46     [If you see this text your browser unfortunately does not support
     47     Javascript.]
     48 </div>
     49 <p>
     50     Another observation about browser differences can be made here: In Chromium
     51     I can zoom smoothly at this microscopic scale, Firefox only allows zoom
     52     steps. Interestingly for every zoom step the image size is an integer
     53     multiple of 1/2 of the interference period. I do not know why. Also on
     54     Firefox for Android there are graphic glitches across the whole screen for
     55     some zoom levels. I guess this is a graphics driver issue of my device but
     56     I am not sure.
     57 </p>
     58 <p>
     59     On Chromium the image is completely black on some zoom levels like
     60     <a class="demo1-checker">0.5x</a>. However this bug does not occur when
     61     opening the image in a new tab and zooming to
     62     <a class="demo1-checker">0.5x</a>.
     63 </p>
     64 <p>
     65     For the second test I inverted the checkerboard pattern for some areas of
     66     the image. There are zoom levels like <a class="demo2-checkerinvert">1x</a>
     67     where just parts of the border of the shape are visible. For other zoom
     68     levels like <a class="demo2-checkerinvert">0.5x</a> the whole shape area is
     69     clearly visible.
     70 </p>
     71 <!-- demo2-checkerinvert -->
     72 <div class="js-container">
     73     [If you see this text your browser unfortunately does not support
     74     Javascript.]
     75 </div>
     76 
     77 
     78 <h2>Other types of colorings</h2>
     79 <p>
     80     Let's explore some other types of local colorings. I chose uniform gray and
     81     random pixel values for the next demo. As expected the gray area does not
     82     show any interference effects at all. The random area on the other hand has
     83     them but they are hardly visible. You can see them if you keep the rough
     84     slider at <a class="demo3-grayrandom">1x</a> and just move the fine slider.
     85 </p>
     86 <!-- demo3-grayrandom -->
     87 <div class="js-container">
     88     [If you see this text your browser unfortunately does not support
     89     Javascript.]
     90 </div>
     91 <p>
     92     Now let's combine different types of colorings. The random noise seems to
     93     be too different but a combination of checkerboard and gray could work. It
     94     does in fact: For <a class="demo4-checkergray">0.999x</a> the difference is
     95     just barely visible on Firefox and invisible on Chromium.
     96 </p>
     97 <!-- demo4-checkergray -->
     98 <div class="js-container">
     99     [If you see this text your browser unfortunately does not support
    100     Javascript.]
    101 </div>
    102 <p>
    103     To hide the remaining interference artifacts we bring the random noise back
    104     and add it to our color values. Now things start to get really interesting.
    105     Let's just look at the zoom levels
    106     <a class="demo5-checkergrayrandom">0.999x</a> and
    107     <a class="demo5-checkergrayrandom">0.5x</a> for the next two demos.
    108 </p>
    109 <p>
    110     On <a class="demo5-checkergrayrandom">0.5x</a> the square is sometimes
    111     visible and sometimes invisible. After a bit of testing I found out that it
    112     depends on the parity of the image width. I cannot explain it but I also do
    113     not find it implausible that these interference effects change drastically
    114     on size parity.
    115 </p>
    116 <p>
    117     The real weirdness starts on <a class="demo5-checkergrayrandom">0.999x</a>.
    118     On Firefox the square is visible for images smaller or equal to 500px in
    119     size and invisible for larger ones. I suppose Firefox uses different
    120     rendering techniques for different image sizes. On Chrome the square is
    121     visible if and only if it is also visible on
    122     <a class="demo5-checkergrayrandom">1x</a>
    123     - this means it is visible for even image sizes and invisible for odd
    124     sizes.
    125 </p>
    126 <!-- demo5-checkergrayrandom -->
    127 <div class="js-container">
    128     [If you see this text your browser unfortunately does not support
    129     Javascript.]
    130 </div>
    131 <!-- demo5-checkergrayrandom -->
    132 <div class="js-container">
    133     [If you see this text your browser unfortunately does not support
    134     Javascript.]
    135 </div>
    136 
    137 
    138 <h2>Invisibility on 1x</h2>
    139 <p>
    140     It would be really cool to create an image that is invisible on <a>1x</a>
    141     but appears on zoom. This did already work but just in Chromium. My first
    142     idea for this was to hide the interference area in a random area and match
    143     the grayscale level:
    144 </p>
    145 <div class="js-container">
    146     [If you see this text your browser unfortunately does not support
    147     Javascript.]
    148 </div>
    149 <p>
    150     This does work on Firefox on my specific screen. The difference is however
    151     visible in other browsers and on Firefox on other devices.
    152 </p>
    153 <p>
    154     To create a truly invisible interference area my next idea was to rearrange
    155     the pixels according to their color. This ensures equal color distribution
    156     inside and outside the interference area. It is however rather complicated
    157     to implement. The same effect can be achieved with random colors using
    158     uneven probabilities. For a dark pixel on the checkerboard we generate two
    159     random color values and take the smaller one. This is equivalent to
    160     imagining a neighboring light pixel and swapping their values if necessary.
    161 </p>
    162 <p>
    163     Now the effect really works consistent across devices and screens! Try
    164     zooming to <a class="demo6-reordering">0.5x</a> for example.
    165 </p>
    166 <!-- demo6-reordering -->
    167 <div class="js-container">
    168     [If you see this text your browser unfortunately does not support
    169     Javascript.]
    170 </div>
    171 <p>
    172     Now if we think in terms of probability distributions this process can be
    173     easily generalized from hidden black-and-white to grayscale images. Try the
    174     following example on <a class="demo7-reordering-grayscale">0.5x</a>.
    175     Unfortunately the interference patterns are only clearly visible in the
    176     center of the image as you can see at the end of the paint brush. (This is
    177     sometimes not the case on Chromium.)
    178 </p>
    179 <!-- demo7-reordering-grayscale -->
    180 <div class="js-container">
    181     [If you see this text your browser unfortunately does not support
    182     Javascript.]
    183 </div>
    184 <p>
    185     It would be really cool if the whole area could be used for hidden images.
    186     However i think that is impossible. There are always spots of destructive
    187     interference and for <a class="demo7-reordering-grayscale">0.5x</a> and its
    188     whole number parts these spots are already at the border of the image.
    189 </p>
    190 <p>
    191     Using the following file picker you can try the effect yourself. I respect
    192     your privacy so all images are processed client-side. You can check that in
    193     the network tab in the debugging tools of your browser. Please choose a
    194     square image - implementing and exploring other aspect ratios is left as an
    195     idea to the reader.
    196 </p>
    197 <!-- custom file upload -->
    198 <div class="js-container">
    199     [If you see this text your browser unfortunately does not support
    200     Javascript.]
    201 </div>
    202 
    203 
    204 <h2>Colored images</h2>
    205 <p>
    206     Since RGB displays have separate LEDs for the three color components this
    207     process should be easily generalizable to color images by just repeating it
    208     three times per pixel. It works, indeed
    209     (try <a class="demo8-color">0.5x</a>).
    210 </p>
    211 
    212 <!-- demo8-color -->
    213 <div class="js-container">
    214     [If you see this text your browser unfortunately does not support
    215     Javascript.]
    216 </div>
    217 <p>
    218     As above, you can try it yourself:
    219 </p>
    220 <!-- custom file upload 2 -->
    221 <div class="js-container">
    222     [If you see this text your browser unfortunately does not support
    223     Javascript.]
    224 </div>
    225 
    226 
    227 <h2>Ideas for future exploration</h2>
    228 <p>
    229     Many questions are left unanswered in this text. I chose to highlight some
    230     of them:
    231 </p>
    232 <ul>
    233     <li>What happens on aspect ratios different from 1:1?</li>
    234     <li>Is it possible to show different images on different zoom levels?
    235         If so, how?</li>
    236     <li>How can these phenomena be explained? Maybe explanations can be found
    237         in the source code of Firefox/Chromium or image rendering libraries.
    238         This is unfortunately beyond my abilities.</li>
    239 </ul>
    240 <p>
    241     That's enough for my curiosity. If you are still curious you can find the
    242     source code of this page <a href="/git/tongong.net/files.html">here</a>.
    243 </p>
    244 
    245 
    246 <h2>Thank you...</h2>
    247 <ul>
    248     <li>... <a href="https://mithril.js.org/">mithril.js</a> for keeping the
    249         fun in this project by abstracting over the Javascript DOM API</li>
    250     <li>... <a href="https://ciechanow.ski/">Bartosz Ciechanowski</a> for being
    251         a great inspiration</li>
    252     <li>... for reading :)</li>
    253 </ul>
    254 
    255 <script src="./main.js"></script>