<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Longcreek Blog</title>
    <description>Notes on physics, math and technology, particularly in microscopy and imaging with Python for calculations
</description>
    <link>https://longcreek.me/</link>
    <atom:link href="https://longcreek.me/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Wed, 24 Apr 2024 15:03:47 +0000</pubDate>
    <lastBuildDate>Wed, 24 Apr 2024 15:03:47 +0000</lastBuildDate>
    <generator>Jekyll v4.3.2</generator>
    
      <item>
        <title>Georeferencing Chernarus and visiting in real life 🗺️</title>
        <description>&lt;p&gt;In this post I will walk through how to&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Obtain a high-resolution raster map by stitching map tiles from a &lt;a href=&quot;https://en.wikipedia.org/wiki/Tiled_web_map&quot;&gt;tileserver&lt;/a&gt; with a &lt;a href=&quot;https://gitlab.com/-/snippets/2167748&quot;&gt;shell script&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Georeference a fictional map to a real location by manually matching features and their corresponding real locations using &lt;a href=&quot;https://www.qgis.org/&quot;&gt;QGIS&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Convert the georeferenced map to a Garmin compatible KMZ file with a &lt;a href=&quot;https://gitlab.com/kogens/gdal2custommap&quot;&gt;Python script&lt;/a&gt; using &lt;a href=&quot;https://pypi.org/project/GDAL/&quot;&gt;GDAL&lt;/a&gt; for use on a handheld GPS device.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I will apply it to the fictional map of &lt;a href=&quot;https://community.bistudio.com/wiki/Chernarus&quot;&gt;Chernarus&lt;/a&gt; which is based on a real area near Ústí nad Labem in Czechia. The end product is a georeferenced Garmin compatible &lt;a href=&quot;/assets/2021-09-01-chernarus-irl/chernarus.kmz&quot;&gt;KMZ file&lt;/a&gt; which you can put on your GPS handheld if you ever visit the area.&lt;/p&gt;

&lt;p&gt;The map below shows Chernarus (left) overlayed with the real region (right) - you can move the map and drag the slider to compare:&lt;/p&gt;

&lt;iframe width=&quot;100%&quot; height=&quot;500&quot; src=&quot;https://longcreek.me/leaflets/chernarus?center=50.705/14.082&amp;amp;collapseLayers=1&amp;amp;zoom=14&amp;amp;disableZoom=1&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Click &lt;a href=&quot;/chernarus-tilemap&quot;&gt;here&lt;/a&gt; for a full screen version of the map.&lt;/p&gt;

&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://armedassault.fandom.com/wiki/Chernarus&quot;&gt;Chernarus&lt;/a&gt; is a fictional country introduced in the game &lt;a href=&quot;https://en.wikipedia.org/wiki/ARMA_2&quot;&gt;Arma II&lt;/a&gt;, and the name of a large piece of terrain featured in the game spanning roughly 15x15 km. It was also the main location used in the &lt;a href=&quot;https://store.steampowered.com/app/224580/Arma_II_DayZ_Mod/&quot;&gt;DayZ mod&lt;/a&gt; which modified the game from a “military simulator” to a zombie survival game, which was later expanded&lt;sup id=&quot;fnref:itsinalpha&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:itsinalpha&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; into a &lt;a href=&quot;https://en.wikipedia.org/wiki/DayZ_(video_game)&quot;&gt;standalone game&lt;/a&gt; where new details and towns were added to the original terrain (known as Chernarus+).&lt;/p&gt;

