{"id":357043,"date":"2024-05-20T23:42:21","date_gmt":"2024-05-20T23:42:21","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=357043"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=357043","title":{"rendered":"<span>A (more) accurate camera sensor dynamic range measurement<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>Introduction<\/h2>\n<p>Hello, everyone! In this post, let&#8217;s talk about how to (more) accurately measure the dynamic range of a camera sensor and what can be done with these measurements.<\/p>\n<p>Of course, I am not an expert in computer vision, a programmer or a statistician, so please feel free to correct me in the comments if I make mistakes in this post. Here my interest was primarily focused on everyday and practical tasks, such as photography, but I believe the results may also be useful to computer vision professionals.<\/p>\n<hr\/>\n<p>Update: mistakes were found here after publishing this post on the DPReview forum. I think it is important to note that here, and <a href=\"https:\/\/www.dpreview.com\/forums\/thread\/4731088\" rel=\"noopener noreferrer nofollow\">here is the link to the thread itself<\/a><\/p>\n<hr\/>\n<h2>Existing Problem<\/h2>\n<p>The dynamic range of modern image sensors is limited; we cannot capture detail in very bright highlights and very dark shadows simultaneously without degrading the image quality due to noise. In general, the noise, in my opinion, is the most limiting factor for image quality today. The darker the scene, the more noise there is in the shadows, which when the image becomes darker increases in amplitude more and more, progressively \u201ceating away\u201d detail, especially that of low\u2011contrast objects.<\/p>\n<h2>Why Measure Dynamic Range<\/h2>\n<p>In general, accurate dynamic range measurements can be used by both photographers (not only enthusiasts but also professionals) and computer vision specialists to evaluate some equipment.<\/p>\n<p>Firstly, measurements help to answer the question of which camera or sensor to choose for the future tasks or whether an upgrade is worth it\u00a0\u2014 to what extent the advantage will be noticeable. Secondly, through measurements, one can analyze an existing camera or sensor to find an optimal exposure and post\u2011processing strategy and also use the data for further research.<\/p>\n<h2>How Sensor Dynamic Range is Currently Measured<\/h2>\n<p><em>In this chapter, I am using the method and data from Bill Claff&#8217;s website, <\/em><a href=\"https:\/\/www.photonstophotos.net\/\" rel=\"noopener noreferrer nofollow\"><em>Photons to Photos<\/em><\/a><em>.<\/em><\/p>\n<p><a href=\"https:\/\/www.photonstophotos.net\/GeneralTopics\/Sensors_&amp;_Raw\/Sensor_Analysis_Primer\/Engineering_and_Photographic_Dynamic_Range.htm\" rel=\"noopener noreferrer nofollow\">The current method of measuring dynamic range<\/a> begins with the plotting of a graph of the signal-to-noise ratio for a specific ISO at different exposure values, as illustrated below:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d68\/e95\/db6\/d68e95db636189c1784e28ba68014a2a.gif\" width=\"864\" height=\"772\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d68\/e95\/db6\/d68e95db636189c1784e28ba68014a2a.gif\"\/><\/figure>\n<p>In general, there are engineering and so-called photographic dynamic ranges. Here is what Mr. Claff writes regarding the first:<\/p>\n<blockquote>\n<p>The low endpoint for Engineering Dynamic Range is determined by where the SNR curve crosses the value of 1.<\/p>\n<p>Here is an extreme close-up of that area of the Photon Transfer Curve:<\/p>\n<\/blockquote>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7d5\/5ca\/844\/7d55ca844f6906f839eeaa4f526289b4.gif\" width=\"864\" height=\"772\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7d5\/5ca\/844\/7d55ca844f6906f839eeaa4f526289b4.gif\"\/><\/figure>\n<blockquote>\n<p>The ISO 100\u00a0line crosses 0\u00a0(the log<sub>2<\/sub>(1)) at 1.63\u00a0EV.<\/p>\n<p>So Engineering Dynamic Range is 14.00\u00a0EV\u00a0\u2014 1.63\u00a0EV = 12.37\u00a0EV.<\/p>\n<p>Or, if we use the White Level (from <a href=\"https:\/\/www.photonstophotos.net\/GeneralTopics\/Sensors_&amp;_Raw\/Sensor_Analysis_Primer\/White_Level.htm\" rel=\"noopener noreferrer nofollow\"><u>White Level<\/u><\/a>), (14.00\u00a0EV\u00a0\u2014 0.11\u00a0EV)\u00a0\u2014 1.63\u00a0EV = 12.26\u00a0EV.<\/p>\n<\/blockquote>\n<p>For comparison, here is the definition of the so-called photographic dynamic range:<\/p>\n<blockquote>\n<p>My definition of Photographic Dynamic Range is a low endpoint with an SNR of 20\u00a0when adjusted for the appropriate Circle Of Confusion (COC) for the sensor.<\/p>\n<p>For the D300\u00a0the SNR values on this curve is for a 5.5\u00a0micron square photosite.<\/p>\n<p>To correct for a COC of.022mm we are looking for a log<sub>2<\/sub> SNR value of 2.49.<\/p>\n<p>Here is an close\u2011up of the area of the curve:<\/p>\n<\/blockquote>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1e7\/3cc\/34d\/1e73cc34dab47a5fd3cbabbb00ed1936.gif\" width=\"864\" height=\"772\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1e7\/3cc\/34d\/1e73cc34dab47a5fd3cbabbb00ed1936.gif\"\/><\/figure>\n<blockquote>\n<p>Note that the ISO 100\u00a0crosses 2.49\u00a0at 5.00\u00a0EV.<\/p>\n<p>So Photographic Dynamic Range at ISO 100\u00a0is 14.00\u00a0EV\u00a0\u2014 5.00\u00a0EV = 9.00\u00a0EV.<\/p>\n<p>Or, if we use the White Level (from <a href=\"https:\/\/www.photonstophotos.net\/GeneralTopics\/Sensors_&amp;_Raw\/Sensor_Analysis_Primer\/White_Level.htm\" rel=\"noopener noreferrer nofollow\"><u>White Level<\/u><\/a>), (14.00\u00a0EV\u00a0\u2014 0.11\u00a0EV)\u00a0\u2014 5.00\u00a0EV = 8.89\u00a0EV.<\/p>\n<\/blockquote>\n<p>The graphs obtained after such measurements can be found here\u00a0\u2014 <a href=\"https:\/\/www.photonstophotos.net\/Charts\/PDR.htm\" rel=\"noopener noreferrer nofollow\">Photographic Dynamic Range versus ISO Setting<\/a>.<\/p>\n<p>For example, here is what the data looks like for the Pentax K-1:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/402\/5e1\/8e8\/4025e18e8129496301d9eadf5dcb2561.png\" width=\"1599\" height=\"642\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/402\/5e1\/8e8\/4025e18e8129496301d9eadf5dcb2561.png\"\/><\/figure>\n<p>However, choosing an exposure strategy based solely on this graph is not the best idea because some cameras are so\u2011called ISO\u2011less. This means that increasing the ISO in the camera before capturing the image will not improve the noisy shadow detail but will only destroy highlight one.<\/p>\n<p>Therefore, another graph is needed as well\u00a0\u2014 such as this one\u00a0\u2014 that shows <a href=\"https:\/\/www.photonstophotos.net\/Charts\/PDR_Shadow.htm\" rel=\"noopener noreferrer nofollow\">shadow improvement versus ISO setting<\/a>:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/61a\/111\/f45\/61a111f4595335b2b09bd391833bee45.png\" width=\"1599\" height=\"642\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/61a\/111\/f45\/61a111f4595335b2b09bd391833bee45.png\"\/><\/figure>\n<p>Indeed, the chosen camera turned out to be ISO\u2011less, meaning that increasing ISO beyond 100\u00a0will not improve the shadow detail.<\/p>\n<p>For clarity, here are two frames from the same camera <a href=\"https:\/\/www.dpreview.com\/reviews\/image-comparison\/fullscreen?attr134_0=pentax_k1&amp;attr134_1=pentax_k1&amp;attr134_2=pentax_k1&amp;attr134_3=pentax_k1&amp;attr136_0=6&amp;attr136_1=1&amp;attr136_2=3&amp;attr136_3=2&amp;attr403_0=1&amp;attr403_1=1&amp;attr403_2=1&amp;attr403_3=1&amp;normalization=full&amp;widget=487&amp;x=0.151173145&amp;y=0.5005349\" rel=\"noopener noreferrer nofollow\">by DPReview<\/a>\u00a0\u2014 one at ISO 3200\u00a0with exposure increased by one stop, and another at ISO 100\u00a0with exposure increased by 6\u00a0stops:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e5f\/98f\/07b\/e5f98f07bf32562f7c03bcb771bad5a5.png\" width=\"580\" height=\"264\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e5f\/98f\/07b\/e5f98f07bf32562f7c03bcb771bad5a5.png\"\/><\/figure>\n<p>But this doesn&#8217;t apply to all cameras. For example, here is the Canon 6D, increasing ISO indeed improves the shadows:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/80f\/bb3\/197\/80fbb3197e7f67abefa475c27fd16b35.png\" width=\"1599\" height=\"642\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/80f\/bb3\/197\/80fbb3197e7f67abefa475c27fd16b35.png\"\/><\/figure>\n<p>One cannot say that the camera is necessarily better or worse solely because of this characteristic, but it does influence the choice of an optimal exposure strategy during shooting.<\/p>\n<h2>Shortcoming of Such Measurement Method<\/h2>\n<p>The problem with such a classical approach arises when a camera uses noise reduction. Yes, these are still RAW files, it&#8217;s just that noise reduction can be applied even before demosaicing. As seen in the graph below, the dynamic range sharply increases at ISO 640:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b69\/726\/cf6\/b69726cf6698a2010de8067b0b0ea126.png\" width=\"1599\" height=\"642\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b69\/726\/cf6\/b69726cf6698a2010de8067b0b0ea126.png\"\/><\/figure>\n<p>This does not necessarily mean that the image quality has actually improved. On the contrary, noise reduction could have destroyed some fine detail.<\/p>\n<p>On the Shadow Improvement chart, the advantage is even more apparent\u00a0\u2014 reaching almost 2\u00a0stops:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c72\/cb9\/857\/c72cb9857d911484d7e30e9b52429f5f.png\" width=\"1599\" height=\"642\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c72\/cb9\/857\/c72cb9857d911484d7e30e9b52429f5f.png\"\/><\/figure>\n<p>In reality, as you understand, things won&#8217;t be as great. This is the problem with the classical measurement approach\u00a0\u2014 DSP algorithms, such as noise reduction and detail recovery, can only be detected (which is what the triangles pointing down on the graph represent), but their actual impact on image quality cannot be accurately assessed.<\/p>\n<h2>A more advanced method of dynamic range measurement<\/h2>\n<p>You are likely familiar with the <a href=\"https:\/\/www.libraw.org\/\" rel=\"noopener noreferrer nofollow\">libraw<\/a> library, and perhaps even use it. The developer of this library, Alexey Tutubalin (\u0410\u043b\u0435\u043a\u0441\u0435\u0439 \u0422\u0443\u0442\u0443\u0431\u0430\u043b\u0438\u043d), <a href=\"https:\/\/blog.lexa.ru\/2017\/08\/25\/novyy_staryy_podhod_k_dinamicheskomu_diapazonu_na_primere_kamery_canon_eos_5d_iv.html\" rel=\"noopener noreferrer nofollow\">proposed<\/a> his way of measuring dynamic range back in 2017. He pondered the question of how much real resolution remains in an image due to the influence of noise. For this, Alexey used a low\u2011contrast rotated target to test the resolution. The rotation was introduced to challenge the internal DSP algorithms in the camera, in case such algorithms were present. It looked like this:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/2ef\/e7f\/902\/2efe7f9021f2d5c0266203e869302564.jpg\" width=\"1000\" height=\"710\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2ef\/e7f\/902\/2efe7f9021f2d5c0266203e869302564.jpg\" data-blurred=\"true\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/421\/8b4\/636\/4218b4636e05ef36feb3da25d8608adc.jpg\" width=\"1000\" height=\"718\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/421\/8b4\/636\/4218b4636e05ef36feb3da25d8608adc.jpg\" data-blurred=\"true\"\/><\/figure>\n<p>After a series of shots and a semi-automatic analysis of results, this interesting graph was obtained:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/3fe\/e3f\/a56\/3fee3fa5646fa63086056420b436536e.png\" width=\"960\" height=\"635\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/3fe\/e3f\/a56\/3fee3fa5646fa63086056420b436536e.png\"\/><\/figure>\n<p>In my opinion, the data turned out to be incredibly useful and illustrative, but I wanted to replicate the results using fully automated measurements and metrics, ensuring that the developed method is accessible to everyone in home conditions.<\/p>\n<h2>Proposed Solution<\/h2>\n<p>I believe that testing resolution using special targets might lead to potential cheating attempts by the camera. The target should have resolution, i.e., detail, higher than that of a sensor. Therefore, we need a target with a large number of small details that cannot be tampered with\u00a0\u2014 essentially just noise. However, we cannot use ordinary noise, as it would decrease as the camera moves away from the target. So, we need a special, scale\u2011invariant pink noise.<\/p>\n<p>Imatest sells such targets for $330:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7a1\/805\/916\/7a180591624a9e30adbe2f6ad053ba58.png\" width=\"1186\" height=\"604\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7a1\/805\/916\/7a180591624a9e30adbe2f6ad053ba58.png\"\/><\/figure>\n<p>I just printed such a square on a regular printer on an A4 sheet.<\/p>\n<p>Unfortunately, I don&#8217;t have a standalone camera, so the testing was done on a regular phone with a SONY IMX686\u00a0sensor. I used the <a href=\"https:\/\/github.com\/KillerInk\/FreeDcam\" rel=\"noopener noreferrer nofollow\">FreeDCam<\/a> app, controlled it from a PC using <a href=\"https:\/\/github.com\/Genymobile\/scrcpy\" rel=\"noopener noreferrer nofollow\">scrcpy<\/a> to avoid moving the phone between frames (in the case of a real camera, it would need to be placed on a tripod and remotely controlled from the PC). After that, I took series of shots of the resulting target at different ISOs with different exposures, from 1\u00a0to 12\u00a0stops below sensor saturation (careful readers will notice that, in fact, the lines on the graph are cut off before 12\u00a0stops at ISO 3200\u00a0and 6400\u00a0\u2014 FreeDCam simply does not have such short exposure time settings). The captured frames were converted into linear 16-bit TIFF without demosaicing but with white balance applied through channel amplification. Then they were analyzed relative to the reference frame\u00a0\u2014 10\u00a0averaged frames of the target taken at one stop below sensor saturation\u00a0\u2014 equivalent to a frame at ISO 5\u00a0with ideal exposure.<\/p>\n<p>The resulting graph shows the signal\u2011to\u2011noise ratio:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/648\/515\/802\/6485158026d71cb17a18d1fcbc8ded53.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/648\/515\/802\/6485158026d71cb17a18d1fcbc8ded53.png\"\/><\/figure>\n<p>Unlike Mr. Claff&#8217;s graph, this graph, if not entirely, at least partially, is resistant to DSP\u00a0\u2014 please pay attention to the lower values at ISO 3200\u00a0and 6400, which are likely signs of noise reduction. Although the graph is not entirely free from its influence, there is no improvement relative to the upper values. Therefore, the obtained data has higher quality than the one that would be obtained by the standard method. In fact, I tested my phone without actual pink noise, so using real pink noise (which can be generated, for example, using functions from <a href=\"https:\/\/github.com\/VileBile\/colorednoise_2d\" rel=\"noopener noreferrer nofollow\">here<\/a>) will likely only improve the result.<\/p>\n<p>Instead of plotting graphs the classical way, I decided to go further and plot a graph similar to Alexey Tutubalin&#8217;s, again using data obtained fully automatically and, as I hope, with greater accuracy. For this, I wrote and used this numpy function:<\/p>\n<pre><code class=\"python\">def find_real_resolution(image_resolution, ground_truth, noisy_image):      stock_contrast = np.max(ground_truth) \/ np.min(ground_truth)      noise = np.mean(np.abs(noisy_image - ground_truth))      real_contrast = (np.max(ground_truth) - noise) \/ (np.min(ground_truth) + noise)      contrast_change_coefficient = stock_contrast \/ real_contrast      real_resolution = image_resolution \/ contrast_change_coefficient      return real_resolution<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>More about it:<\/summary>\n<div class=\"spoiler__content\">\n<p><code>image_resolution<\/code> &#8212; the resolution of the entire frame (as in this case only a cropped part of 100&#215;100 pixels was tested), <code>ground_truth<\/code> &#8212; the reference image, <code>noisy_image<\/code> &#8212; the tested image from the series. As you understand, all frames in the series just need to be passed through this function. But what does it do?<\/p>\n<p>Let&#8217;s take another look at the resolution test target:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/4f6\/561\/8fe\/4f65618fe8337acceba33dc75289dc65.jpeg\" width=\"426\" height=\"689\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4f6\/561\/8fe\/4f65618fe8337acceba33dc75289dc65.jpeg\" data-blurred=\"true\"\/><\/figure>\n<p>In the worst case, noise will decrease the value of the white background and increase the value of the black lines, leading to a reduction in contrast, and consequently a drop in the resolution for the given target. Therefore, I first find the \u201caverage noise\u201d of each frame (line 2\u00a0inside the function), then subtract it from the white point of the reference image and add it to the black point of the same image (line 3). Then, I compare (line 4) the original (line 1) and the new (line 3) contrast, after which I simply divide (line 5) the entire frame&#8217;s resolution by this coefficient to obtain the actual resolution.<\/p>\n<\/div>\n<\/details>\n<p>The resulting graph looks like this:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c95\/2ec\/d6c\/c952ecd6c9a9f7c7fe65cff1b6a6c33b.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c95\/2ec\/d6c\/c952ecd6c9a9f7c7fe65cff1b6a6c33b.png\"\/><\/figure>\n<p><em>Values below 0 are shown for illustrative purposes only.<\/em><\/p>\n<p>As mentioned earlier, such a graph can be used to compare two sensors to understand, for example, which one to choose for specific lighting conditions. Alternatively, one can investigate the graph of a single sensor to determine the optimal exposure strategy and to develop the best post\u2011processing algorithms, such as noise reduction.<\/p>\n<h2>Further Research<\/h2>\n<p>For a further work I would like to note the following opportunities:<\/p>\n<ul>\n<li>\n<p>Splitting Bayer filter into channels before the analysis. If the camera&#8217;s autofocus pixels are only blue ones, it would be interesting to compare them with those without autofocus (e.g., one of the green channels).<\/p>\n<\/li>\n<li>\n<p>Using this method for processed, non\u2011RAW images. This would be useful not only for visually evaluating the performance of noise reduction algorithms in post\u2011processing but also for understanding how much real detail they preserve. It could aid in the development of new algorithms related to detail recovery and noise reduction, possibly even neural network\u2011based.<\/p>\n<\/li>\n<li>\n<p>Modification of the method for video use. It could involve displaying new pink noise images frame by frame on a high\u2011refresh\u2011rate monitor. However, the program analyzing such video should know when each frame was displayed. This could be achieved by providing auxiliary information (e.g., frame number, possibly encoded in a QR code) alongside the main target. Such a system would be resistant to temporal noise reduction methods commonly used in video.<\/p>\n<\/li>\n<li>\n<p>Employing more accurate calculations, possibly relying on statistical analysis, to determine real resolution.<\/p>\n<\/li>\n<li>\n<p>Using different image quality evaluation metrics to present results. For example, here is SSIM:<\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/67e\/87a\/dd7\/67e87add759bc899e443281acbc540ea.png\" width=\"1920\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/67e\/87a\/dd7\/67e87add759bc899e443281acbc540ea.png\"\/><\/figure>\n<p>That&#8217;s all for now, thanks for reading!<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/766324\/\"> https:\/\/habr.com\/ru\/articles\/766324\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>Introduction<\/h2>\n<p>Hello, everyone! In this post, let&#8217;s talk about how to (more) accurately measure the dynamic range of a camera sensor and what can be done with these measurements.<\/p>\n<p>Of course, I am not an expert in computer vision, a programmer or a statistician, so please feel free to correct me in the comments if I make mistakes in this post. Here my interest was primarily focused on everyday and practical tasks, such as photography, but I believe the results may also be useful to computer vision professionals.<\/p>\n<hr\/>\n<p>Update: mistakes were found here after publishing this post on the DPReview forum. I think it is important to note that here, and <a href=\"https:\/\/www.dpreview.com\/forums\/thread\/4731088\" rel=\"noopener noreferrer nofollow\">here is the link to the thread itself<\/a><\/p>\n<hr\/>\n<h2>Existing Problem<\/h2>\n<p>The dynamic range of modern image sensors is limited; we cannot capture detail in very bright highlights and very dark shadows simultaneously without degrading the image quality due to noise. In general, the noise, in my opinion, is the most limiting factor for image quality today. The darker the scene, the more noise there is in the shadows, which when the image becomes darker increases in amplitude more and more, progressively \u201ceating away\u201d detail, especially that of low\u2011contrast objects.<\/p>\n<h2>Why Measure Dynamic Range<\/h2>\n<p>In general, accurate dynamic range measurements can be used by both photographers (not only enthusiasts but also professionals) and computer vision specialists to evaluate some equipment.<\/p>\n<p>Firstly, measurements help to answer the question of which camera or sensor to choose for the future tasks or whether an upgrade is worth it\u00a0\u2014 to what extent the advantage will be noticeable. Secondly, through measurements, one can analyze an existing camera or sensor to find an optimal exposure and post\u2011processing strategy and also use the data for further research.<\/p>\n<h2>How Sensor Dynamic Range is Currently Measured<\/h2>\n<p><em>In this chapter, I am using the method and data from Bill Claff&#8217;s website, <\/em><a href=\"https:\/\/www.photonstophotos.net\/\" rel=\"noopener noreferrer nofollow\"><em>Photons to Photos<\/em><\/a><em>.<\/em><\/p>\n<p><a href=\"https:\/\/www.photonstophotos.net\/GeneralTopics\/Sensors_&amp;_Raw\/Sensor_Analysis_Primer\/Engineering_and_Photographic_Dynamic_Range.htm\" rel=\"noopener noreferrer nofollow\">The current method of measuring dynamic range<\/a> begins with the plotting of a graph of the signal-to-noise ratio for a specific ISO at different exposure values, as illustrated below:<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>In general, there are engineering and so-called photographic dynamic ranges. Here is what Mr. Claff writes regarding the first:<\/p>\n<blockquote>\n<p>The low endpoint for Engineering Dynamic Range is determined by where the SNR curve crosses the value of 1.<\/p>\n<p>Here is an extreme close-up of that area of the Photon Transfer Curve:<\/p>\n<\/blockquote>\n<figure class=\"full-width\"><\/figure>\n<blockquote>\n<p>The ISO 100\u00a0line crosses 0\u00a0(the log<sub>2<\/sub>(1)) at 1.63\u00a0EV.<\/p>\n<p>So Engineering Dynamic Range is 14.00\u00a0EV\u00a0\u2014 1.63\u00a0EV = 12.37\u00a0EV.<\/p>\n<p>Or, if we use the White Level (from <a href=\"https:\/\/www.photonstophotos.net\/GeneralTopics\/Sensors_&amp;_Raw\/Sensor_Analysis_Primer\/White_Level.htm\" rel=\"noopener noreferrer nofollow\"><u>White Level<\/u><\/a>), (14.00\u00a0EV\u00a0\u2014 0.11\u00a0EV)\u00a0\u2014 1.63\u00a0EV = 12.26\u00a0EV.<\/p>\n<\/blockquote>\n<p>For comparison, here is the definition of the so-called photographic dynamic range:<\/p>\n<blockquote>\n<p>My definition of Photographic Dynamic Range is a low endpoint with an SNR of 20\u00a0when adjusted for the appropriate Circle Of Confusion (COC) for the sensor.<\/p>\n<p>For the D300\u00a0the SNR values on this curve is for a 5.5\u00a0micron square photosite.<\/p>\n<p>To correct for a COC of.022mm we are looking for a log<sub>2<\/sub> SNR value of 2.49.<\/p>\n<p>Here is an close\u2011up of the area of the curve:<\/p>\n<\/blockquote>\n<figure class=\"full-width\"><\/figure>\n<blockquote>\n<p>Note that the ISO 100\u00a0crosses 2.49\u00a0at 5.00\u00a0EV.<\/p>\n<p>So Photographic Dynamic Range at ISO 100\u00a0is 14.00\u00a0EV\u00a0\u2014 5.00\u00a0EV = 9.00\u00a0EV.<\/p>\n<p>Or, if we use the White Level (from <a href=\"https:\/\/www.photonstophotos.net\/GeneralTopics\/Sensors_&amp;_Raw\/Sensor_Analysis_Primer\/White_Level.htm\" rel=\"noopener noreferrer nofollow\"><u>White Level<\/u><\/a>), (14.00\u00a0EV\u00a0\u2014 0.11\u00a0EV)\u00a0\u2014 5.00\u00a0EV = 8.89\u00a0EV.<\/p>\n<\/blockquote>\n<p>The graphs obtained after such measurements can be found here\u00a0\u2014 <a href=\"https:\/\/www.photonstophotos.net\/Charts\/PDR.htm\" rel=\"noopener noreferrer nofollow\">Photographic Dynamic Range versus ISO Setting<\/a>.<\/p>\n<p>For example, here is what the data looks like for the Pentax K-1:<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>However, choosing an exposure strategy based solely on this graph is not the best idea because some cameras are so\u2011called ISO\u2011less. This means that increasing the ISO in the camera before capturing the image will not improve the noisy shadow detail but will only destroy highlight one.<\/p>\n<p>Therefore, another graph is needed as well\u00a0\u2014 such as this one\u00a0\u2014 that shows <a href=\"https:\/\/www.photonstophotos.net\/Charts\/PDR_Shadow.htm\" rel=\"noopener noreferrer nofollow\">shadow improvement versus ISO setting<\/a>:<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>Indeed, the chosen camera turned out to be ISO\u2011less, meaning that increasing ISO beyond 100\u00a0will not improve the shadow detail.<\/p>\n<p>For clarity, here are two frames from the same camera <a href=\"https:\/\/www.dpreview.com\/reviews\/image-comparison\/fullscreen?attr134_0=pentax_k1&amp;attr134_1=pentax_k1&amp;attr134_2=pentax_k1&amp;attr134_3=pentax_k1&amp;attr136_0=6&amp;attr136_1=1&amp;attr136_2=3&amp;attr136_3=2&amp;attr403_0=1&amp;attr403_1=1&amp;attr403_2=1&amp;attr403_3=1&amp;normalization=full&amp;widget=487&amp;x=0.151173145&amp;y=0.5005349\" rel=\"noopener noreferrer nofollow\">by DPReview<\/a>\u00a0\u2014 one at ISO 3200\u00a0with exposure increased by one stop, and another at ISO 100\u00a0with exposure increased by 6\u00a0stops:<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>But this doesn&#8217;t apply to all cameras. For example, here is the Canon 6D, increasing ISO indeed improves the shadows:<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>One cannot say that the camera is necessarily better or worse solely because of this characteristic, but it does influence the choice of an optimal exposure strategy during shooting.<\/p>\n<h2>Shortcoming of Such Measurement Method<\/h2>\n<p>The problem with such a classical approach arises when a camera uses noise reduction. Yes, these are still RAW files, it&#8217;s just that noise reduction can be applied even before demosaicing. As seen in the graph below, the dynamic range sharply increases at ISO 640:<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>This does not necessarily mean that the image quality has actually improved. On the contrary, noise reduction could have destroyed some fine detail.<\/p>\n<p>On the Shadow Improvement chart, the advantage is even more apparent\u00a0\u2014 reaching almost 2\u00a0stops:<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>In reality, as you understand, things won&#8217;t be as great. This is the problem with the classical measurement approach\u00a0\u2014 DSP algorithms, such as noise reduction and detail recovery, can only be detected (which is what the triangles pointing down on the graph represent), but their actual impact on image quality cannot be accurately assessed.<\/p>\n<h2>A more advanced method of dynamic range measurement<\/h2>\n<p>You are likely familiar with the <a href=\"https:\/\/www.libraw.org\/\" rel=\"noopener noreferrer nofollow\">libraw<\/a> library, and perhaps even use it. The developer of this library, Alexey Tutubalin (\u0410\u043b\u0435\u043a\u0441\u0435\u0439 \u0422\u0443\u0442\u0443\u0431\u0430\u043b\u0438\u043d), <a href=\"https:\/\/blog.lexa.ru\/2017\/08\/25\/novyy_staryy_podhod_k_dinamicheskomu_diapazonu_na_primere_kamery_canon_eos_5d_iv.html\" rel=\"noopener noreferrer nofollow\">proposed<\/a> his way of measuring dynamic range back in 2017. He pondered the question of how much real resolution remains in an image due to the influence of noise. For this, Alexey used a low\u2011contrast rotated target to test the resolution. The rotation was introduced to challenge the internal DSP algorithms in the camera, in case such algorithms were present. It looked like this:<\/p>\n<figure class=\"full-width\"><\/figure>\n<figure class=\"full-width\"><\/figure>\n<p>After a series of shots and a semi-automatic analysis of results, this interesting graph was obtained:<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>In my opinion, the data turned out to be incredibly useful and illustrative, but I wanted to replicate the results using fully automated measurements and metrics, ensuring that the developed method is accessible to everyone in home conditions.<\/p>\n<h2>Proposed Solution<\/h2>\n<p>I believe that testing resolution using special targets might lead to potential cheating attempts by the camera. The target should have resolution, i.e., detail, higher than that of a sensor. Therefore, we need a target with a large number of small details that cannot be tampered with\u00a0\u2014 essentially just noise. However, we cannot use ordinary noise, as it would decrease as the camera moves away from the target. So, we need a special, scale\u2011invariant pink noise.<\/p>\n<p>Imatest sells such targets for $330:<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>I just printed such a square on a regular printer on an A4 sheet.<\/p>\n<p>Unfortunately, I don&#8217;t have a standalone camera, so the testing was done on a regular phone with a SONY IMX686\u00a0sensor. I used the <a href=\"https:\/\/github.com\/KillerInk\/FreeDcam\" rel=\"noopener noreferrer nofollow\">FreeDCam<\/a> app, controlled it from a PC using <a href=\"https:\/\/github.com\/Genymobile\/scrcpy\" rel=\"noopener noreferrer nofollow\">scrcpy<\/a> to avoid moving the phone between frames (in the case of a real camera, it would need to be placed on a tripod and remotely controlled from the PC). After that, I took series of shots of the resulting target at different ISOs with different exposures, from 1\u00a0to 12\u00a0stops below sensor saturation (careful readers will notice that, in fact, the lines on the graph are cut off before 12\u00a0stops at ISO 3200\u00a0and 6400\u00a0\u2014 FreeDCam simply does not have such short exposure time settings). The captured frames were converted into linear 16-bit TIFF without demosaicing but with white balance applied through channel amplification. Then they were analyzed relative to the reference frame\u00a0\u2014 10\u00a0averaged frames of the target taken at one stop below sensor saturation\u00a0\u2014 equivalent to a frame at ISO 5\u00a0with ideal exposure.<\/p>\n<p>The resulting graph shows the signal\u2011to\u2011noise ratio:<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>Unlike Mr. Claff&#8217;s graph, this graph, if not entirely, at least partially, is resistant to DSP\u00a0\u2014 please pay attention to the lower values at ISO 3200\u00a0and 6400, which are likely signs of noise reduction. Although the graph is not entirely free from its influence, there is no improvement relative to the upper values. Therefore, the obtained data has higher quality than the one that would be obtained by the standard method. In fact, I tested my phone without actual pink noise, so using real pink noise (which can be generated, for example, using functions from <a href=\"https:\/\/github.com\/VileBile\/colorednoise_2d\" rel=\"noopener noreferrer nofollow\">here<\/a>) will likely only improve the result.<\/p>\n<p>Instead of plotting graphs the classical way, I decided to go further and plot a graph similar to Alexey Tutubalin&#8217;s, again using data obtained fully automatically and, as I hope, with greater accuracy. For this, I wrote and used this numpy function:<\/p>\n<pre><code class=\"python\">def find_real_resolution(image_resolution, ground_truth, noisy_image):      stock_contrast = np.max(ground_truth) \/ np.min(ground_truth)      noise = np.mean(np.abs(noisy_image - ground_truth))      real_contrast = (np.max(ground_truth) - noise) \/ (np.min(ground_truth) + noise)      contrast_change_coefficient = stock_contrast \/ real_contrast      real_resolution = image_resolution \/ contrast_change_coefficient      return real_resolution<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>More about it:<\/summary>\n<div class=\"spoiler__content\">\n<p><code>image_resolution<\/code> &#8212; the resolution of the entire frame (as in this case only a cropped part of 100&#215;100 pixels was tested), <code>ground_truth<\/code> &#8212; the reference image, <code>noisy_image<\/code> &#8212; the tested image from the series. As you understand, all frames in the series just need to be passed through this function. But what does it do?<\/p>\n<p>Let&#8217;s take another look at the resolution test target:<\/p>\n<figure class=\"\"><\/figure>\n<p>In the worst case, noise will decrease the value of the white background and increase the value of the black lines, leading to a reduction in contrast, and consequently a drop in the resolution for the given target. Therefore, I first find the \u201caverage noise\u201d of each frame (line 2\u00a0inside the function), then subtract it from the white point of the reference image and add it to the black point of the same image (line 3). Then, I compare (line 4)<\/p>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-357043","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/357043","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=357043"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/357043\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=357043"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=357043"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=357043"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}