Colormap that "stacks" in an additive way?

60 views Asked by At

I would like to find a colormap so that images made with it are "additive" in opacity, or alpha channel, mix-blend-mode or some other similar way. So, when I "stack" the images one on top of the other, I get a third image, that image is in the same colormap, and the colors are those that would have been chosen had I "added" the two images. Possibly this thing does not exist, and that is a satisfactory answer. Preferably, this solution scales to arbitrary numbers of images, i.e. I can stack 50 images one atop the other, and the result would be the same as a single image representing the "addition" of the values corresponding to the colors.

By "additive" I mean the following. Consider the following three datasets:

enter image description here [FIGURE 1]

These are each 49 values along a linear scale from 0 to 1 (the leftmost is np.linspace(0,1,49).reshape(7,7)). The middle is the transpose of the one on the left, and the one on the right is random values from 0-1. The colormap is viridis. When I add the leftmost matrix to each of these, I get the following:

enter image description here [FIGURE 2]

So, from left to right in figure 2 we have here left+left, middle+left, right+left (for left, middle, right in figure 1). This is regular component-wise matrix addition, and then plotting the resulting sum.

What I would like to be able to do is to "stack" the individual images from figure 1 using html/css, and get something resembling the images in figure 2.

The variables that I know that I can change are 1) the colormap (globally, for all images), 2) the opacity (for individual images), 3) the alpha channel (for individual images), 4) mix-blend-mode (for individual images). Possibly there are other variables that I don't know of.

Is it possible to "stack" the images in a way that results in matrix addition?

Here are a couple of attempts:

enter image description here [FIGURE 3: opacity 50%. viridis colormap. Let "|" represent "stacking", then, from left to right, we have left|left, left|middle, left|right for left,middle,right in figure 1]

enter image description here [FIGURE 4: opacity 50%. matplotlib "binary" colormap. Let "|" represent "stacking", then, from left to right, we have left|left, left|middle, left|right for left,middle,right in figure 1]

enter image description here [FIGURE 5: additional random matrix generated RAND (not shown). the image on top is left+RAND (matrix addition). The image below is left|RAND (image stacking), colormap "binary", opacity 100% for the "bottom" image and opacity 50% for the "top" image.]

Figure 5 shows a combination that is pretty close to matrix addition. You can see that it's not quite the same e.g. in the cell row=2 col=1.

enter image description here [FIGURE 6: same layout as in figure 5, with white mapped to 0 (instead of the minimum value), black mapped to 1 in the original matrices (left and also RAND), and white->0, black->2 in left+RAND]

Figure 6 shows the effect of choosing the lower and upper bound values of the colormap, which also seem relevant. I'm not entirely confident, but this seems to work at least for grayscale and exactly two images.

enter image description here [FIGURE 7: similar layout as in figures 5 and 6, with fixed upper and lower bounds. The upper image is left+RAND+RAND, and the lower image is left|RAND|RAND. The lower image is opacity 100%, and the second and third images are opacity 50%.]

Figure 7 shows that the opacity 50% for the top image doesn't seem to scale to more than two images. rows 3 and 4 in the last column are extremely close, but not quite identical between the two images.

Here is python code to generate the individual images:

DATA = "geoopacity_data/"
RAND = np.random.uniform(size=49).reshape(7,7)

def plotfigs(cmap):
    fig, ax = plt.subplots()
    ax.imshow(np.linspace(0,1,49).reshape(7,7), cmap=cmap)
    ax.axis('off')
    fig.savefig(DATA + "{}1.png".format(cmap), bbox_inches='tight')

    fig, ax = plt.subplots()
    ax.imshow(np.linspace(0,1,49).reshape(7,7).T, cmap=cmap)
    ax.axis('off')
    fig.savefig(DATA + "{}2.png".format(cmap), bbox_inches='tight')
    
    fig, ax = plt.subplots()
    ax.imshow(RAND, cmap=cmap)
    ax.axis('off')
    fig.savefig(DATA + "{}3.png".format(cmap), bbox_inches='tight')
def plotref(cmap):
    d1 = np.linspace(0,1,49).reshape(7,7)
    d2 = np.linspace(0,1,49).reshape(7,7).T
    d3 = RAND
    
    d11 = d1 + d1
    d12 = d1 + d2
    d13 = d1 + d3
    
    fig, ax = plt.subplots()
    ax.imshow(d11, cmap=cmap)
    ax.axis('off')
    fig.savefig(DATA + "{}ref11.png".format(cmap), bbox_inches='tight')

    fig, ax = plt.subplots()
    ax.imshow(d12, cmap=cmap)
    ax.axis('off')
    fig.savefig(DATA + "{}ref12.png".format(cmap), bbox_inches='tight')
    
    fig, ax = plt.subplots()
    ax.imshow(d13, cmap=cmap)
    ax.axis('off')
    fig.savefig(DATA + "{}ref13.png".format(cmap), bbox_inches='tight')
