6

I am a beginner in actionscript. If I understand correctly, the DisplacementMapFilter moves pixels from a 'source image' according to the color of the corresponding pixel position in a 'MAP image'.

The problem is that my destination image contains pixels which are NOT in the source image !

For example, I take a UNICOLOR 10 * 10 pixels 'source image' with this BitMapData:

sourceBitmap = new BitmapData(BITMAP_WIDTH, BITMAP_HEIGHT, false, 0x000002);

produce:

  0   1   2   3   4   5   6   7   8   9
[002,002,002,002,002,002,002,002,002,002] Row 0
[002,002,002,002,002,002,002,002,002,002] Row 1
[002,002,002,002,002,002,002,002,002,002] Row 2
[002,002,002,002,002,002,002,002,002,002] Row 3
[002,002,002,002,002,002,002,002,002,002] Row 4
[002,002,002,002,002,002,002,002,002,002] Row 5
[002,002,002,002,002,002,002,002,002,002] Row 6
[002,002,002,002,002,002,002,002,002,002] Row 7
[002,002,002,002,002,002,002,002,002,002] Row 8
[002,002,002,002,002,002,002,002,002,002] Row 9

Now, I take this BLACK displacement MAP and I add a little BLUE square:

displacementBitmap = new BitmapData(BITMAP_WIDTH,BITMAP_HEIGHT,false,0x000000);
for(i=5;i<10;i++)
    for(j=5;j<10;j++)
        displacementBitmap.setPixel(i,j,255);

produce:

 0   1   2   3   4   5   6   7   8   9 
[000,000,000,000,000,000,000,000,000,000] Row 0
[000,000,000,000,000,000,000,000,000,000] Row 1
[000,000,000,000,000,000,000,000,000,000] Row 2
[000,000,000,000,000,000,000,000,000,000] Row 3
[000,000,000,000,000,000,000,000,000,000] Row 4
[000,000,000,000,000,255,255,255,255,255] Row 5
[000,000,000,000,000,255,255,255,255,255] Row 6
[000,000,000,000,000,255,255,255,255,255] Row 7
[000,000,000,000,000,255,255,255,255,255] Row 8
[000,000,000,000,000,255,255,255,255,255] Row 9

The result:

displacementFilter = new DisplacementMapFilter();
displacementFilter.alpha=0;
displacementFilter.color=0;
displacementFilter.mapPoint=new Point(0,0);
displacementFilter.scaleX=1;
displacementFilter.scaleY=1;
displacementFilter.componentX = flash.display.BitmapDataChannel.BLUE;
displacementFilter.componentY = flash.display.BitmapDataChannel.BLUE;
displacementFilter.mapBitmap = displacementBitmap;

destinationBitmap = new BitmapData(BITMAP_WIDTH,BITMAP_HEIGHT,false,0xFFFFFFFF);
destinationBitmap.applyFilter(
    sourceBitmap.bitmapData,
    new Rectangle(0,0,BITMAP_WIDTH,BITMAP_HEIGHT),
    new Point(0,0),
    displacementFilter
);

produce:        

  0   1   2   3   4   5   6   7   8   9 
[002,002,002,002,002,002,002,002,002,002] Row 0
[002,002,002,002,002,002,002,002,002,002] Row 1
[002,002,002,002,002,002,002,002,002,002] Row 2
[002,002,002,002,002,002,002,002,002,002] Row 3
[002,002,002,002,002,002,002,002,002,002] Row 4
[002,002,002,002,002,001,001,001,001,001] Row 5
[002,002,002,002,002,001,001,001,001,001] Row 6
[002,002,002,002,002,001,001,001,001,001] Row 7
[002,002,002,002,002,001,001,001,001,001] Row 8
[002,002,002,002,002,001,001,001,001,001] Row 9

So I don't understand why I have '001' pixels which don't exists in the source image.

Thanks you very much.

James
  • 969
  • 1
  • 8
  • 13
Josh Xoder
  • 67
  • 2
  • 1
    And now, time for a shameless plug to my [question](http://stackoverflow.com/questions/9260717/displacement-map-filter-in-opencv). – karlphillip Mar 29 '12 at 17:05

1 Answers1

3

The displacement map filter decides which pixel to grab from the source bitmap using this formula:

dstPixel[x, y] = srcPixel[x + ((componentX(x, y) - 128) * scaleX) / 256, y + ((componentY(x, y) - 128) *scaleY) / 256)

dstPixel is the destination bitmap, srcPixel is the source bitmap, and componentX/Y is from the displacement bitmap. The mapping is determined by how far away the component channel is from 128. Note that 128 is the neutral value where there is no transformation, and the same source pixel is used.

For example, let's consider the pixel at (1, 1) in your case. Your component channel is blue, and the blue channel at (1, 1) in the displacement map has a value of 0. So we displace by (0 - 128)/256, or -0.5. So the final pixel we grab from the source bitmap is at (0.5, 0.5).

But what does it mean to use half of a pixel? It turns out that Flash uses bilinear filtering to smooth out the results. You end up with a blend of the colors in the four pixels between (0,0) and (1,1).

This is the reason you are seeing odd pixels that aren't in the source image. Even though all of the pixels in your source image are the same color, there seem to be some floating-point inaccuracies when Flash interpolates between colors, so sometimes you get a value that's just slightly off. Notice that if you use a value in your displacement bitmap that divides "cleanly" by 128, such as 0 or 64, then you get the correct result. But if you use a value like 255 or 19, you get some error.

Unfortunately, there doesn't seem to be any way to turn off the filtering and use simple nearest-neighbor sampling. So if you need to guarantee that no new colors are introduced, then you must carefully select the values in your displacement map.

Alternatively, you could use Pixel Bender to create a kernel that does what you need. Pixel Bender allows you to do nearest-neighbor sampling from a source bitmap.

Mike Welsh
  • 1,549
  • 1
  • 9
  • 14