Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is uniform grey not a neutral DisplacementMap?

I have been trying to generate a specific feDisplacementMap and failing miserably. I believe it's because I have a fundamental misunderstanding of the mechanism. The SVG 1.1 spec says:

This filter primitive uses the pixels values from the image from ‘in2’ to spatially displace the image from ‘in’. This is the transformation to be performed:

P'(x,y) <- P( x + scale * (XC(x,y) - .5), y + scale * (YC(x,y) - .5)) where P(x,y) is the input image, ‘in’, and P'(x,y) is the destination. XC(x,y) and YC(x,y) are the component values of the channel designated by the xChannelSelector and yChannelSelector. For example, to use the R component of ‘in2’ to control displacement in x and the G component of Image2 to control displacement in y, set xChannelSelector to "R" and yChannelSelector to "G".

By my reading, this means a neutral grey image should result in no net pixel movement. Aka in a filter with scale=50, a pixel at 100,100 should get its new value from (100 + 50 * (0.5 - 0.5), 100 + 50*(0.5-0.5)) = 100,100. However when I try a greyscale, it's mapping pixels up and to the left of the source image.

<svg width="800px" height="600px" >
  
  <defs>
    <g id="displacerect">
    <rect x="50" y="50" width="300" height="300" fill="rgb(127, 127, 127)"/>
    <rect x="90" y="90" width="50" height="50" fill="red">
      </rect>
    </g>
    
    
      <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" stop-color="rgb(255,255,0)" stop-opacity="1" />
      <stop offset="100%"stop-color="rgb(255,0,0)" stop-opacity="1" />
    </linearGradient>
  
  <filter id="displaceME" x="0%" y="0%" width="100%" height="100%">
    <feImage xlink:href="#displacerect"  result="displaceImage"/>
    <feDisplacementMap scale="125" xChannelSelector="R" yChannelSelector="G" in="SourceGraphic" in2="displaceImage"/>

 
    </filter>
  
  </defs>
  
  <g filter="url(#displaceME)">
  <rect x="50" y="50" width="300" height="300" fill="url(#grad1)"/>
  </g>
  
  <use xlink:href="#displacerect" x="400"/>
  
 
  
</svg>

According to other sources: the ACTUAL neutral displacement Map should be this image:

enter image description here

like image 211
Michael Mullany Avatar asked Apr 24 '16 20:04

Michael Mullany


1 Answers

I was having a similar problem. My source image and my displacement map image were the same size, so the "neutral" displacement image you showed above couldn't possibly be right. It had to be that the red channel and the green channel had the same constant values across the image for zero shift. I couldn't understand why I had to use 188 for a zero pixel shift instead of 128 like you'd expect. The blog at http://www.tapper-ware.net/blog/?p=39 offered the following hint that solved the problem for me:

color-interpolation-filters="sRGB"

The author's svg code snippet was:

<svg:filter
 id="myFilterId"
 color-interpolation-filters="sRGB" 
 filterUnits="userSpaceOnUse"
 x="0" y="0" width="768" height="512">
</svg:filter>

After specifying the color space to be sRGB it all started working as I expected.

like image 156
Kevin Nash Avatar answered Sep 22 '22 16:09

Kevin Nash