def plotref2(cmap):
    d1 = np.linspace(0,1,49).reshape(7,7)
    d2 = np.linspace(0,1,49).reshape(7,7).T
    d3 = RAND
    
    d11 = d1 + d1 + d1
    d12 = d1 + d2 + d2
    d13 = d1 + d3 + d3
    
    fig, ax = plt.subplots()
    ax.imshow(d11, cmap=cmap)
    ax.axis('off')
    fig.savefig(DATA + "{}ref111.png".format(cmap), bbox_inches='tight')

    fig, ax = plt.subplots()
    ax.imshow(d12, cmap=cmap)
    ax.axis('off')
    fig.savefig(DATA + "{}ref122.png".format(cmap), bbox_inches='tight')
    
    fig, ax = plt.subplots()
    ax.imshow(d13, cmap=cmap)
    ax.axis('off')
    fig.savefig(DATA + "{}ref133.png".format(cmap), bbox_inches='tight')
    
plotfigs("viridis")
plotfigs("binary")
plotref("binary")
plotref2("binary")

Here is an html page to view the results:

<!doctype html>
<html>
  <head>
    <title>This is the title of the webpage!</title>
    <style>
      img {
        opacity: 100%;
        left: 0;
      }
      .im {
        position: relative;
        display: inline-block;
      }
      .top {
        position: absolute;
        opacity: 50%;
      }
      .second {
        position: absolute;
        opacity: 50%;
      }
      .third {
        position: absolute;
        opacity: 50%;
      }
    </style>
  </head>
  <body>
    <div class="row">
      <div class="im">
        <img src="viridis1.png" style="opacity: 100%;"/>
      </div>
      <div class="im">
        <img src="viridis2.png" style="opacity: 100%;"/>
      </div>
      <div class="im">
        <img src="viridis3.png" style="opacity: 100%;"/>
      </div>
    </div>
    <div class="row">
      <div class="im">
        <img src="viridisref11.png" style="opacity: 100%;"/>
      </div>
      <div class="im">
        <img src="viridisref12.png" style="opacity: 100%;"/>
      </div>
      <div class="im">
        <img src="viridisref13.png" style="opacity: 100%;"/>
      </div>
    </div>
    <div class="row">
      <div class="im">
        <img src="viridis1.png"/>
        <img src="viridis1.png" class="top"/>
      </div>
      <div class="im">
        <img src="viridis1.png"/>
        <img src="viridis2.png" class="top"/>
      </div>
      <div class="im">
        <img src="viridis1.png"/>
        <img src="viridis3.png" class="top"/>
      </div>
    </div>
    <div class="row">
      <div class="im">
        <img src="binaryref11.png" style="opacity: 100%;"/>
      </div>
      <div class="im">
        <img src="binaryref12.png" style="opacity: 100%;"/>
      </div>
      <div class="im">
        <img src="binaryref13.png" style="opacity: 100%;"/>
      </div>
    </div>
    <div class="row">
      <div class="im">
        <img src="binary1.png"/>
        <img src="binary1.png" class="top"/>
      </div>
      <div class="im">
        <img src="binary1.png"/>
        <img src="binary2.png" class="top"/>
      </div>
      <div class="im">
        <img src="binary1.png"/>
        <img src="binary3.png" class="top"/>
      </div>
    </div>
    <div class="row">
      <div class="im">
        <img src="binaryref111.png" style="opacity: 100%;"/>
      </div>
      <div class="im">
        <img src="binaryref122.png" style="opacity: 100%;"/>
      </div>
      <div class="im">
        <img src="binaryref133.png" style="opacity: 100%;"/>
      </div>
    </div>
    <div class="row">
      <div class="im">
        <img src="binary1.png"/>
        <img src="binary1.png" class="second"/>
        <img src="binary1.png" class="third"/>
      </div>
      <div class="im">
        <img src="binary1.png"/>
        <img src="binary2.png" class="second"/>
        <img src="binary2.png" class="third"/>
      </div>
      <div class="im">
        <img src="binary1.png"/>
        <img src="binary3.png" class="second"/>
        <img src="binary3.png" class="third"/>
      </div>
    </div>
  </body>
</html>
0

There are 0 answers