&lt;!--
On the left below is a screenshot of the real [location in OpenTopoMap](http://127.0.0.1:4000/blog/2021/chernarus-irl), and on the right the whole region of Chernarus as seen in the games.

![Comparison of Chernarus with area around Ústi nad Labem](/assets/2021-09-01-chernarus-irl/map before.jpg)
--&gt;
&lt;p&gt;&lt;a href=&quot;https://dayz.ginfo.gg/chernarus/&quot;&gt;The map of Chernarus&lt;/a&gt; is closely based on an area in nothern Bohemia in Czechia, &lt;a href=&quot;https://opentopomap.org/#map=12/50.7215/14.1411&quot;&gt;between Ústí nad Labem and Děčín&lt;/a&gt; and appears very similar to the real location, as many of the real buildings are also appearing in the game. Some people in the community would occasionally post pictures comparing the game with the real location either by &lt;a href=&quot;https://imgur.com/a/Oeph3&quot;&gt;Google Street View&lt;/a&gt; or from &lt;a href=&quot;https://imgur.com/a/qecHz&quot;&gt;actual visits&lt;/a&gt; and note how familiar the place felt even though it was their first time there.&lt;/p&gt;

&lt;p&gt;The map can be even be georeferenced and overlayed on the real location quite accurately:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/chernarus-overlayed.jpg&quot; alt=&quot;Chernarus after georeferencing&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A few years ago I was in the area and decided to put the map on my GPS handheld and try to use it as reference while hiking around the area for fun.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/irl_gps_elektro.jpg&quot; alt=&quot;Novy Sobor IRL&quot; class=&quot;half-image center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It took a bit of effort and learning for me to get it working, and in this post I will walk through how I did it. The same process can be used for any map sufficiently similar to a real location, be it other fictional, historical or rare maps that you might have a copy of.&lt;/p&gt;

&lt;h2 id=&quot;download-and-stitch-high-resolution-map-from-a-tileserver&quot;&gt;Download and stitch high-resolution map from a tileserver&lt;/h2&gt;
&lt;p&gt;To obtain a high-resolution map of Chernarus, we are going to download tiles from a tileserver and stitch them together into one large map. A tileserver is a common way to serve maps for the web, where a large map is rendered as many small tiles, so we don’t have to load the full map. For this project I used the &lt;a href=&quot;https://dayz.ginfo.gg/chernarus/&quot;&gt;iZurvive Chernarus map&lt;/a&gt; as a source.&lt;/p&gt;

&lt;p&gt;The address for the tileserver is&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://maps.izurvive.com/maps/CH-Mod/1.7.9/tiles/${z}/${x}/${y}.png&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this format &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;${z}&lt;/code&gt; is the zoom level, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;${x}&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;${y}&lt;/code&gt; is the x and y integer tile coordinates, or simply the tile number.
Thus at zoom level &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;z=6&lt;/code&gt; (the highest of the server) the tile with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x=4&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y=3&lt;/code&gt; is found at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://maps.izurvive.com/maps/CH-Mod/1.7.9/tiles/6/4/3.png&lt;/code&gt; and looks like this&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/6-4-3.jpeg&quot; alt=&quot;Chernarus tile 6/4/3&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The whole map is split into pieces like this, and our goal is now to download all tiles for the Chernarus map and stitch them together.
To download all the tiles, I used &lt;a href=&quot;https://gitlab.com/-/snippets/2167748&quot;&gt;a shell script&lt;/a&gt; (modified from &lt;a href=&quot;https://gis.stackexchange.com/questions/73946/automatically-download-and-merge-webmap-tiles-into-one-big-image&quot;&gt;this question on GIS Stackexchange&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;First we download the tiles:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Extent of map&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;X1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
&lt;span class=&quot;nv&quot;&gt;X2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;50
&lt;span class=&quot;nv&quot;&gt;Y1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
&lt;span class=&quot;nv&quot;&gt;Y2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;42

&lt;span class=&quot;c&quot;&gt;# Zoom level&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;Z&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;6

&lt;span class=&quot;c&quot;&gt;# Iterate through tiles and download&lt;/span&gt;
TILE_URL &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; https://maps.izurvive.com/maps/CH-Mod/1.7.9/tiles/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Z&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.png
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;x &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;seq&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$X1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$X2&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
    for &lt;/span&gt;y &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;seq&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$Y1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$Y2&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
        &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Getting &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
        curl &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$TILE_URL&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Z&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;_&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;_&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.png &amp;amp;
    &lt;span class=&quot;k&quot;&gt;done
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;wait
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;done

&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Rename .png to .jpg as files are wrongly named&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;i &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; ./&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Z&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;_&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.png &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mv&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/.png/.jpg&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The images are actually JPEG files, despite the .png file extension, which is why they get renamed to .jpg file extension.&lt;/p&gt;

&lt;p&gt;To stitch the images together I use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;montage&lt;/code&gt; from &lt;a href=&quot;https://imagemagick.org/script/command-line-options.php#mode&quot;&gt;Imagemagick&lt;/a&gt;.
First we iterate through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; coordinates and for each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; we vertically stack all the relevant tiles from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Y1&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Y2&lt;/code&gt; together giving us a bunch of tall images&lt;sup id=&quot;fnref:montageerror&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:montageerror&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; x&amp;lt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$X2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; x++&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Stitching x=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
    montage &lt;span class=&quot;nt&quot;&gt;-mode&lt;/span&gt; concatenate &lt;span class=&quot;nt&quot;&gt;-tile&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;1x&quot;&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Z&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;_&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;_&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.jpg | &lt;span class=&quot;nb&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-Vr&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt; out_z&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Z&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;_x&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.jpg
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally we stack all of these images horizontally&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Stitching Everything together&quot;&lt;/span&gt;
montage &lt;span class=&quot;nt&quot;&gt;-mode&lt;/span&gt; concatenate &lt;span class=&quot;nt&quot;&gt;-tile&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;x1&quot;&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls &lt;/span&gt;out_z&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Z&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;_&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.jpg | &lt;span class=&quot;nb&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-V&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt; full_map.jpg&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If everything worked out, we now have a full map of Chernarus in high resolution on our hands!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/full_map_800px.jpg&quot; alt=&quot;Full stitched map of Chernarus&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;georeferencing-chernarus-to-real-life&quot;&gt;Georeferencing Chernarus to real life&lt;/h2&gt;
&lt;p&gt;The next step is to overlay the Chernarus map on the real life counterpart by referencing some points on the game map with the same points on the real map. These are known as Ground Control Ppoints (GCP). To do this, I am using &lt;a href=&quot;https://www.qgis.org/en/site/&quot;&gt;QGIS&lt;/a&gt;, a free and open source application for working with GIS (Geographical Information System) and the built in Georeferencer tool. Have a look at the &lt;a href=&quot;https://docs.qgis.org/3.16/en/docs/user_manual/working_with_raster/georeferencer.html&quot;&gt;QGIS documentation on Georeferencing&lt;/a&gt; for more details.&lt;/p&gt;

&lt;h3 id=&quot;adding-other-tilemaps-to-qgis&quot;&gt;Adding other tilemaps to QGIS&lt;/h3&gt;
&lt;p&gt;If you just installed QGIS you may want to add some more map sources, as only the standard Open Street Map tiles are provided by default. On the left panel, simply right click on “XYZ Tiles” and choose “New Connection”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/add_xyz_connection.jpg&quot; alt=&quot;Add XYZ connection&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the following dialogue you can add sources.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/opentopomap_connection.jpg&quot; alt=&quot;OpenTopoMap parameters&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I like to use the &lt;a href=&quot;https://opentopomap.org/&quot;&gt;OpenTopoMap&lt;/a&gt; for topographical maps at&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://tile.opentopomap.org/{z}/{x}/{y}.png&lt;/code&gt;, and &lt;a href=&quot;https://docs.microsoft.com/en-us/bingmaps/rest-services/directly-accessing-the-bing-maps-tiles&quot;&gt;Bing Aerial&lt;/a&gt; for satelite views at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://ecn.t3.tiles.virtualearth.net/tiles/a{q}.jpeg?g=1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can find more open tile servers &lt;a href=&quot;https://wiki.openstreetmap.org/wiki/Tile_servers&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now start a new project in QGIS and simply double click on the tilemaps you want to add them as a layer in the project.&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/add_layer_to_project.jpg&quot; alt=&quot;Add layer to project&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/first_layers.jpg&quot; alt=&quot;Add layer to project&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Since we are using a web map for reference we will set the Coordinate Reference System (CRS) of the project to the &lt;a href=&quot;https://en.wikipedia.org/wiki/Web_Mercator_projection&quot;&gt;Web Mercator projection&lt;/a&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EPSG: 3857&lt;/code&gt; so it renders properly. QGIS automatically sets the project CRS to be the same as the first layer added, but yo be sure you can set it by right clicking on the OpenTopoMap layer, then “Layer CRS” -&amp;gt; “Set project CRS from layer”. This should set the project CRS to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EPS 3857 - WGS 84 / Pseudo-Mercator&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: When we later transform the Chernarus map after georeferencing, it should be transformed into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EPSG: 4326&lt;/code&gt; if you want to use it on your Garmin device to show up properly.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/crs-from-layer.jpg&quot; alt=&quot;Set project CRS from OpenTopoMap CRS&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Zoom in on Ústí nad Labem (in north western Czechia, north of Prague) in preparation for the next step.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/usti-topo.jpg&quot; alt=&quot;Ústí nad Labem in OpenTopoMap&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;georeferencing-points&quot;&gt;Georeferencing points&lt;/h3&gt;
&lt;p&gt;In order to load the Chernarus map into QGIS we first convert it to a PNG&lt;sup id=&quot;fnref:jpg-in-qgis&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:jpg-in-qgis&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;, e.g. with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;convert&lt;/code&gt; from Imagemagick. Or just load it into &lt;a href=&quot;https://krita.org/&quot;&gt;your favourite image editor&lt;/a&gt; and save as PNG.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;convert full_map.jpg chernarus.png&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now open the Georeferencer with Raster -&amp;gt; Georeferencer&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/raster-georeferencer.jpg&quot; alt=&quot;Raster -&amp;gt; Georeferencer&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Load in the Chernaus map using Open raster (Ctrl+O), and it should look like this
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/open-raster.jpg&quot; alt=&quot;Chernarus map opened for georeferencing&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now comes the fun part! We need to find points on the Chernarus map which are identifiable on the real map. Press “Add point” (or Ctrl + A) to add points, and then click somewhere on the Chernarus map that you can recognize in the real map. It will ask you to enter map coordinates - if you press “From map canvas” you can now click on the corresponding point on the real map, and the coordinates will be filled out.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/enter-coords.jpg&quot; alt=&quot;GCP in Lipová&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This could e.g. be the T-junction in Stary Sobor (Lipová)&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/gcp-stary.jpg&quot; alt=&quot;GCP in Stary Sobor&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/gcp-stary-irl.jpg&quot; alt=&quot;GCP in Lipová&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Or the roads meeting at Topolka dam (just north of Povrly)&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/gcp-topolka.jpg&quot; alt=&quot;GCP near Topolka Dam&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/gcp-topolka-irl.jpg&quot; alt=&quot;GCP near Povrly&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Keep going until you have at least four points, preferably more - I’ve used 10-15 points for a good fit, making sure to put points near the map edges as well.&lt;/p&gt;

&lt;p&gt;Now open Transform Settings (yellow cogwheel) to set the parameters used for the georeferencing transform. After some experimenting I have chosen transformation type “Polynomial 2” and resampling method “Cubic” for the final transform, but feel free to see what works best for you. I suggest using “Nearest Neighbour” resampling to begin with, as it is the fastest so you can do adustments more easily.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want to use it on a Garmin device&lt;/strong&gt; you should set “Target SRS” to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EPSG:4326 - WGS 84&lt;/code&gt; as this is the standard map projection used in these devices (and for GPS in general), unless you want to fiddle with your devices projection settings.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/transformation-settings.jpg&quot; alt=&quot;Transformation settings&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.qgis.org/3.16/en/docs/user_manual/working_with_raster/georeferencer.html&quot;&gt;The Georeferencer documentation&lt;/a&gt; describes in more detail how the transformations work, and says the following about the Polynomial transforms:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The Polynomial algorithms 2-3 use more general 2nd or 3rd degree polynomials instead of just affine transformation. This allows them to account for curvature or other systematic warping of the image, for instance photographed maps with curving edges. At least 6 (respectively 10) GCP’s are required. Angles and local scale are not preserved or treated uniformly across the image. In particular, straight lines may become curved, and there may be significant distortion introduced at the edges or far from any GCPs arising from extrapolating the data-fitted polynomials too far.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you check “Load in QGIS when done” the georeferenced Chernarus map will automatically be added as a new layer in the project when done. The file will also be saved as a &lt;a href=&quot;https://en.wikipedia.org/wiki/GeoTIFF&quot;&gt;GeoTIFF&lt;/a&gt;, here named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chernarus_modified.tif&lt;/code&gt;, which is our georeferenced and transformed map.&lt;/p&gt;

&lt;p&gt;Once the transformation parameters have been set, QGIS will calculate a residual for each point. When calculating a polynomial transform, there are some mathematical constraints which means a point on the raster may not end up exactly on top of the point you referenced on the real map after the transform. The residual essentially tells you how far off each point will land from its target. Thus if one point has a much higher residual than the rest (I aim for less than 10 px in this case), you may want to correct it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/gcp-residuals.jpg&quot; alt=&quot;Residuals of GCPs&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now press “Start georeferencing” (green arrow or Ctrl + G) and wait for it to finish (takes about a minute on my laptop). If everything worked out, the Chernarus map should now be visible on top of the area around Ústí nad Labem&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/transformed-map.jpg&quot; alt=&quot;Chernarus overlayed on area around Ústí nad Labem&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In order to see both the real map and Chernarus map at once, you can open the layer style panel (F7) and chose “Blending mode” “Multiply”.
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/blending-multiply.jpg&quot; alt=&quot;Multiply blending for transparency&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;While the fit will never be perfect, you should be able to see most roads fairly well aligned to the real life counterparts. Otherwise try adjusting the GCP points and transformation parameters
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/blending-stary.jpg&quot; alt=&quot;Multiply blending for transparency&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/blending-gorka.jpg&quot; alt=&quot;Multiply blending for transparency&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;add-to-handheld-gps-garmin-gpsmap&quot;&gt;Add to handheld GPS (Garmin GPSMap)&lt;/h2&gt;
&lt;p&gt;If you have a Garmin GPS device you can add the georeferenced map if your device supports CustomMaps&lt;sup id=&quot;fnref:devicesupport&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:devicesupport&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;. I’m using a GPSMap 64s, but the steps should be similar for other devices.&lt;/p&gt;

&lt;p&gt;These devices don’t support GeoTIFFs directly, and we have to convert our newly made map into the Garmin CustomMap format. The format is a KMZ file, which uses raster map tiles with a &lt;a href=&quot;https://en.wikipedia.org/wiki/Keyhole_Markup_Language&quot;&gt;KML file&lt;/a&gt; to keep track of their positions. This means we have to convert our image back into tiles! The difference is of course that we have adjusted the map and can specify proper coordinates for the tiles.&lt;/p&gt;

&lt;h3 id=&quot;installing-gdal&quot;&gt;Installing GDAL&lt;/h3&gt;
&lt;p&gt;To convert the GeoTIFF I use the Python 3 script &lt;a href=&quot;https://gitlab.com/kogens/gdal2custommap&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gdal2custommap&lt;/code&gt;&lt;/a&gt;&lt;sup id=&quot;fnref:fork&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:fork&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;. You will need to install the &lt;a href=&quot;https://gdal.org/&quot;&gt;GDAL library&lt;/a&gt; as well as the python bindings found in the &lt;a href=&quot;https://pypi.org/project/GDAL/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GDAL&lt;/code&gt;&lt;/a&gt; package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linux&lt;/strong&gt;: If you are running some variant of Debian/Ubuntu it can be installed system wide with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo apt install python3-gdal&lt;/code&gt;, which will take care of the GDAL dependencies. If you are managing packages with e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pip&lt;/code&gt; you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python -m pip install GDAL&lt;/code&gt; (assuming &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python&lt;/code&gt; points to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python3&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows&lt;/strong&gt;: Assuming you have a working Python 3 installation on your machine, you will need to install GDAL and the Python bindings manually. This can be done with binaries found at &lt;a href=&quot;https://www.gisinternals.com/release.php&quot;&gt;GISInternals&lt;/a&gt;. Have a look at the python &lt;a href=&quot;https://pypi.org/project/GDAL/#windows&quot;&gt;GDAL package documentation&lt;/a&gt; for more details. After this, install the python &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GDAL&lt;/code&gt; package with Python Package manager of choice, e.g. &lt;a href=&quot;https://docs.conda.io/en/latest/&quot;&gt;Conda&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;convert-to-kmz-custommap&quot;&gt;Convert to KMZ (CustomMap)&lt;/h3&gt;
&lt;p&gt;If we have a georeferenced map of Chernarus named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chernarus_modified.tif&lt;/code&gt; we first convert it to tiles and an associated KML file with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gdal2kml.py&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python gdal2kml.py chernarus_modified.tif chernarus.kml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is possible to specify some options such as JPEG quality (defaults to 75), KML draw order etc, which is detailed in the &lt;a href=&quot;https://gitlab.com/kogens/gdal2custommap/-&quot;&gt;readme&lt;/a&gt; of the script. Next we use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kml2kmz.py&lt;/code&gt; to zip up all the files into a single KMZ file&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python kml2kmz.py chernarus.kml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now you should have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chernarus.kmz&lt;/code&gt; which is ready to put on your device.&lt;/p&gt;

&lt;h3 id=&quot;add-kmz-file-to-garmin-device&quot;&gt;Add KMZ file to Garmin device&lt;/h3&gt;
&lt;p&gt;Connect to the device storage with e.g. USB cable and transfer &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chernarus.kmz&lt;/code&gt; onto the device under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Garmin/CustomMaps/chernarus.kmz&lt;/code&gt;. If your device supports an SD card you can use this to store the map, just put it under the same directory structure as the internal memory. This is recommended for transferring large files as the SD card tends to be much faster if used directly in a card reader instead of through the USB interface.  Next, disconnect the device, insert the SD card if used, and reboot it.&lt;/p&gt;

&lt;p&gt;Now you need to enable the custom map to see it. For my GPSMap 64s i do the following: In the map view, press the MENU button, Setup Map and in the bottom under Map Information/Select Map, I can choose which maps to show.&lt;/p&gt;

&lt;p class=&quot;center-images imborder&quot;&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/scrn/256.jpg&quot; alt=&quot;Area near Ústi&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/scrn/181.jpg&quot; alt=&quot;Setup Map&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/scrn/185.jpg&quot; alt=&quot;Select Map&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Find &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chernarus.kmz&lt;/code&gt; under Custom Maps and enable it.&lt;/p&gt;

&lt;p class=&quot;center-images imborder&quot;&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/scrn/191.jpg&quot; alt=&quot;Custom Map&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/scrn/200.jpg&quot; alt=&quot;Custom Map&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/scrn/206.jpg&quot; alt=&quot;Custom Map&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can quickly check if it works by opening it again after enabling it, which should show a preview of the Chernarus map. If it doesn’t show up, try disabling other map layers as they might cover the custom map, and make sure the CRS of the GeoTIFF is set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EPSG:4326&lt;/code&gt;&lt;/p&gt;

&lt;p class=&quot;center-images imborder&quot;&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/scrn/195.jpg&quot; alt=&quot;Custom Map&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/scrn/198.jpg&quot; alt=&quot;Custom Map&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you haven’t already, find the area around Ústí nad Labem and Děčín and zoom in. You have to zoom quite close before the custom map renders, for me it shows only at the 500 m scale bar and closer.&lt;/p&gt;

&lt;p class=&quot;center-images imborder&quot;&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/scrn/917.jpg&quot; alt=&quot;Custom Map&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/scrn/920.jpg&quot; alt=&quot;Custom Map&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you have other maps enabled, they might overlay or completely cover the Chernarus map. Here’s how it looks in Lipová with and without &lt;a href=&quot;https://garmin.opentopomap.org/#czech_republic&quot;&gt;OpenTopoMap for Garmin&lt;/a&gt; enabled, where roads, town names and similar show as an overlay.&lt;/p&gt;

&lt;p class=&quot;center-images imborder&quot;&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/scrn/409.jpg&quot; alt=&quot;Custom Map&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/scrn/395.jpg&quot; alt=&quot;Custom Map&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can experiment with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--draw-order&lt;/code&gt; option for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gdal2kml.py&lt;/code&gt; if you want to use overlays, as the KML order determines “height” of the layers, where layers with the lowest numbers are drawn on the top.&lt;/p&gt;

&lt;h2 id=&quot;visit-to-north-bohemia&quot;&gt;Visit to North Bohemia&lt;/h2&gt;
&lt;p&gt;The final step is of course to travel to the area in real life! Ústí can be reached &lt;a href=&quot;https://en.mapy.cz/s/ferahakego&quot;&gt;by direct train from Prague&lt;/a&gt; in 70 minutes for 5-7 € (tickets from &lt;a href=&quot;https://oneticket.cz/#/search?from=57076&amp;amp;to=53179&amp;amp;fare=adult&amp;amp;adultnum=1&quot;&gt;oneticket.cz&lt;/a&gt; or directly from &lt;a href=&quot;https://www.cd.cz/en/&quot;&gt;České dráhy&lt;/a&gt;, the national rail service), and there are plenty of places to stay overnight in the area - I can warmly recommmend the combined hotel-brewery &lt;a href=&quot;https://www.pivovarnarychte.cz/en/&quot;&gt;Na Rychtě&lt;/a&gt; both for eating at their restaurant or for staying a few nights in Ústí.&lt;/p&gt;

&lt;p&gt;If you have played just a bit of Arma or Dayz in Chernaus, you will find the place quite familiar as you walk around, as the developers have included not just the road network but also several buildings in the game, as shown in &lt;a href=&quot;https://imgur.com/a/Oeph3&quot;&gt;this imgur album&lt;/a&gt;. Below are a couple of the pictures I took myself&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/irl_gorka_church.jpg&quot; alt=&quot;Custom&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/chernarus_gorka_church.jpg&quot; alt=&quot;Custom&quot; class=&quot;half-image&quot; /&gt;
Characteristic yellow church in Javory (“Gorka”).&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/irl_altar_berezino.jpg&quot; alt=&quot;Custom&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/chernarus_altar_berezino.jpg&quot; alt=&quot;Custom&quot; /&gt;
View from Javorský vrch (“Altar”) to Děčín (“Berezino”).&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/irl_gps_stary.jpg&quot; alt=&quot;Custom&quot; class=&quot;half-image-single&quot; /&gt;
View of GPS when entering Lipová (“Stary Sobor”).&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/irl_stary_barn.jpg&quot; alt=&quot;Custom&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/chernarus_stary_barn.jpg&quot; alt=&quot;Custom&quot; /&gt;
The infamous red metal barn in Lipová (“Stary Sobor”). It seems to have been repaired when comparing to older pictures.&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/irl_barn_bukov.jpg&quot; alt=&quot;Custom&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/chernarus_barn_bukov.jpg&quot; alt=&quot;Custom&quot; /&gt;
A farm building in Český Bukov (“Staroye”) used several places in the game.&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/irl_topolka_dam.jpg&quot; alt=&quot;Custom&quot; /&gt;
&lt;img src=&quot;/assets/2021-09-01-chernarus-irl/chernarus_topolka_dam.jpg&quot; alt=&quot;Custom&quot; /&gt;
View towards south of dam near Povrly (“Topolka Dam” north of “Elektrozavodsk”).&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;In this post we have obtained a high-resolution raster map from a tileserver, georeferenced it in QGIS to the real world location it is based on, and then converted it to a Garmin compatible KMZ file for viewing on a handheld GPS device.&lt;/p&gt;

&lt;p&gt;You can also grab the &lt;a href=&quot;/assets/2021-09-01-chernarus-irl/chernarus.kmz&quot;&gt;Chernarus KMZ file&lt;/a&gt; directly to put on your device and save some time.&lt;/p&gt;

&lt;p&gt;The methods shown here can be applied to any map which is sufficiently similar to real world locations - It could be interesting to walk around your town using a historical map to get a sense of how things used to look, and how much it changed since the map was made, for example.&lt;/p&gt;

&lt;!--
## TODO
- Add screenshots from Arma Chernarus
- Center multiple images with CSS?
- Add useful resources (OpenTopoMap Garmin, list of tileservers,...)
- Add GPX points and suggested routes?
- Give link to the full map, GCP points and KMZ file.

https://www.google.com/maps/d/viewer?mid=1EJNBRC6X6C2P6Q1MGrsOb8Zynt4&amp;ll=50.719315505531675%2C14.126621773895067&amp;z=13
--&gt;

&lt;hr /&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:itsinalpha&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;DayZ standalone had quite a turbulent development history, being stuck in a paid “early alpha” pre-release stage for five years from 2013 until its &lt;a href=&quot;https://en.wikipedia.org/wiki/DayZ_(video_game)#Release&quot;&gt;official release in December 2018&lt;/a&gt;, but that’s a story for another time… &lt;a href=&quot;#fnref:itsinalpha&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:montageerror&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Ideally &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;montage&lt;/code&gt; can stitch all the images together in one command, but I had issues with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;too many open files&lt;/code&gt; errors on my system when trying to stack them all, which is why it is split in two sections. &lt;a href=&quot;#fnref:montageerror&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:jpg-in-qgis&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;QGIS does support loading of JPEG raster images, but I encounter whenever I try: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;not a supported raster data source. (libjpeg: Wrong JPEG library version: library is 62, caller expects 80)&lt;/code&gt;, which is why I convert to PNG. I didn’t find a solution, let me know if you can get it to work! &lt;a href=&quot;#fnref:jpg-in-qgis&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:devicesupport&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;There’s a list of supported Garmin devices on &lt;a href=&quot;https://support.garmin.com/?faq=cVuMqGHWaM7wTFWMkPNLN9&quot;&gt;this support page&lt;/a&gt; in footnote 1, “Click Here for a List of Compatible Devices”. &lt;a href=&quot;#fnref:devicesupport&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:fork&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;This is a fork of the Python 2 &lt;a href=&quot;https://github.com/tf198/gdal2custommap&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gdal2custommap&lt;/code&gt;&lt;/a&gt; scripts by Tris Forster, which I modified slightly to wok with Python 3 and iron out some bugs. &lt;a href=&quot;#fnref:fork&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Wed, 15 Sep 2021 10:00:00 +0000</pubDate>
        <link>https://longcreek.me/blog/2021/chernarus-irl</link>
        <guid isPermaLink="true">https://longcreek.me/blog/2021/chernarus-irl</guid>
        
        
        <category>gis,</category>
        
        <category>qgis,</category>
        
        <category>chernarus,</category>
        
        <category>arma,</category>
        
        <category>dayz,</category>
        
        <category>maps,</category>
        
        <category>gps</category>
        
      </item>
    
      <item>
        <title>Visualizing the magnetic field of nanoparticles with Python</title>
        <description>\[\newcommand{\vr}{\mathrm{\mathbf{r}}}
\newcommand{\unit}[1]{\,\mathrm{#1}}
\newcommand{\vec}[1]{\mathrm{\mathbf{#1}}}
\newcommand{\fourier}[1]{\mathcal{F}\left[#1 \right]}

\newcommand{\vB}{\vec{B}}
\newcommand{\vq}{\vec{q}}

\newcommand{\Iholo}{I_\mathrm{holo}}
\newcommand{\Iside}{I_\mathrm{s.b.}}\]

&lt;p&gt;&lt;em&gt;Note: The following is a continuation on &lt;a href=&quot;/blog/2021/holography-intro&quot;&gt;this post on electron holography&lt;/a&gt;, which I suggest reading first to get a sense of what is going on.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As you have probably seen before, magnets and their magnetic fields are often visualized as field lines like in the figure below&lt;sup id=&quot;fnref:wikimedia-fieldlines&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:wikimedia-fieldlines&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; which represent how the magnetic field extends outside a rectangular magnet&lt;/p&gt;

&lt;!---
https://commons.wikimedia.org/wiki/File:VFPt_cylindermagnet_field-representations.svg
---&gt;
&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/magnetic-field-lines-2.svg&quot; alt=&quot;Magnetic field lines&quot; class=&quot;center-image half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is a common illustration used for magnetic fields, where magnetic field lines are drawn along lines of constant field strength – A sort of contour lines for the magnetic field strength. If we were to place a tiny compas at any position outside the magnet, the compass needle would align itself to the direction of the field lines at this position.&lt;/p&gt;

&lt;p&gt;This is usually presented for magnets large enough hold in your hand, but it is actually possible to directly measure the magnetic field of nanoparticles in a &lt;a href=&quot;https://en.wikipedia.org/wiki/Transmission_electron_microscopy&quot;&gt;Transmission Electron Microscope&lt;/a&gt; (TEM), just like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/12-hires-contour-overlay.png&quot; alt=&quot;magnetic field lines around magnetite nanoparticle&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The TEM uses electrons as a probe to image particles, and electrons moving in a magnetic field will get affected by it. Information about the magnetic field of a sample can be saved using a technique known as Electron Holography which preserves the phase \(\phi\) of the electrons in the acquired image.&lt;/p&gt;

&lt;p&gt;Reconstructing the above image from raw holograms involve a few different image processing techniques including Fourier analysis, frequency filtering and image matching to find the translational shift between two almost identical images, as well as other image processing techniques.&lt;/p&gt;

&lt;p&gt;In this post I walk through all the Python code used to go from a raw hologram to a magnetic phase image such as the above.
You can see the full code in &lt;a href=&quot;/assets/2021-06-holo-part2/holography-python.html&quot;&gt;this Jupyter notebook&lt;/a&gt;, which you can &lt;a href=&quot;/assets/2021-06-holo-part2/holography-python.zip&quot;&gt;download along with the holograms&lt;/a&gt; if you want to play along yourself.&lt;/p&gt;

&lt;p&gt;All the data shown was acquired as part of my bachelors thesis&lt;sup id=&quot;fnref:bachelorthesis&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:bachelorthesis&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; at &lt;a href=&quot;https://www.nanolab.dtu.dk/&quot;&gt;DTU Nanolab&lt;/a&gt; (previously Center for Electron Nanoscopy) several years back and follows the procedure detailed in &lt;a href=&quot;https://doi.org/10.5772/22366&quot;&gt;this book chapter&lt;/a&gt;&lt;sup id=&quot;fnref:holographybook&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:holographybook&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. I recently went back to revisit the subject to redo it in Python out of curiousity and decided do this writeup to share with anyone why might be interested.&lt;/p&gt;

&lt;!--
A lot of terms used here were defined in my previous [post on electron holography fundamentals](/blog/2021/holography-intro) which you may want to read first to understand fully what we will be doing.
--&gt;

&lt;h2 id=&quot;calculating-phase-image-from-a-hologram&quot;&gt;Calculating phase image from a hologram&lt;/h2&gt;
&lt;h3 id=&quot;importing-microscope-data&quot;&gt;Importing microscope data&lt;/h3&gt;
&lt;p&gt;We start out with some common packages for scientific Python, namely &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;numpy&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;matplotlib&lt;/code&gt;&lt;sup id=&quot;fnref:requirements&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:requirements&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;. We use pyplot for plotting and will set some default parameters with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plt.rcParams&lt;/code&gt; so we don’t have to do manually for each plot.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Import numpy and fft functions directly
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numpy.fft&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fft2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ifft2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fftshift&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Set some default parameters for the plots
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rcParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;figure.figsize&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rcParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;figure.frameon&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rcParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;image.cmap&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;gray&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The raw data from the microscope is saved in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dm3&lt;/code&gt; files, a common format used in electron microscopy. It is usually opened with the proprietary &lt;a href=&quot;https://www.gatan.com/products/tem-analysis/gatan-microscopy-suite-software&quot;&gt;Gatan Digital Micrograph&lt;/a&gt; software or a program like &lt;a href=&quot;https://imagej.nih.gov/ij/&quot;&gt;ImageJ&lt;/a&gt; which can be difficult to work with for more complex calculations, but luckily the &lt;a href=&quot;https://openncem.readthedocs.io/en/latest/&quot;&gt;OpenNCEM&lt;/a&gt; project allows us to open it in Python (&lt;a href=&quot;https://www.mathworks.com/matlabcentral/fileexchange/43005-read-dm3-and-dm4-image-files&quot;&gt;look here if using Matlab&lt;/a&gt;).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ncempy.io.dm&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dmReader&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Load dm3 files for a particle and reference
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dmdata1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;dmReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;data/h05 +30sat.dm3&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;dmdata1r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;dmReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;data/h06r +30sat.dm3&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Extract image data
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dmdata1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;im1r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dmdata1r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The raw image in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;im1&lt;/code&gt;, our hologram, looks like this&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/01-particle1.png&quot; alt=&quot;Raw hologram of magnetite nanoparticle&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Note that the numbered axes show pixel numbers instead of nanometers. We keep it this way for now as it helps illustrate the numerical calculalations we will be doing. However, it is  still important to provide a scale when showing microscope images, and it is readily available from the metadata:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Scale from metadata: 1 px = %s %s&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dmdata1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;pixelSize&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dmdata1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;pixelUnit&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; Scale from metadata: 1 px &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0.0037131761 µm&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So 1 px = 0.0037 µm, &lt;strong&gt;but&lt;/strong&gt;: the scale is off by a factor 10 in these specific images. This is because the objective lens (the one that forms the image) is the special Lorentz lens, and the correction has not been included correctly in the metadata. We will correct for this and convert to nanometers while we’re at it:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Redefine to nm and correct for Lorentz lens factor 10 error
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dmdata1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;pixelSize&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pixel_unit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;nm&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Corrected scale: 1 px = %.4f %s&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pixel_unit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Field of view: %.2f nm x %.2f nm&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; Corrected scale: 1 px &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0.3713 nm
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; Field of view: 760.46 nm x 760.46 nm&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The image is thus 760 nm from one side to the other, and the particle is about 90 nm wide.&lt;/p&gt;

&lt;p&gt;There is a wealth of other information in the metadata such as acceleration voltage, magnification etc. which can be accessed with the &lt;a href=&quot;https://openncem.readthedocs.io/en/latest/ncempy.io.html#ncempy.io.dm.fileDM&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fileDM&lt;/code&gt;&lt;/a&gt; method from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncempy&lt;/code&gt; if needed.&lt;/p&gt;

&lt;h3 id=&quot;fourier-transformed-hologram-with-sidebands&quot;&gt;Fourier Transformed hologram with sidebands&lt;/h3&gt;
&lt;p&gt;We can now calculate the Fast Fourier Transform (FFT) on our hologram of the particle using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fft2&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;numpy&lt;/code&gt;. We also use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fftshift&lt;/code&gt; which centers the main peak in the image, as it is otherwise split into the corners for numerical reasons.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Transform image, ready for visualization
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1_fft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fftshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fft2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;im1_fft_abslog&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Adjust colormap to increase contrast
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vmin_fft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;amin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1_fft_abslog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;vmax_fft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;amax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1_fft_abslog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1_fft_abslog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vmax&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vmax_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vmin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vmin_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;xlim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1448&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ylim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1448&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2//02-particle1-fft.png&quot; alt=&quot;FFT of particle&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here we see the central peak with the two “sidebands” off to the sides&lt;sup id=&quot;fnref:fft-abslog&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:fft-abslog&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;. Each sideband contains both the amplitude of the wave which passed through the sample and the reference wave \(A_i(\vr)\) and \(A_r(\vr)\) respectively, as well as the electron phase \(\phi(\vr)\):&lt;/p&gt;

\[\hat{I}_\mathrm{s.b.}(\vq) = \fourier{A_i(\vr)A_r(\vr)e^{i\phi(\vr)}}\]

&lt;p&gt;Here \(\vr = (x,y)\) refers to a given point (or pixel) in the image. The next step in isolating the phase image \(\phi(\vr)\) is then to extract one of the sidebands.&lt;/p&gt;

&lt;h3 id=&quot;extracting-a-sideband&quot;&gt;Extracting a sideband&lt;/h3&gt;
&lt;p&gt;The FFT image contains three significant peaks, namely the central one (by far most intense) and the two sidebands (similar intensity). Each sideband is almost identical, with the important difference being that they are complex conjugates of each other - This means a phase image calculated from one sideband will correspond exactly to the phase image from the other sideband with opposite sign.&lt;/p&gt;

&lt;p&gt;To select a sideband, we will find coordinates of the peaks in the image using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;peak_local_max&lt;/code&gt; from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scikit-image&lt;/code&gt; package exactly like in &lt;a href=&quot;https://scikit-image.org/docs/dev/auto_examples/segmentation/plot_peak_local_max.html&quot;&gt;this example&lt;/a&gt;. As the central peak is always strongest we simply find the second strongest peak and check if it’s a positive or negative phase change, otherwise we take the third strongest. We write this into a function as we’ll do it a few times&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scipy.ndimage&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maximum_filter&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;skimage.feature&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;peak_local_max&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;peak_coordinate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;peak_number&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Find the peaks
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;image_max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;maximum_filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;constant&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;coordinates&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;peak_local_max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;min_distance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Get values of peaks and sort, get coordinates of second largest peak
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;peaks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coordinate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;coordinate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;coordinate&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;coordinates&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;peaks_idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;argsort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;peaks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;coordinates_sorted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coordinates&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;peak_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;peak_idx&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;peaks_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;sideband_idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;coordinates_sorted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;peak_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Choose sideband on the right side of the image
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sideband_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sideband_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sideband_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sideband_idx&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We’ll wrap this into a function to automatically extract a sideband from a given FFT image. Note that the image is stored as a matrix where rows (up and down) are indexed before columns (left and right), meaning \(x\) and \(y\) must be reversed since we want a horizontal x-axis and vertical y-axis.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;extract_sideband&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sideband_idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;peak_coordinate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sideband_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sideband_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sideband_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;y2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sideband_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;sideband_fft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sideband_fft&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We can now apply our new function and take a closer look at the sideband.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;sideband_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sideband1_fft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;extract_sideband&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband1_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/
03-particle1-sideand.png&quot; alt=&quot;Selected sideband of first hologram&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The vertical and horizontal streaks are artifacts which appear because our our original image is finite at the edges. When we decompose the image into its frequency components the sharp, abrupt change at the image have to be represented by many different frequencies, giving rise to these streaks. Later you will be able to see the the result of these artifacts in the reconstructed image along the very edges of the images but this will not affect our analysis otherwise.&lt;/p&gt;

&lt;h3 id=&quot;phase-and-amplitude-from-sideband&quot;&gt;Phase and amplitude from sideband&lt;/h3&gt;
&lt;p&gt;We are now ready to calculate the amplitude and phase of our image!&lt;/p&gt;

&lt;p&gt;When performing a fourier transform of an image (real values), the FFT will contain complex values. Usually when the inverse fourier transform is applied we would get back the original image containing only real values. However, by cropping out the sideband we have redefined the center of the FFT image. Now when applying the inverse fourier transform to the sideband, the resulting image will contain complex values.&lt;/p&gt;

&lt;p&gt;This is actually intended! We can find the “usual” intensity image from the absolute value of the complex number in each pixel as \(I = \sqrt{\mathrm{Re}^2+\mathrm{Im}^2}\) with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;np.abs&lt;/code&gt; (like when visualizing the FFT). The phase image is found from the angle of the complex number \(\varphi=\arctan\left(\frac{\mathrm{Im}}{\mathrm{Re}}\right)\) using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;np.angle&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Calculate amplitude and phase of image
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ifft2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fftshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband1_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sideband1_abs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sideband1_phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;angle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Here’s the amplitude image&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/04a-p1-amp.png&quot; alt=&quot;Amplitude of magnetic particle hologram&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Note how the amplitude image is very similar to the original hologram, but in reduced resolution since we cropped it out as part of the full FFT image. The phase image looks like this&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/04b-p1-phase.png&quot; alt=&quot;Phase of magnetic particle hologram with wrapping artifacts&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We immediately notice some odd artifacts in the form of sudden jumps in value. We calculated the phase (or angle) of the complex numbers with &lt;a href=&quot;https://numpy.org/doc/stable/reference/generated/numpy.angle.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;np.angle&lt;/code&gt;&lt;/a&gt; which is an implementation of &lt;a href=&quot;https://en.wikipedia.org/wiki/Atan2&quot;&gt;atan2&lt;/a&gt;, a numerical version of the \(\arctan\) function which outputs an angle between \(-\pi\) and \(\pi\), and an angle is thus bound between these values.&lt;/p&gt;

&lt;p&gt;This means that if a region of the phase image has a phase value extending above \(\pi\) for example, the value returned by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;atan2&lt;/code&gt; will “wrap around” and return \(-\pi\) as it is does not know that it should be continuing the values of the neighbouring pixels.&lt;/p&gt;

&lt;p&gt;Fortunately “unwrapping” phase images is a common procedure in image processing and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scikit-image&lt;/code&gt; has it built into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unwrap_phase&lt;/code&gt; method:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;skimage.restoration&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unwrap_phase&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sideband1_phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;unwrap_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband1_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Our phase image now looks like this&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/05-p1-unwrapped-phase.png&quot; alt=&quot;Phase image of particle&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So far so good, we have succesfully recovered the full phase shift of the electron beam after passing through a nanoparticle! We will improve it a bit by subtracting a background reference before.&lt;/p&gt;

&lt;h3 id=&quot;correcting-phase-image-with-background-reference&quot;&gt;Correcting phase image with background reference&lt;/h3&gt;
&lt;p&gt;First we load in a reference background image which was acquired in an area without any sample present to get a clean background reference. Using the functions defined earlier makes quick work of extracting the sideband&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;im1r_fft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fftshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fft2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sideband1r_fft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;extract_sideband&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1r_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;fig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ax1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ax2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ax3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subplots&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1r_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband1r_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/06-p1r-extraction.png&quot; alt=&quot;Reference phase image for background correction&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we calculate the phase of the reference image&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;sideband1r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ifft2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fftshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband1r_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sideband1r_phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;unwrap_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;angle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband1r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Background reference phase image&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband1r_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/06-p1r-phase.png&quot; alt=&quot;Reference background phase image&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Finally we subtract the reference image which leaves us with a much more even phase image&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;phi1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sideband1_phase&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband1r_phase&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Corrected phase image of particle&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/08a-phi1-corrected.png&quot; alt=&quot;Phase image with background reference subtracted&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The magnetic phase shift still not easily visible as the electric contribution dominates the phase image.&lt;/p&gt;

&lt;h3 id=&quot;hologram-of-particle-with-reversed-magnetization&quot;&gt;Hologram of particle with reversed magnetization&lt;/h3&gt;
&lt;p&gt;In order to isolate just the magnetic contribution \(\phi_m\) to the phase shift we need an image of the exact same particle where the particle’s magnetization, and thus \(\phi_m\), is reversed. Since \(\phi_m\) changes sign while \(\phi_e\) is unchanged it is a matter of simple subtraction&lt;/p&gt;

\[\phi = (\phi_e+\phi_m) - (\phi_e - \phi_m) = 2\phi_m\]

&lt;p&gt;Then we just divide by 2, giving us the pure magnetic phase image \(\phi_m\).&lt;/p&gt;

&lt;p&gt;The magnetic reversal is done by applying a strong magnetic field inside the microscope in the opposite direction of the previous used to magnetize the particle in the first place, using one of the magnetic lenses.&lt;/p&gt;

&lt;p&gt;We load in the image and subtract a reference phase image just like before:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Load data
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dmdata2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;dmReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;data/h19 -30sat.dm3&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;dmdata2r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;dmReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;data/h17r.dm3&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;im2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dmdata2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;im2r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dmdata2r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Calculate FFT and extract sideband for image
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im2_fft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fftshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fft2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sideband2_fft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;extract_sideband&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im2_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sideband2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ifft2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fftshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband2_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sideband2_phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;unwrap_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;angle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Calculate FFT and extract sideband for reference image
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im2r_fft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fftshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fft2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im2r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sideband2r_fft&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;extract_sideband&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im2r_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sideband2r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ifft2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fftshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband2r_fft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sideband2r_phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;unwrap_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;angle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband2r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Subtract reference phase shift
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sideband2_phase&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband2r_phase&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Corrected phase image of particle with reversed magnetization&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/08b-phi2-corrected.png&quot; alt=&quot;Phase image with reversed magnetization&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This phase image is almost identical to the first, but with two important differences: \(\phi_m\) is opposite of before, and the particle is in a slightly different position in the image. This means we cannot directly subtract the two images until we have found out exactly how much the particle position changed.&lt;/p&gt;

&lt;h2 id=&quot;matching-two-similar-images-to-adjust-for-translation&quot;&gt;Matching two similar images to adjust for translation&lt;/h2&gt;
&lt;p&gt;There is a significant shift in x and y positions between the images, but only negligible rotation. This means we can use &lt;a href=&quot;https://en.wikipedia.org/wiki/Phase_correlation&quot;&gt;phase cross correlation&lt;/a&gt; to get a good estimate of the translation between images as implemented in &lt;a href=&quot;https://scikit-image.org/docs/dev/api/skimage.registration.html?skimage.registration.phase_cross_correlation#phase-cross-correlation&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phase_cross_correlation&lt;/code&gt;&lt;/a&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scikit-image&lt;/code&gt;&lt;sup id=&quot;fnref:match-rotation&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:match-rotation&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;. There is a decent &lt;a href=&quot;https://scikit-image.org/docs/dev/auto_examples/registration/plot_register_translation.html#sphx-glr-auto-examples-registration-plot-register-translation-py&quot;&gt;example with details here&lt;/a&gt;. Knowing this shift we can correct for it and ensure the images have a common center so we can subtract them properly.&lt;/p&gt;

&lt;p&gt;We start out by applying a bandpass with gaussian blur to remove some high- and low-frequency details which can detract from the image matching.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;skimage.filters&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gaussian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;difference_of_gaussians&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;skimage.registration&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phase_cross_correlation&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;skimage&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Bandpass with Gaussian blur
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sigma1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sigma2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;phi1_filt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;difference_of_gaussians&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sigma1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sigma2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;phi2_filt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;difference_of_gaussians&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sigma1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sigma2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;fig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subplots&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi1_filt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi2_filt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/09a-phi12-blurred.png&quot; alt=&quot;Gaussian blur for image matching&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As noted when extracting the first sideband, there are significant artifacts along the edges of the image which can also cause issues – image edges are generally troublesome when dealing with frequency decompositions. For this reason we will construct a “window” and multiply with our images, which ensures all values go smoothly towards \(0\) at the edges.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Apply Hann window to avoid border issues
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;window_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;hann&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;window_image&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;window_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phi1_filt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;phi1_windowed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phi1_filt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;window_image&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;phi2_windowed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phi2_filt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;window_image&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;fig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subplots&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;window_image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi1_windowed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/09b-phi-windowing.png&quot; alt=&quot;Hann window to avoid edge artifacts&quot; /&gt;&lt;/p&gt;

&lt;p&gt;With the bandpass filter and window applied to both images, we are now ready to calculate the shift in x and y&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Calculate the shift using phase cross correlation on filtered images
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shifts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phasediff&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;phase_cross_correlation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi1_filt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phi2_filt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;upsample_factor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Note that matrices are indexed as rows (&quot;y&quot;) at [0] and columns (&quot;x&quot;) at [1]
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shifts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shifts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Translation: (dx, dy) = (%.2f, %.2f)&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; Translation: &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;dx, dy&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;15.04, 13.14&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The calculated translation is now applied as a geometrical transform to correct one of the unfiltered phase images. After this we can subtract one phase image from the other to isolate the magnetic phase shift (and remember to divide by 2).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Translate the second unfiltered phase image for matching on top of the first
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tform&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;EuclideanTransform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;translation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;phi2_tf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;warp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inverse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Subtract unfiltered phase images, remember division by 2!
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m_raw&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi2_tf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Magnetic phase shift&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m_raw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/10-phim-raw.png&quot; alt=&quot;Magnetic phase image without electric contribution!&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The magnetic phase shift has revealed itself! Note how there is a lighter region on one side of the particle and dark on the other. This is the magnetic contribution to the phase shift.&lt;/p&gt;

&lt;h3 id=&quot;magnetic-field-lines-from-phase-image&quot;&gt;Magnetic field lines from phase image&lt;/h3&gt;
&lt;p&gt;We can enhance the magnetic phase image by cutting out the relevant part where the images overlap and filtering some noise away.&lt;/p&gt;

&lt;p&gt;First we make a function to cut off the parts of the image that without overlap after subtraction&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;crop_from_shifts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:]&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;border&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;border&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We can also filter the image a bit with a gaussian blur to reduce high frequency noise, since the magnetic field (and phase shift) only varies slowly across the image. We will also apply a scalebar to show the size of the features.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matplotlib_scalebar.scalebar&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ScaleBar&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Scale original pixel size to match resolution of phase image and add to scalebar
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize_phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;scalebar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ScaleBar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pixel_unit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length_fraction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Blur before cropping to minimize edge effects
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m_filt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;gaussian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m_raw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Crop non-overlapping part and a bit of border
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;crop_border&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;phi_m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;crop_from_shifts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m_filt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;crop_border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;fig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subplots&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;axis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_artist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scalebar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Magnetic phase shift&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The phase image now looks like this&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/10-phim-filtered.png&quot; alt=&quot;Visualization of magnetic field lines and phase shift on particle&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Contour lines representing the magnetic field lines can also be overlayed directly on top of the bright field image, letting us see the field lines emanating from the particle itself. Using a divergent colormap which shows the central values as white, while displaying values above and below that as blue and red respectively, we can enhance the readability of the phase image.&lt;/p&gt;

&lt;p&gt;We just need to make sure we crop the bright field image in the same way so the centering is right.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Apply a bit stronger blur to enhance contour lines
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m_extrafilt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;crop_from_shifts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gaussian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m_raw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;crop_border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subplots&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Plot phase with divergent colormap, overlay contour lines
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;RdBu&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;contour&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m_extrafilt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;axis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;scalebar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ScaleBar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pixel_unit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length_fraction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_artist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scalebar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Crop BF image with same parameters as the phase image was cropped to get same center
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bf_image&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;crop_from_shifts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband1_abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;crop_border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Overlay contours onto bright field image
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gaussian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bf_image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;contour&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m_extrafilt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;white&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;linewidths&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;axis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;scalebar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ScaleBar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pixel_unit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length_fraction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_artist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scalebar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;By plotting the contour lines we are in essence displaying the magnetic field lines as they emanate from the particle:&lt;/p&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/11-phim-contour-overlay.png&quot; alt=&quot;Alternative visualizations of magnetic field lines and phase shift on particle&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now that is looking like proper magnetic field lines from a magnetic nanoparticle!&lt;/p&gt;

&lt;!--
## Magnetic field from phase shift

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;skimage.measure&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;profile_line&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Scale original pixel size to match resolution of phase image
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize_phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Extract profile plot across particle
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;110&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;160&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;dist&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize_phase&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;profile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;profile_line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;linewidth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;nearest&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;profile_dist&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;linspace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;profile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Make axes of plot match the physical size
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phi_m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize_phase&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phi_m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize_phase&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;fig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subplots&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;extent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;plot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;linewidth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pxsize_phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;profile_dist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;profile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set_box_aspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

![Profile plot of magnetic phase shift across particle](/assets/2021-06-holo-part2/11-phim-profile.png){:.center-image}
--&gt;

&lt;p&gt;To enhance the image a bit, we will overlay the contour lines on top of the original hologram image so we get much better contrast. We do this by rescaling the magnetic phase image used for contour lines and again cropping parts of the orginal hologram to get the same center&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;skimage.transform&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rescale&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Increase resolution of phase image
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scaling&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sideband_size&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;phi_m_upscaled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rescale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gaussian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scaling&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Crop original image the same way as the sideband images were, correcting for scale
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1_crop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;crop_from_shifts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scaling&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scaling&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;crop_border&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scaling&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;im1_filt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;gaussian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1_crop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im1_filt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;contour&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi_m_upscaled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;white&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;linewidths&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/12-hires-contour-overlay.png&quot; alt=&quot;Magnetic contour lines overlayed on bright field image&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;Congratulations for making it all the way through!&lt;/p&gt;

&lt;p&gt;We have worked all the way from loading raw holograms taken in a Transmisison Electron Microscope into Python to extracting and visualizing a magnetic phase image by using various image processing techniques and a bit of Fourier transform magic.&lt;/p&gt;

&lt;p&gt;There is still much that can be done with this data, such as calculations on the exact magnetization of the particle and how it compares to expected values from other sources, which I have skipped as this post is already running long. If you want to try the code yourself, make sure to download &lt;a href=&quot;/assets/2021-06-holo-part2/holography-python.zip&quot;&gt;the associed Jupyter Notebook&lt;/a&gt; with data, where you can make your own calculations (&lt;a href=&quot;/assets/2021-06-holo-part2/holography-python.html&quot;&gt;preview of notebook&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;While I have omitted many details on this complex topic, I hope it can server as an interesting appetizer on some of the things that can be done in Transmission Electron Microscopes, and how information that is usually not obtainable can be brought forward with some clever techniques.&lt;/p&gt;

&lt;!--
# Notes and Todo:
- ~~Show lineplot across particle~~
- ~~Fix axes to match physical size~~
- ~~**Pixel size is off, figure out right one (look in thesis or old matlab code)**. Is it just factor 10?~~
- ~~Add note on particle size~~
- ~~Relate phase to magnetic field strength (add to first article as well)~~
- ~~Check the thing about choosing negative/positive phase shift (which part of fourier image is it?)~~
- ~~Add classic magnetic field lines image to first post~~
- ~~overlay contour lines on full resolution image~~
- ~~Calculate and show gradient, relate to B field (strength and direction as vector map)~~ Naaahhh...
- ~~Draw flow chart of steps?~~ Naaah
- ~~**Make images with scale bars some places**~~
- Add note on profile plot about 2 pi phase being 4.14×10^-15 Tm2. of enclosed flux and how much we would expect from magnetite?
- ~~Finish section on phase being equivalent to field strength in first article~~
- Clean up notebook for publishing
- Export notebook to html, zip up files with data.
--&gt;

&lt;hr /&gt;
&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:wikimedia-fieldlines&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Adapted from diagrams of the magnetic field around a bar magnet from &lt;a href=&quot;https://commons.wikimedia.org/wiki/File:VFPt_cylindermagnet_field-representations.svg&quot;&gt;Wikimedia Commons&lt;/a&gt; &lt;a href=&quot;#fnref:wikimedia-fieldlines&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:bachelorthesis&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Supervisors: Takeshi Kasama, Marco Beleggia, Cathrine Frandsen. &lt;a href=&quot;#fnref:bachelorthesis&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:holographybook&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Takeshi Kasama, Rafal E. Dunin-Borkowski and Marco Beleggia (2011). &lt;em&gt;Electron Holography of Magnetic Materials&lt;/em&gt;, Holography - Different Fields of Application, F. A. Ramirez (Ed.), IntechOpen, &lt;a href=&quot;https://doi.org/10.5772/22366&quot; target=&quot;_blank&quot;&gt;DOI: 10.5772/22366&lt;/a&gt; &lt;a href=&quot;#fnref:holographybook&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:requirements&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;All packages used in the notebook are: &lt;a href=&quot;https://pypi.org/project/numpy/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;numpy&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://pypi.org/project/matplotlib/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;matplotlib&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://pypi.org/project/ncempy/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncenmpy&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://pypi.org/project/scikit-image/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scikit-image&lt;/code&gt;&lt;/a&gt; (imports as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;skimage&lt;/code&gt;) and &lt;a href=&quot;https://pypi.org/project/matplotlib-scalebar/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;matplotlib_scalebar&lt;/code&gt;&lt;/a&gt;. &lt;a href=&quot;#fnref:requirements&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:fft-abslog&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Remember that each pixel in the fourier transformed image &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;im1_fft&lt;/code&gt; consists of complex values with a real value \(\mathrm{Re}\) and imaginary value \(\mathrm{Im}\). What we display as “the FFT” is the amplitude as \(r = \sqrt{\mathrm{Re}^2+\mathrm{Im}^2}\) using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;np.abs&lt;/code&gt;. Further, to avoid the central peak dominating the image I also calculate the logarithm of each pixel value with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;np.log&lt;/code&gt; to enhance visibility of the smaller values in the sidebands relative to the peak, as well as adjusting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vmin&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vmax&lt;/code&gt;. &lt;a href=&quot;#fnref:fft-abslog&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:match-rotation&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Even if the image is rotated and scaled this method can still be used as demonstrated in &lt;a href=&quot;https://scikit-image.org/docs/dev/auto_examples/registration/plot_register_rotation.html#sphx-glr-auto-examples-registration-plot-register-rotation-py&quot;&gt;this example&lt;/a&gt; – essentially the matching is performed on the FFT of the image to obtain rotation, followed by the same method as here after correcting for rotation. &lt;a href=&quot;#fnref:match-rotation&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Tue, 06 Jul 2021 10:00:00 +0000</pubDate>
        <link>https://longcreek.me/blog/2021/holography-code</link>
        <guid isPermaLink="true">https://longcreek.me/blog/2021/holography-code</guid>
        
        
        <category>holography</category>
        
        <category>imaging</category>
        
        <category>tem</category>
        
        <category>microscopy</category>
        
        <category>physics</category>
        
        <category>magnetism</category>
        
        <category>Python</category>
        
      </item>
    
      <item>
        <title>Visualizing the magnetic field of nanoparticles - Fundamentals</title>
        <description>\[\newcommand{\vr}{\mathrm{\mathbf{r}}}
\newcommand{\unit}[1]{\,\mathrm{#1}}
\newcommand{\vec}[1]{\mathrm{\mathbf{#1}}}
\newcommand{\fourier}[1]{\mathcal{F}\left[#1 \right]}

\newcommand{\vv}{\vec{v}}
\newcommand{\vB}{\vec{B}}
\newcommand{\vq}{\vec{q}}

\newcommand{\Iholo}{I_\mathrm{holo}}
\newcommand{\Iside}{I_\mathrm{s.b.}}\]

&lt;!--
This post deals with the math relating to electron holography in preparation for a more visual approach coming later. Stick around the blog to see it applied to actual images! The math that follows is essentially a boiled down version of [this book chapter](https://www.intechopen.com/books/holography-different-fields-of-application/electron-holography-of-magnetic-materials){:target=&quot;_blank&quot;}[^1] on electron holography of magnetic materials[^2].


The tiny wavelengths allows us to image cool stuff like this

![Rows of atoms in a particle](/assets/holography/HR-TEM_brightfield.jpg){:.shadow-image .half-image .center-image}

This is a nanoparticle of platinum, and the dots you see are individual rows of atoms! That kind of &quot;direct&quot; imaging is known as Bright Field (BF) imaging and is one of the simplest operating modes in TEM and very analogous to an optical microscope.

While atomic resolution images are very interesting and useful, it only scratches the surface of the techniques possible in a TEM. One of my favourite techniques is one that allows you to *directly visualise the magnetic field of a magnetic nanoparticle*.
--&gt;

&lt;!--
Electron microscopes are really versatile things -- Not only can they be used to see nanoparticles down to the atomic level, but because we are using electrons instead of visible light we get a lot of analytic capabilities &quot;for free&quot; as well. One of my favourites is the a method were we can directly &quot;see&quot; the magnetic field around nanoparticles.
--&gt;
&lt;p&gt;&lt;em&gt;This is the first of two posts - the second on reconstructing holograms using Python can be found &lt;a href=&quot;/blog/2021/holography-code&quot;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When learning about magnets and magnetic fields, you have probably seen visualizations similar to these&lt;sup id=&quot;fnref:wikimedia-fieldlines&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:wikimedia-fieldlines&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; which represent how the magnetic field extends outside a rectangular magnet&lt;/p&gt;

&lt;!---
https://commons.wikimedia.org/wiki/File:VFPt_cylindermagnet_field-representations.svg
---&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/magnetic-field-lines-1.svg&quot; alt=&quot;Magnetic field lines&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The left represents how iron filings agglomerate when sprinkled around a magnet as they roughly align to the magnetic field, a common method to directly “see” the magnetic field around larger magnets. In the middle the magnetic field is represented with a series of magnetic field lines which are drawn along lines of constant field strength, while the rightmost image shows how an array of freely rotating magnets (e.g. compasses) would align themselves in the same magnetic field.&lt;/p&gt;

&lt;p&gt;This is usually presented for magnets large enough hold in your hand, but it is actually possible to directly measure the magnetic field all the way down at the nano scale in a &lt;a href=&quot;https://en.wikipedia.org/wiki/Transmission_electron_microscopy&quot;&gt;Transmission Electron Microscope&lt;/a&gt; or &lt;em&gt;TEM&lt;/em&gt;, just like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/2021-06-holo-part2/12-hires-contour-overlay.png&quot; alt=&quot;magnetic field lines around magnetite nanoparticle&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The above image shows a magnetite nanoparticle around 90 nm wide where the contour lines represent the magnetic field around the particle as measured directly in the microscope. Iron filings and tiny compasses work great for magnets large enough to handle, but what do we do when working on the nanoscale?&lt;/p&gt;

&lt;!--
A TEM uses electrons as a probe and as luck would have it, electrons moving in a magnetic field will get affected by it, specifically by shifting the phase $$\phi$$ of the electrons. In usual imaging in the TEM the phase is not preserved, but by using a technique known as [Electron Holography](https://en.wikipedia.org/wiki/Electron_holography) we can preserve the phase and use it to extract information about the magnetic field (among other things).
--&gt;

&lt;p&gt;Below i will explain a method known as Off-Axis Electron Holography and how it can be used to measure and visualize the magnetic field around magnetic nanoparticles in the TEM to make images like the above. Much of what follows is based on &lt;a href=&quot;https://www.intechopen.com/books/holography-different-fields-of-application/electron-holography-of-magnetic-materials&quot; target=&quot;_blank&quot;&gt;this book chapter&lt;/a&gt;&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; on electron holography of magnetic materials which I recommend reading if you are interested in the subject.&lt;/p&gt;

&lt;p&gt;The data shown was acquired as part of my bachelors thesis&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; at &lt;a href=&quot;https://www.nanolab.dtu.dk/&quot;&gt;DTU Nanolab&lt;/a&gt; (previously Center for Electron Nanoscopy) several years back. I recently went back to revisit the subject and redo (and improve) in Python out of curiousity and decided do this writeup to share with anyone why might be interested.&lt;/p&gt;

&lt;p&gt;This post is part one of two and covers some TEM fundamentals and relevant mathematics. For numerical calculations, take a look at part two where we &lt;a href=&quot;/blog/2021/holography-code&quot;&gt;reconstruct holograms using Python&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;very-brief-intro-to-the-tem&quot;&gt;&lt;em&gt;Very&lt;/em&gt; brief intro to the TEM&lt;/h2&gt;
&lt;p&gt;A Transmission Electron Microscope in conventional operation is very similar to a typical optical microscope, but instead of using light waves we use a beam of electrons. Since electron waves generated at high voltages have a &lt;em&gt;much&lt;/em&gt; shorter wavelength than visible light, we can use it to see much smaller things. As an example,  blue light has a wavelength around \(400 \unit{nm}\), while an electron will have a wavelength around \(0.0025 \unit{nm}\) at \(200 \unit{kV}\) acceleration voltage – for reference a hydrogen atom has a diameter of around \(0.01 \unit{nm}\)&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;. &lt;!--As a (very hand-wavy) rule of thumb, features need to be larger than your probing wavelength in order to affect the waves significantly.--&gt;&lt;/p&gt;

&lt;p&gt;The diagram below shows a simplified schematic of a TEM in bright field (BF) mode, where an electron gun at the top provides a beam of coherent electrons which are condensed to a uniform plane wavefront before passing through a sample. After this the beam is focused, various apertures can be inserted, and the image is formed in the image plane on the bottom, where we place 2D detector to save the image.&lt;/p&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/holography/tem-diagram.png&quot; alt=&quot;Simplified TEM diagram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Unlike in the optical microscope, the lenses are not made from glass or any physical material. Instead, we use magnetic lenses to focus the electron beam – Essentially a symmetric bunch of coils with adjustable current going through them to create a magnetic field. The reason we can manipulate the electrons with magnetic fields is due to the &lt;a href=&quot;https://en.wikipedia.org/wiki/Lorentz_force&quot; target=&quot;_blank&quot;&gt;Lorentz force&lt;/a&gt;.&lt;/p&gt;

\[\vec{F} = q \, \vec{v}\times\vec{B}\]

&lt;!-- This basically means that any charged particle (such as electrons) moving in a magnetic field will feel a force orthogonal to its direction of movement. --&gt;

&lt;p&gt;With a strong field of a certain shape we can use this to focus our electron beam. This is also the reason we are able to visualise the magnetic field of a sample when using electrons, as the field around a magnetic particle deflects the electrons slightly and change their phase.&lt;/p&gt;

&lt;p&gt;I am barely scratching the surface of the subject for the sake of brevity - have a look at the very detailed and pedagogical &lt;a href=&quot;https://www.doitpoms.ac.uk/tlplib/tem/index.php&quot;&gt;DoITPoMS from the University of Cambridge&lt;/a&gt; on the TEM if you want more details.&lt;/p&gt;

&lt;h3 id=&quot;electron-beam-as-a-wavefunction&quot;&gt;Electron beam as a wavefunction&lt;/h3&gt;
&lt;p&gt;Mathematically we can describe the electron beam at any point \(\vr\) in the image plane as a plane wave with amplitude \(A(\vr)\) and phase \(\phi(\vr)\) in a complex exponential phase term&lt;/p&gt;

\[\psi(\vr) = A(\vr)e^{i \phi(\vr)}\]

&lt;p&gt;In typical operating conditions, when recording the image on a detector the phase information is lost as the intensity distribution is the absolute square of the wavefunction, where the conjugated exponential terms cancel out&lt;/p&gt;

\[I(\vr) = \left| \psi(\vr) \right|^2 = \left[A(\vr)e^{i \phi(\vr)}\right]\left[A(\vr)e^{-i \phi(\vr)}\right]= A(\vr)^2\]

&lt;p&gt;In other words we’re only recording the square of the amplitude of the wave, which simply tells us how many electrons reached each pixel on the sensor, regardless of their phase. This is plenty for most uses, but in our case we actually need to know the phase of the electrons.&lt;/p&gt;

&lt;p&gt;When an electron wave passes through a sample the phase \(\phi\) of the wave will experience a phase shift. For thin magnetic samples we can express the phase shift at a given point \(\vr\) after passing through a sample as the sum of an electric and magnetic contribution&lt;/p&gt;

\[\phi(\vr) = \phi_e(\vr) + \phi_m(\vr)\]

&lt;p&gt;\(\phi_e\) arises from the electron beam intereacting with the electrons in the sample, while \(\phi_m\) depends on the in-plane component of the magnetic field from the sample due to the Lorentz force. We note that since the force is proportional to the &lt;em&gt;cross product&lt;/em&gt; \(\vv\times\vB\), the moving charges are only affected by the components of the B-field orthogonal to the movement direction.
Since the electrons are moving from the top and down into the sample they will thus only be affected by the in-plane component of the B-field. If we imagine a magnetic field pointing directly upwards from the sample, parallel to the movement of electrons there would be no phase shift, while a field perfectly orthogonal, along the sample plane, would show up fully in the phase shift.&lt;/p&gt;

&lt;p&gt;The phase shift \(\phi_m\) is thus our key to imaging the magnetic field of our particles, and we need to figure out how to record it. As luck would have it there are workarounds for this problem.&lt;/p&gt;

&lt;h3 id=&quot;holography-in-the-electron-microscope&quot;&gt;Holography in the electron microscope&lt;/h3&gt;
&lt;p&gt;In case you are wondering, &lt;em&gt;holo graphy&lt;/em&gt; comes from Greek and can be translated as &lt;em&gt;whole drawing&lt;/em&gt; - in microscopy and this often refers to the fact that holographic methods preserve the phase. The “whole” in cool shiny 3D holograms on old CD’s, toys, credit cards etc.  refers to the fact that they capture the “whole” three dimensional scene.&lt;/p&gt;

&lt;p&gt;The challenge for us is to find a way to make sure the phase information of our electron wave is not lost as we record it on the detector. Below is a very simplified diagram of a TEM in a setup used for a method called &lt;em&gt;Off-Axis Electron Holography&lt;/em&gt;.&lt;/p&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/holography/holography_schematic.png&quot; alt=&quot;Holography schematic&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The green part of the beam which passed trough the sample we’ll call \(\psi_s\), and the other half which goes unhindered through the vacuum is our reference wave, \(\psi_r\).&lt;/p&gt;

&lt;p&gt;Like before we generate a coherent plane wave of electrons, but now we only send part of it through the sample (green part). Further down, after the objective lens&lt;sup id=&quot;fnref:lorentzlens&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:lorentzlens&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;, is the key part of the setup: the biprism. It is simply a wire going all the way through the middle of the electron beam with a plate on each side along the length of the wire outside the beam. When applying a positive charge to the beam and negative charge to the plates the electrons are repelled by the plates and attracted to the wire.&lt;/p&gt;

&lt;p&gt;So we have essentially split the whole wavefront in two parts which we can bend towards each other causing them to overlap, and this is where the magic happens. When two coherent (in-phase) plane waves meet each other at an angle a sinusoidal interference pattern will appear as illustrated in the bottom of the diagram and can be recorded with out image sensor. The pattern is highly sensitive to small differences in phase between the two waves and will thus have information relating to \(\phi_e\) and \(\phi_m\) embedded in it.&lt;/p&gt;

&lt;p&gt;So how do we extract the phase?&lt;/p&gt;

&lt;h2 id=&quot;mathematics-of-the-phase-retrieval&quot;&gt;Mathematics of the phase retrieval&lt;/h2&gt;
&lt;p&gt;Let’s formalise a bit on what was described above.&lt;/p&gt;

&lt;h3 id=&quot;contributions-to-the-phase-shift&quot;&gt;Contributions to the phase shift&lt;/h3&gt;
&lt;p&gt;For a sample with no external charge distributions or external electric fields, the electrostatic contribution to the phase shift can be expressed in terms of a mean inner potential \(V_0\) which is assumed constant throughout the sample.&lt;/p&gt;

\[\phi_e(x,y) = C_E V_0 t(x,y)\]

&lt;p&gt;where \(C_E\) is a constant dependent on the microscope acceleration voltage&lt;sup id=&quot;fnref:CE&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:CE&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt; and \(t(x,y)\) the thickness profile of the sample projected in the beam direction.&lt;/p&gt;

&lt;p&gt;The magnetic phase shift can be expressed as&lt;/p&gt;

\[\phi_m(x,y)  = -\frac{e}{\hbar} \int A_z(x,y,z) \,dz\]

&lt;p&gt;where \(A_z\) is the magnetic vector potential, specifically the component parallel to the electron beam direction. The gradient of the magnetic phase then gives us a direct relationship to the B-field form the phase shift&lt;/p&gt;

\[\nabla \phi_m(x,y) = \frac{e}{\hbar}\begin{bmatrix}B_y^p(x,y)\\\; -B_x^p(x,y) \end{bmatrix}\]

&lt;p&gt;where \(B^p\) is the total projection of the B-field components perpendicular to electron beam direction through the sample area&lt;/p&gt;

\[B^p(x,y) = \int B(x,y,z)\,dz\]

&lt;!--
Between two points $$(x_1, y_1)$$ and $$(x_2, y_2)$$ in the sample plane, the magnetic phase shift can be expressed as

$$\Delta\phi_m=\phi_m(x_2, y_2)-\phi_m(x_1, y_1)
= \frac{e}{\hbar}\left(-\int A_z(x_2, y_2, z) \,dz + \int A_z(x_1,y_1,z) \,dz \right)$$

This can be rewritten as

$$\Delta \phi_m=-\frac{e}{\hbar} \oint \vec{A}\cdot d\vec{l} $$

By Stoke&apos;s theorem

$$ \Delta\phi_m = \frac{e}{\hbar} \iint \vec{B}\cdot\hat{\vec{n}} \, dS$$
--&gt;

&lt;p&gt;As such, the phase shift of the electron beam after passing through a sample can be described as&lt;/p&gt;

\[\phi(x,y) = \phi_e(x,y) + \phi_m(z,y)\]

&lt;p&gt;Our goal now is to extract just the magnetic phase shift \(\phi_m\) of the electron beam and we need to get rid of \(\phi_e\) in some way.&lt;/p&gt;

&lt;p&gt;If we can exactly reverse the magnetic field of our particle, the magnetic phase shift will also be reversed from \(\phi_m\) to \(-\phi_m\) while \(\phi_e\) is unchanged. In the TEM this can be done by applying a strong magnetic field in one direction, record an image, then apply a strong field in the opposite direction to reverse the magnetisation of the particle, and record another image.&lt;/p&gt;

&lt;p&gt;We can then record two images where the magnetisation of the particle is exactly reversed between them and then subtract the phase shifts. Then \(\phi_e\) cancels out and leaves just the magnetic information&lt;/p&gt;

\[\phi_{\mathrm{rev}} = \phi_1 - \phi_2 = (\phi_e + \phi_m) - (\phi_e - \phi_m) = 2\phi_m\]

&lt;p&gt;Now we just remember to divide by 2 and we have our magnetic phase shift!&lt;sup id=&quot;fnref:5&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:5&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h3 id=&quot;preserving-the-phase-information&quot;&gt;Preserving the phase information&lt;/h3&gt;
&lt;p&gt;Remembering that the electron beam at a given point \(\vr\) in the image plane can be described as a wavefunction \(\psi_i(\vr) = A_i(\vr) e^{i\phi(\vr)}\), we now introduce a plane reference wave that only passes unhindered through vacuum&lt;/p&gt;

\[\psi_r(\vr)=A_r(\vr)e^{i2\pi \vq_c\cdot \vr}\]

&lt;p&gt;with \(\vq_c\) being a two-dimenstional reciprocal space vector determining the tilt of the reference wave. This is what we do with the biprism in the off-axis holography setup, when we split the beam into two parts and make them overlap. In the overlap the wavefunction is simply a superposition of the two wavefunctions leading to the following intensity distribution&lt;/p&gt;

\[\Iholo(\vr) = \left|\psi_i(\vr)+\psi_r(\vr)\right|^2 = \left| A_i(\vr) e^{i\phi(\vr)} + A_r(\vr)e^{i2\pi \vq\cdot \vr}\right|^2\]

&lt;p&gt;This can be evaluated as&lt;/p&gt;

\[I_{holo}(\vr) = A_i^2(\vr) + A_r^2(\vr) + A_i(\vr)A_r(\vr)\left(e^{i(2\pi\vq_c\cdotp\vr-\phi(\vr))}+e^{-i(2\pi\vq_c\cdotp\vr-\phi(\vr))}\right)\]

&lt;!--
$$I_{\mathrm{holo}}(\vr) = A_i^2(\vr) + A_r^2(\vr) + A_i(\vr)A_r(\vr) \cos\left[2\pi\vq_c\cdot\vr+\phi(\vr)\right]$$
--&gt;

&lt;p&gt;The phase information is now preserved directly in the intensity distribution on our image sensor! We have the amplitude of the wave passing through the sample \(A_i(\vr)^2\) (as before), the amplitude of the reference wave \(A_r(\vr)^2\), and finally an oscillating term&lt;sup id=&quot;fnref:Iholo&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:Iholo&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt; which contains the phase of the sample beam \(\phi(\vr)\).&lt;/p&gt;

&lt;p&gt;Let’s see how it looks in practice. Below is a holographic image of a &lt;a href=&quot;https://en.wikipedia.org/wiki/Magnetite&quot; target=&quot;_blank&quot;&gt;magnetite&lt;/a&gt; nanoparticle which is about 90 nm wide. It is actually shaped like an &lt;a href=&quot;https://en.wikipedia.org/wiki/Octahedron&quot; target=&quot;_blank&quot;&gt;octahedron&lt;/a&gt; but as it is lying down the projection through the particle appears as a hexagon. The large round shape in the top left half of the image is a hole in a thin carbon substrate&lt;sup id=&quot;fnref:holeycarbon&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:holeycarbon&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;9&lt;/a&gt;&lt;/sup&gt;, and our particle is just barely holding on to the edge of this hole.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/holography/particle-lines.png&quot; alt=&quot;Magnetite particle with interference pattern&quot; class=&quot;shadow-image center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The thin lines all across the image is a direct result of the interference of the two beams. In areas with even background it closely matches a cosine function as expected. Note that the much larger parallel lines (top left) are an artifact from diffraction fringes at the edges of the biprism wire and not directly related to the phase. Let’s look at a closeup of the particle&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/holography/particle-lines-closeup.png&quot; alt=&quot;Closeup of interference pattern&quot; class=&quot;shadow-image center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Notice how the lines are not straight everywhere. If we follow one from top to bottom, we see it bends at the top end of the particle, continues in a mostly straight line and then bends back close to its original position.
This bending is directly due to the phase shift of the electron beam due to the particle - at the edges the thickness varies causing the bend, while the center of the particle is fairly even, giving straight lines. The phase shift is primarily from the electric interaction \(\phi_e\) as it tends to be stronger than \(\phi_m\).&lt;/p&gt;

&lt;h3 id=&quot;recovering-just-the-phase&quot;&gt;Recovering just the phase&lt;/h3&gt;
&lt;!--Now, as we&apos;re only interested in the phase information we don&apos;t care much about the amplitude terms which is essentially just a regular bright field image. Further, the image is now muddled by our reference wave which gives rise to the intereference lines seen.--&gt;

&lt;p&gt;To separate the phase term, we turn to the trusty Fourier transform, which I wrote a bit about &lt;a href=&quot;/blog/2020/fourier-filtering&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;. Now, as the Fourier transform is a linear operator, the transform of a sum of terms is equivalent to the sum of individually transformed terms:&lt;/p&gt;

\[\fourier{\Iholo} = \fourier{A_i(\vr)^2} + \fourier{A_r(\vr)^2} + \fourier{A_i(\vr)A_r(\vr)\left(e^{i(2\pi\vq_c\cdotp\vr-\phi(\vr))}+e^{-i(2\pi\vq_c\cdotp\vr-\phi(\vr))}\right)}\]

&lt;p&gt;With a bit of mathematical gymnastics the last term in the expression can expressed as a convolution with a delta function \(\delta(\vq\pm\vq_c)\)&lt;/p&gt;

\[\begin{align*}
\hat{I}_\mathrm{holo} =&amp;amp; \hat{A}_i(\vq)^2 + \hat{A}_r(\vq)^2 \\
&amp;amp;+ \delta(\vq+\vq_c)*\fourier{A_i(\vr)A_r(\vr)e^{i\phi(\vr)}} \\
&amp;amp;+ \delta(\vq-\vq_c)*\fourier{A_i(\vr)A_r(\vr)e^{-i\phi(\vr)}}
\end{align*}\]

&lt;!--
$$\begin{align*}
\hat{I}_\mathrm{holo} =&amp; \fourier{A_i(\vr)^2} + \fourier{A_r(\vr)^2} \\
&amp;+ \delta(\vq+\vq_c)*\fourier{A_i(\vr)A_r(\vr)e^{i\phi(\vr)}} \\
&amp;+ \delta(\vq-\vq_c)*\fourier{A_i(\vr)A_r(\vr)e^{-i\phi(\vr)}}
\end{align*}$$
--&gt;

&lt;p&gt;where \(*\) denotes the &lt;a href=&quot;https://en.wikipedia.org/wiki/Convolution&quot;&gt;convolution operator&lt;/a&gt;. The proof of the above is &lt;a href=&quot;http://www.mathmatique.com/articles/left-exercise-reader&quot; target=&quot;_blank&quot;&gt;left as an exercise to the reader.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is slightly complex, but here’s what you need to take away from the above: When convolving a delta function with a fourier transform, it essentially becomes “centered” at the point where the argument of the delta function is zero; \(\delta(\mathbf{0})\). Thus if convolving with \(\delta(\vq+\vq_c)\) the center will be at \(\vq=-\vq_c\).&lt;/p&gt;

&lt;p&gt;So now we have two amplitude terms with no phase information, \(\hat{A}_i(\vq)^2\) and \(\hat{A}_r(\vq)^2\) centered around \(\vq=(0,0)\) in the middle of the reciprocal space in the fourier transformed image. They are more or less the regular bright field image you would get without the special technique. But now we also have two phase terms, which are the complex conjugates of each other, centered at \(\vq=\vq_c\) and \(\vq=-\vq_c\) respectively. These will show up at opposite sides, away from the center of the fourier transformed image.&lt;/p&gt;

&lt;p&gt;Visually it looks like this. Below is shown the 2D Fast Fourier Transform of the hologram image&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/holography/particle-lines-fft.png&quot; alt=&quot;FFT with sidebands&quot; class=&quot;shadow-image center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A large peak in the center with two distinct peaks away from center at opposite sides. These are the sidebands mentioned before, and the \(\vq_c\) vector is the vector pointing from the center and out to these sidebands. The visible line from the center all the way to the sideband comes from the diffraction fringes from the biprism as mentioned earlier.&lt;/p&gt;

&lt;p&gt;Note that the Fourier transform of a real valued image results in complex values, i.e. each pixel has a real part \(\mathrm{Re}\) and imaginary part \(\mathrm{Im}\). When showing the image here, we are seeing the absolute value, or amplitude, of this complex image.&lt;/p&gt;

&lt;p&gt;We can now select a sideband from the full image, i.e. we pick out just the term&lt;/p&gt;

\[\delta(\vq+\vq_c)*\fourier{A_i(\vr)A_r(\vr)e^{i\phi(\vr)}}\]

&lt;p&gt;&lt;img src=&quot;/assets/holography/fft-sideband.png&quot; alt=&quot;Sideband in the FFT&quot; class=&quot;shadow-image center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The horizontal and vertical streaks are artifacts from the edges of the image and will not affect our analysis. The center of this new image is now at \(\vq=-\vq_c\) and the convolution with the delta function becomes \(1\) leaving us with&lt;/p&gt;

\[\hat{I}_\mathrm{s.b.}(\vq) = \fourier{A_i(\vr)A_r(\vr)e^{i\phi(\vr)}}\]

&lt;p&gt;By performing an inverse Fourier transform the image is now simply&lt;/p&gt;

\[\Iside(\vr) = A_i(\vr)A_r(\vr)e^{i\phi(\vr)}\]

&lt;p&gt;We are now liberated of the other terms and we are one important step closer to isolating \(\phi(\vr)\) itself. Exciting!&lt;/p&gt;

&lt;h3 id=&quot;amplitude-and-phase-of-a-complex-number&quot;&gt;Amplitude and phase of a complex number&lt;/h3&gt;
&lt;p&gt;Our sideband \(\Iside(\vr)\) is now a complex function on the exponential or polar form \(z = re^{i\varphi}\) where \(r\) is the amplitude and \(\varphi\) the phase. Mathematically we can directly read off the amplitude as \(r=A_iA_r\) and the phase of our image as \(\varphi=\phi\) but numerically our data is stored in another form.&lt;/p&gt;

&lt;p&gt;The (Inverse) Fast Fourier Transform used to numerically perform fourier transforms gives us an image where complex numbers are in the cartesian form \(z=a+ib\), and thus each pixel has a real value \(\mathrm{Re}(z) = a\) and imaginary value \(\mathrm{Im}(z) = b\). Luckily the conversion comes from basic trigonometry. The amplitude is simply the pythagorean length of the complex number&lt;/p&gt;

\[r = \sqrt{a^2+b^2}\]

&lt;p&gt;and the phase is the angle&lt;/p&gt;

\[\varphi = \arctan\left(\frac{b}{a}\right)\]

&lt;p&gt;That’s it, we now have everything we need to recover the phase! The reconstructed phase of our particle looks like this&lt;/p&gt;

\[\phi(\vr) = \phi_e(\vr) + \phi_m(\vr)\]

&lt;p&gt;&lt;img src=&quot;/assets/holography/particle1-phase.png&quot; alt=&quot;Phase from sideband&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The above image (besides artifacts) is a direct image of the phase of the electron beam where it reached the detector in the microscope, reconstructed from the shown hologram. We would expect the magnetic field somewhere outside the particle, so where is it? The electric contribution \(\phi_e\) is much larger than the magnetic \(\phi_m\) so it gets a bit lost in the signal. To see it properly we still need to subtract an image of the same particle with reversed magnetic field, meaning we still have some work to do.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;We’ve gone briefly through the workings of a transmission electron microscope and seen how the electron beam can be described as a wave. With a special setup in the microscope which introduces a reference wave, the interference pattern in the overlap of these waves enables us to record the phase information of the beam passing through the sample. Using some Fourier transform magic we walked through the mathematics of extracting the phase from this pattern and demonstrated it for a single particle.&lt;/p&gt;

&lt;p&gt;The remaining work to isolate only the magnetic contribution to the phase shift is mainly computational. I continue this in the post on &lt;a href=&quot;/blog/2021/holography-code&quot;&gt;reconstructing holograms using Python&lt;/a&gt; where I walk through the code used to go from raw holograms to finished magnetic phase images.&lt;/p&gt;

&lt;hr /&gt;
&lt;!--
The electric controbution is directly proportinal to the path

$$\phi_e = C_E \int_{-\infty}^{\infty}V(z) dz$$
--&gt;
&lt;!--
## TODO
- Describe magnetite particle and support
- Ensure TEM diagrams are matching in size, colors etc
- Find HRTEM BF image of atomic resolution I&apos;m allowed to use, make sure it is not STEM.
--&gt;
&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:wikimedia-fieldlines&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Diagrams of the magnetic field around a bar magnet from &lt;a href=&quot;https://commons.wikimedia.org/wiki/File:VFPt_cylindermagnet_field-representations.svg&quot;&gt;Wikimedia Commons&lt;/a&gt; &lt;a href=&quot;#fnref:wikimedia-fieldlines&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Takeshi Kasama, Rafal E. Dunin-Borkowski and Marco Beleggia (2011). &lt;em&gt;Electron Holography of Magnetic Materials&lt;/em&gt;, Holography - Different Fields of Application, F. A. Ramirez (Ed.), IntechOpen, &lt;a href=&quot;https://doi.org/10.5772/22366&quot; target=&quot;_blank&quot;&gt;DOI: 10.5772/22366&lt;/a&gt; &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Supervisors: Takeshi Kasama, Marco Beleggia, Cathrine Frandsen. On a personal note: Takeshi Kasama passed away a few years back at a much too young age. He did an amazing job as supervisor on my bachelor’s project.  He had a knack for teaching and for making me “learn how to learn”, and I am grateful to have been under his guidance. He has definitely shaped my approach to science and physics and how I explain things to others, so if you like what you read send him a friendly thought! &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Strictly speaking an atom has a fuzzy undefined size, but the diameter from the Bohr model gives a useful sense of how far from the center of a hydrogen atom you are likely to find its accompanying electron. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:lorentzlens&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Since we are trying to image the weak magnetic field of our nanoparticles, the objective lens is now a Lorentz lens, as this does not generate a magnetic field at the sample. &lt;a href=&quot;#fnref:lorentzlens&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:CE&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;With acceleration voltage as \(U=\frac{E}{e}\) we have \(C_E = \left(\frac{2\pi}{\lambda}\right) \left(\frac{E+E_0}{E(E+2E_0)}\right)\) where \(\lambda\) is the relativistic electron wavelength and \(E_0\) the rest mass energy of the electron. &lt;a href=&quot;#fnref:CE&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:5&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;There are also other ways of removing the electric phaseshift \(\phi_e\), such as directly simulating \(\phi_e\) from detailed sample information and subtracting that. It can also be useful on its own, e.g. for accurate measurements of particle thickness, but we will not consider this for now. &lt;a href=&quot;#fnref:5&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:Iholo&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Using some identities of complex exponentials we can also write the phase term as a cosine term \(A_i(\vr)A_r(\vr) \cos\left[2\pi\vq_c\cdot\vr+\phi(\vr)\right]\). These sinusoidal interference fringes are what we directly measure in the raw hologram. &lt;a href=&quot;#fnref:Iholo&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:holeycarbon&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Take a look at &lt;a href=&quot;https://www.agarscientific.com/tem/support-films-holey-carbon&quot; target=&quot;_blank&quot;&gt;Agar scientific&lt;/a&gt; for some example images. &lt;a href=&quot;#fnref:holeycarbon&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 20 May 2021 10:14:00 +0000</pubDate>
        <link>https://longcreek.me/blog/2021/holography-intro</link>
        <guid isPermaLink="true">https://longcreek.me/blog/2021/holography-intro</guid>
        
        
        <category>holography</category>
        
        <category>imaging</category>
        
        <category>tem</category>
        
        <category>microscopy</category>
        
        <category>physics</category>
        
      </item>
    
      <item>
        <title>Some visual intuition for 2D Fourier transforms</title>
        <description>&lt;h2 id=&quot;improving-by-blurring&quot;&gt;Improving by blurring&lt;/h2&gt;
&lt;p&gt;Let’s say we have a image of a cat and we want to blur it a bit&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cat.png&quot; alt=&quot;Cute!&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cat_filt.png&quot; alt=&quot;Softer cute!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s pretty cute, but you may not need blurred cat images so often. However there are also more useful things we can do using the exact same method. This here is Constable Sinclair Tait of the Inverness-shire Constabulary&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/constable.jpg&quot; alt=&quot;Constable Tait in his original form&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Many things can be said about Mr. Tait, which you can read a lot more about on &lt;a href=&quot;https://www.flickr.com/photos/91779914@N00/8378619946&quot;&gt;Dave Conner’s Flickr&lt;/a&gt;, but he certainly hasn’t been preserved all that well. The interesting thing is that by using the exact same method as for blurring a cat we can bring some life back to our constable:&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/constable_filt.png&quot; alt=&quot;Fixed it!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s pretty neat, and, some would argue, more useful than blurred cats. So how does it work?&lt;/p&gt;

&lt;h2 id=&quot;the-fourier-transform&quot;&gt;The Fourier transform&lt;/h2&gt;
&lt;p&gt;Both the cat blurring and constable reconstruction is done by applying a low-pass filter to the images, or, in other words, by removing high frequencies.&lt;/p&gt;

&lt;p&gt;The way we go about is by a &lt;a href=&quot;https://en.wikipedia.org/wiki/Fourier_transform&quot;&gt;Fourier transformation&lt;/a&gt; of our image. I will not go into too many details of exactly how or why it works in this post - for now all we need to know is that &lt;strong&gt;any&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; function or signal can be expressed as a sum of sine and cosine functions&lt;/strong&gt; to arbitrary precision.&lt;/p&gt;

&lt;p&gt;How does this help us blur cats? Consider this illustration by &lt;a href=&quot;https://en.wikipedia.org/wiki/File:Fourier_transform_time_and_frequency_domains_(small).gif&quot;&gt;Lucas Barbosa&lt;/a&gt; of a 1D function being decomposed into it’s frequency components&lt;/p&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/fourer_transform_animation.gif&quot; alt=&quot;Animation of Fourier decomposition&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here a square wave function \(f\) is decomposed into a range of sine and cosine functions each multiplied by a constant \(a_n\) or \(b_n\) (their amplitude) and each with a different frequency (here proportional to \(n\)) - if each of these individual sine and cosines were to be added together the result is again the original function \(f\). We are essentially seeing \(f\) being split up into its frequency components, and the function \(\hat{f}\) shows us how large each component is.&lt;/p&gt;

&lt;p&gt;This is essentially what the Fourier transform does - it tells us which frequencies a function or signal consists of and how strong they each are. In other words, if our signal is in “real space” we can transform it to “frequency space”.&lt;/p&gt;

&lt;h3 id=&quot;notation-and-an-important-property&quot;&gt;Notation and an important property&lt;/h3&gt;
&lt;p&gt;Applying the Fourier transform can be denoted as \(\mathcal{F}\left\{f\right\} = \hat{f}\), where \(f\) is transformed into \(\hat{f}\). Importantly we can directly recover our original function with the inverse Fourier transform, \(\mathcal{F}^{-1}\{\hat{f}\} = f\). For disctrete (digital) signals such as images we typically use a numerical version called a &lt;a href=&quot;https://en.wikipedia.org/wiki/Fast_Fourier_transform&quot;&gt;Fast Fourier Transform&lt;/a&gt;. For our use in this blog post we consider them equivalent, and I will use “the FFT” in some places to refer to the result of a transform on an image.&lt;/p&gt;

&lt;p&gt;A very useful fact about the Fourier transformation is its &lt;a href=&quot;https://en.wikipedia.org/wiki/Fourier_transform#Basic_properties&quot;&gt;linearity&lt;/a&gt;. This means that the Fourier transform of a sum of functions can be expressed as a sum of individual Fourier transforms on each function: \(\mathcal{F}\left\{f_1 + f_2 \right\} = \mathcal{F}\left\{f_1\right\} + \mathcal{F}\left\{f_2\right\}\)&lt;/p&gt;

&lt;p&gt;We are going to leverage this to our advantage.&lt;/p&gt;

&lt;h2 id=&quot;frequencies-in-an-image&quot;&gt;Frequencies in an image&lt;/h2&gt;
&lt;p&gt;Let’s experiment a bit and create a little 2D image. Here \(x\) and \(y\) goes from \(0\) to \(2\pi\) (i.e. one full period of a trigonometric function) and we plot the function \(f_1 = \cos (4x)\)&lt;/p&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cos4x.png&quot; alt=&quot;cos(4x)&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The FFT of this simple cosine looks like this&lt;/p&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cos4x_fft.png&quot; alt=&quot;FFT of cos(4x)&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Two dots spaced equally apart from the image center - these are the frequency components of our image, and since our image is a “pure” cosine the frequency is very well defined. The reason there are two dots instead of just one, despite having just one frequency, is beyond the scope of this post. Just know that a Fourier transform of a real valued signal gives a symmetric and complex valued result, meaning each pixel in our image is a complex number, \(z=a+ib\). The two dots represent exactly the same frequency and are each others complex conjugate&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. When I “show the fourier transform” what I am actually showing is the absolute value of each point \(\lvert z \rvert\)&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Let’s try with a higher frequency and see how \(f_2 = \cos(8x)\) and its fourier transform looks&lt;/p&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cos8x.png&quot; alt=&quot;cos(8x)&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cos8x_fft.png&quot; alt=&quot;FFT of cos(8x)&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Again two dots centered around the middle, but now they are further apart. The last bit is important; &lt;strong&gt;higher frequencies are further away from the center in the FFT image&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We can also add the two images together, so we’re now seing \(f_3 = \cos(4x) + \cos(16x)\)&lt;/p&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cos_z1+z2.png&quot; alt=&quot;cos(4x)+cos(16x))&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cos_z1+z2_fft.png&quot; alt=&quot;FFT of cos(4x)+cos(16x)&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then we have two sets of dots, exactly corresponding to the two frequencies we are visualising. And importantly, even though everything is muddled together in “real space”, we still se everything distinct in “frequency space”.&lt;/p&gt;

&lt;p&gt;If we turn the picture by plotting \(f_4 = \cos(4y)\) we also turn the arrangement of dots&lt;/p&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/zz_cos4y.png&quot; alt=&quot;cos(4y)&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/zz_cos4y_fft.png&quot; alt=&quot;FFT of cos(4y)&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Again we can add the pictures together, i.e. our image now shows \(f_5 = \cos(4x)+\cos(8x)+ \cos(4y)\)&lt;/p&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/zz_mix.png&quot; alt=&quot;cos(4y)&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/zz_mix_fft.png&quot; alt=&quot;FFT of cos(4y)&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And again we see two distinct peaks for each frequency in our image.&lt;/p&gt;

&lt;h2 id=&quot;filtering-with-a-mask&quot;&gt;Filtering with a mask&lt;/h2&gt;
&lt;p&gt;Let’s freshen things up a bit and try with a whole bunch of frequencies&lt;/p&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/zz_hifreq.png&quot; alt=&quot;cos(4y)&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/zz_hifreq_fft.png&quot; alt=&quot;FFT of cos(4y)&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you look closely you can see that our previous image with \(f_5\) is actually contained in the one above. It’s quite difficult to see in real space but in the FFT the dots from before a still clearly distinct from all the new ones.&lt;/p&gt;

&lt;p&gt;Let’s recover them!&lt;/p&gt;

&lt;p&gt;Since all the unwanted frequencies are higher than the ones we want, we can do so with a high-pass filter. A simple way of doing this is to just set all frequencies above a certain treshold to \(0\). Remember that in the FFT the frequency is proportional to the distance from the center. This means we will need a circular mask, where white pixels are \(1\) and black are \(0\).&lt;/p&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/zz_mask.png&quot; alt=&quot;cos(4y)&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we can apply the mask to the FFT image by multiplying them together (both real and imaginary parts). This way each pixel with a \(0\) in the mask becomres \(0\) in the FFT, and \(1\)’s in the mask simply keep their value. This results in the following&lt;/p&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/zz_hifreq_fft.png&quot; alt=&quot;FFT of cos(4y)&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/zz_hifreq_fft_filt.png&quot; alt=&quot;cos(4y)&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That should seem familiar. The lines crossing in the center are artifacts from discretization of the higher frequencies, but they don’t matter to omuch now. We can now do an inverse Fourier transform and recover our image!&lt;/p&gt;

&lt;p class=&quot;center-images noshadow&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/zz_mix.png&quot; alt=&quot;cos(4y)&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/zz_hifreq_filt.png&quot; alt=&quot;cos(4y)&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And we’re back to how we started!&lt;/p&gt;

&lt;h1 id=&quot;blurring-the-darn-cat&quot;&gt;Blurring the darn cat&lt;/h1&gt;
&lt;p&gt;This brings us back to the cat. Let’s see it again along with its fourier transform&lt;sup id=&quot;fnref:5&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:5&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cat.png&quot; alt=&quot;Cute!&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cat_fft.png&quot; alt=&quot;Softer cute!&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As there are not many well defined frequencies in the picture we don’t have the same well defined spots as before. Let’s do the same as we did to that previous image and cut off some higher frequencies (aka. use a low pass filter). As before we create a mask and apply it to our image&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cat_fft_filt.png&quot; alt=&quot;Cute!&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cat_filt.png&quot; alt=&quot;Softer cute!&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The mask is made from a &lt;a href=&quot;https://en.wikipedia.org/wiki/Window_function#Tukey_window&quot;&gt;Tukey window&lt;/a&gt; which has tapered edges to avoid edge artifacts which would appear from a sudden frequency cutoff. There are many types of window functions to use (you can even make your own!). I chose Tukey somewhat arbitrarily - we’ll save the specifics for another post.&lt;/p&gt;

&lt;p&gt;We can increase or decrease the diameter of our filter (or window) which will in turn increase or decrease the cut off frequency and thus the sharpness of our image:&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cat_fft_filt2.png&quot; alt=&quot;Cute!&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cat_filt2.png&quot; alt=&quot;Softer cute!&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cat_fft_filt3.png&quot; alt=&quot;Cute!&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/cat_filt3.png&quot; alt=&quot;Softer cute!&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;restoring-the-constable&quot;&gt;Restoring the Constable&lt;/h1&gt;
&lt;p&gt;Using what we have now (hopefully) learned, we return to Mr. Tait and his Fourier transform&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/constable.jpg&quot; alt=&quot;Dotted constable&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/constable_fft.png&quot; alt=&quot;Constable FFT&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The dots are back! Why &lt;em&gt;is&lt;/em&gt; that? As we saw earlier, a well defined frequency in an image leads to a well defined point in the FFT. The dots which were used to print Mr. Taits portrait are very evenly spaced and can be apparently represented well by a limited, fairly well defined set of frequencies. This is good news for us if we want to restore his image as we then only need to block fairly specific frequencies.&lt;/p&gt;

&lt;p&gt;We can begin with the easy way - just cut off all frequencies above a certain point which contains the dots:&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/constable_fft_filt.png&quot; alt=&quot;Constable FFT filtered&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/constable_filt.png&quot; alt=&quot;Constable filtered&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Not a bad start!&lt;/p&gt;

&lt;p&gt;But we may want to keep some information in the higher frequencies. We can basically do whatever we want with the FFT image. Instead of simply cutting off everything above a certain frequency (low-pass filter) we’ll try to just blot out the dots and keep everything else.&lt;/p&gt;

&lt;p&gt;We create a new mask, this time much smaller than the picture and inverted compared to before&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/notch_window.png&quot; alt=&quot;Notch window&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This time we have \(0\)’s in the center and \(1\)’s at the edge, so when we multiply this onto our image we can “erase” certain points. From this we create a larger mask which we can apply to the FFT of the constable&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/notch_mask.png&quot; alt=&quot;Notch mask&quot; class=&quot;half-image&quot; /&gt;
&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/constable_fft_notch_filt.png&quot; alt=&quot;Notch window&quot; class=&quot;half-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The inverse transform gives us the filtered constable&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/constable_notchfilt.png&quot; alt=&quot;Notch mask&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Not perfect.&lt;/p&gt;

&lt;p&gt;You may be thinking that the improvement was not very significant compared to just the low-pass filter, and you would actually be correct.&lt;/p&gt;

&lt;p&gt;The reason is there cannot be any details “between the dots” in the original image. In other words, as all information in the original image is encoded purely by the dots themselves, there shouldn’t be any additional information with higher frequency than those, and when we cut away higher frequencies we don’t lose image information. However there may be additional details from the digitalisation (dust, markings, etc.) which could be interesting for some applications. There are also some artifacts around the edges, which I have not accounted for, seen as vertical and horizontal streaks in the FFT, but that is maybe food for a future blog post.&lt;/p&gt;

&lt;p&gt;Let us combine the two methods and do both a notch filter and low-pass filter&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/constable_fft_doublefilt.png&quot; alt=&quot;Notch mask&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Our constable has now reached his final form:&lt;/p&gt;

&lt;p class=&quot;center-images&quot;&gt;&lt;img src=&quot;/assets/2020-12-10-fourier-filtering/constable_doublefilt.png&quot; alt=&quot;Notch mask&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There are many other techniques that can be used for this kind of image reconstruction, but it is at least interesting to see how much you can do with a fairly straight forward method.&lt;/p&gt;

&lt;p&gt;The principles we have seen and the intuition gained from playing with transforming images can carry over and be of great help in many other areas of science and physics, including understanding of lenses, diffraction gratings, crystallography and many other (some of which I hope to write more about here!)&lt;/p&gt;

&lt;p&gt;Hope you enjoyed reading!&lt;/p&gt;

&lt;hr /&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;There are exceptions, but most reasonably well-behaved functions one might normally encounter in the physical world (and the mathematics describing it) has a Fourier transform. There is a bit more on that on &lt;a href=&quot;https://math.stackexchange.com/questions/1378633/every-function-can-be-represented-as-a-fourier-series&quot;&gt;this Stackexchange&lt;/a&gt; question. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Complex_conjugate&quot;&gt;complex conjugation&lt;/a&gt; is fancy speak for “the \(i\) changes sign” in a complex number. Thus the complex conjugate of \(a + ib\) is just \(a - ib\). &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
\[\lvert z\rvert = \sqrt{a^2 + (i b)^2} = \sqrt{a^2 +  b^2}\]
      &lt;p&gt;&lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:5&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I am now displaying the logarithm of the value of each pixel now, i.e. \(\log\left(\lvert z \rvert\right)\) for all pixels, as the main peak would dominate everything in the image. With the logarithm lower valued pixels are enhanced and easier to see. &lt;a href=&quot;#fnref:5&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 10 Dec 2020 00:00:00 +0000</pubDate>
        <link>https://longcreek.me/blog/2020/fourier-filtering</link>
        <guid isPermaLink="true">https://longcreek.me/blog/2020/fourier-filtering</guid>
        
        <category>fourier</category>
        
        <category>filter</category>
        
        <category>frequency</category>
        
        <category>transformation</category>
        
        <category>image-processing</category>
        
        <category>dsp</category>
        
        <category>FFT</category>
        
        
        <category>image-processing</category>
        
      </item>
    
  </channel>
</rss>
