IL Morphine

Image-Line Morphine является аддитивным синтезатором. Аддитивный синтез создаёт звук целиком из гармоник в виде синусов и на первый взгляд это может показаться ограничением. Тем не менее, теорема…

Smartphone

独家优惠奖金 100% 高达 1 BTC + 180 免费旋转




Color Correction with JavaScript

Poor Man’s Atmospheric Adjustment for a Pretty Glacier Picture

The default Sentinel Hub rendering shown in the image below has some issues, though: the waters and coastal vegetation are too dark, the snow-covered peaks look over-exposed and are all flat white, and there is a bluish tint across the whole image.

I first choose the date of May 5th, 2016, and then set cloud cover filter to 100% to make sure that I get the image of the full swath, even if some of the neighboring tiles are cloudy. After switching to ‘custom script’ rendering mode, I get the following script:

The script maps reflectances from bands 4, 3 and 2 into red, green and blue components of the output color. The default gain factor is set to 2.5, which corresponds to white-point reflectance of 40% (a pixel with 40% or more reflectance in all three bands will appear white in the resulting image). I will deal with white-point selection later, so I set this factor to 1 for now.

Encoding into proper sRGB values reveals the fact that the image was taken by a sensor orbiting 800 km above ground, looking through about 10 km of atmosphere. The bluish veil that covers the scene is caused by scattering of sunlight by atmospheric particles — it is the same blue thing that we normally call the sky but this time we’re looking at it in the opposite direction.

The effect can be largely removed by simply subtracting some small constant from the reflectance values in each band. To determine the optimal amount and prevent me from darkening the image too much, I added some code to highlight pixels whose components become negative after adjustment.

Using this rendering, I choose the offsets for atmospheric adjustment in such a way that very few pixels get highlighted, and I get as many different colors as possible. As I increase the offsets, the image becomes noticeably less hazy, showing vivid colors and enhanced contrasts.

I want to keep a non-zero blue component over water, so I don’t mind if highlights are mostly red and green there. In the image that I’m working with, appropriate offsets seem to be around 4 %, 7 % and 12 % for red, green and blue bands, respectively. Other images will have different atmospheric conditions, so other offsets should be chosen.

Once I’ve compensated for the offset in the measured radiance, I add some multiplicative factors to each component, to ensure that white things in the image appear truly white. Again I start by highlighting the pixels that have some component larger than 1 with the following:

As for the selection of factors, I can get pretty nice results by assuming that they are related to the offset c0 that I’ve determined already: the surface is illuminated by all the light coming from the sun except the part that was scattered and reflected back into space. The illumination of the surface is therefore proportional to (1 - c0). Once the light is reflected and travels back towards the satellite, some of it gets lost again, which means that the total flux has to be multiplied by (1 - c0) again. The resulting full atmospheric adjustment code is then simply:

The image shows the highlighted colors to be quite nicely distributed, especially considering the very crude atmospheric model that I’ve derived with some hand-waving and wishful thinking*.

The image above shows many highlighted pixels, where reflectance values are higher than 100%. This often happens on snow-covered sun-facing slopes, especially when the sun’s angle is low, which is usually true for any image taken around the poles, such as this one.

To prevent flattening of these very bright peaks, I add another constant, max, which I use to scale reflectance values when converting to output color components. Thus I can fine-tune the contrast so that only the very brightest pixels appear white. The resulting image, after setting max = 3, starts too look really nice — the scaling brings out lovely details in the snowy slopes of the mountain and the cracks and ridges of the glaciers.

The stretched image is compelling, but a lot of the contrast was lost in the darker coastal areas, especially in the shadows. To bring that back, I first modify the scaling function and split the linear adjustment function into two parts, forming a piecewise linear function which increases contrast in the dark areas without decreasing it too much in the bright regions.

The result looks nice, but it appears that the sharp break in the adjustment function creates some strange unnatural shading in the snow-covered slopes.

To try and improve that, I replace the straight-line piecewise function with a smoother version, based on a function that is the quotient of two polynomials and matches the slopes of the original at both extreme ends of the reflectance range. The parameters of this function are the same, but the output is much smoother.

Output color value vs. input reflectance for the adjustment functions used: linear (blue); sharp piecewise linear (green); smoothed version of the piecewise linear function (orange).

The resulting image retains most of the contrast across the brightness range and removes the artifacts caused by the sharp break, which means that I’m almost finished.

Any nonlinear adjustment curve applied on the individual r, g, b components will inevitably change the saturation of the rendered colors. Concave curves, such as the one I used, decrease the saturation (because larger components are effectively multiplied by a smaller contrast factor), and that makes the image a bit dull.

This can be corrected with a very crude method of saturation enhancement which increases the distance of the three color components from their average. I select a moderate amount of correction to accentuate the light blue color of the glacial ice, while making sure that the rocks and vegetation don’t look too artificial.

It took me a while to get here, but I think the final image looks pretty good. And the script is not too complicated, so it should be quite useful for lots of other scenes and potentially adjusted to render something other than glaciers.

The following script performs all of the steps mentioned in this article, and supports different options of atmospheric compensation:

I leave you with the full quote from The Voyage of H.M.S. Beagle:

Add a comment

Related posts:

Cuento

si el tacto desintegrara y las miradas fijas convirtieran cuerpos en piedra quizás sería más humano ese espanto del que nos curamos la comodidad sería arrancarme la cabeza y meterla en la heladera…

FITNESS INSTRUMENTS

Fitness instruments are tools used by fitness enthusiasts and professionals to measure and monitor various aspects of physical health, such as heart rate, blood pressure, body composition, and…

How the Lincoln Memorial was Built

One of the most iconic memorials in DC is the massive Lincoln memorial sitting across the Reflecting Pool in the heart of the capital. The process of creating this monument was, of course, highly…