Recipe 8.12. Using Threshold


Problem

You want to change the value of some pixels in a bitmap, based on their current value.

Solution

Use the threshold( ) method of the BitmapData class.

Discussion

The threshold( ) method is probably the most complex in the BitmapData API, but quite powerful once you understand how it works. The method uses two BitmapData objects:

  • destBitmap, which is the bitmap that will be altered.

  • sourceBitmap, which is the other bitmap that gets passed in as a parameter. The method uses this bitmap's pixel data for its calculations.

The method compares each pixel in sourceBitmap against a specified value, using one of six comparison operators. If the comparison fails, the corresponding pixel in destBitmap is set to a specified color value. If it passes the comparison, the pixel is either not changed, or you have the option of copying over the sourceBitmap's value for that pixel.

Here is the syntax for the method:

destBitmap.threshold(sourceBitmap,                      sourceRect,                      destPoint,                      operation,                      threshold,                      color,                      mask,                      copySource)

We've already covered destBitmap and sourceBitmap. The next parameter, sourceRect, is an instance of the flash.geom.Rectangle class. It defines what portion of the sourceBitmap you want to use for comparison. If you want to use the entire bitmap, you can pass in sourceBitmap.rect as a value to this parameter.

The destPoint parameter specifies the point in the destBitmap at which the pixels start to be affected. Picture the sourceBitmap overlaid on destBitmap, with its top-left corner on this point. If you want to use 0, 0 as the origin, just pass new Point( ) to this parameter.

The operation parameter is one of six strings that are equivalent to the comparison operators in ActionScript. They are <, <=, >, >=, ==, and !=. For example, if you specify < as an operation, the test passes for a given pixel if its value is less than the threshold value, and it fails if it is greater than that.

Next is threshold. Each pixel is compared against this value. You can pass a full 32-bit number in here, and compare each pixel against that, but it may not give you the results you expected. The reason is the way color values work. For example, a pixel of 100 percent red (0xFFFF0000) evaluates as "more than" a pixel of 100 percent blue (0xFF0000FF) or green (0xFF00FF00). So normally what you want to do is use a mask to isolate a specific channel and compare against that.

The mask parameter is the hardest for most people to grasp. All it is doing is isolating a particular color channel. Normally you would just pass a hexadecimal value here, with two zeros (00) for each color channel that you want to mask out, and FF for the channel you want to use. For example, 0x00FF0000 isolates the red channel, and 0xFF000000 isolates the alpha channel. See Figure 8-4 for a breakdown of the channels in a hexadecimal color value.

Figure 8-4. The breakdown of a hexadecimal number


The next two parameters determine what happens when a pixel passes or fails a comparison. The color parameter is the color the corresponding pixel is set to in the destBitmap if the comparison passes. The copySource parameter determines what happens if it fails. If this is true, the sourceBitmap's pixel value for that pixel is copied over to the destBitmap. If it is false, nothing happens for that pixel in the destBitmap; it is left as is.

Now let's see a few examples in action. Here's some sample code that creates a source and destination bitmap and creates some Perlin noise in the source. Then it adds the destination bitmap to the display list and applies a threshold using the source bitmap:

var srcBmp:BitmapData = new BitmapData(stage.stageWidth,                                        stage.stageHeight,                                        true, 0xffffffff); srcBmp.perlinNoise(200, 100, 2, 1000, false, true, 1, true); var destBmp:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0xffffffff); var image:Bitmap = new Bitmap(destBmp); addChild(image); destBmp.threshold(srcBmp,             // sourceBitmap                   srcBmp.rect,        // sourceRectangle                   new Point(  ),        // destPoint                   "<",                // operator                   0x00880000,         // threshold                   0x00000000,         // color                   0x00ff0000,         // mask                   true);              // copySource

Here the method checks to see if a given pixel's red channel (since this is defined in the mask) is less than 0x00880000. If so, it makes that pixel transparent. If not, it copies over the source pixel. Since the Perlin noise was created in grayscale, it doesn't matter which of the three color channels (red, green, or blue) you use. If you are using a full color image as a source, you might want to experiment with different channels to see which gives you the desired effect:

  • As you can see if you run this code, it makes all the darker areas of the Perlin noise pattern transparent.

  • Changing the operator to " >" has the opposite effect, cutting out all the lighter value pixels.

  • Making the threshold value higher or lower, say 0x00330000 or 0x00AA0000, cuts out more or less pixels.

  • Try setting a different color value to see what effect this has. Also try changing copySource to false and see that it does not copy over the pixels, but keeps the original values.

One thing to note is that there is no reason why the source and destination bitmaps cannot be the same bitmap. You can use a bitmap's own pixel data as a threshold. However, realize that you are permanently altering that bitmap, so you won't be able to repeat the operation with the same result, if needed.

As with many of the BitmapData methods, they are often most powerful when used in combination. For example, adding one line to the previous example creates a drop shadow, which pops the pattern into 3D:

destBmp.applyFilter(destBmp, destBmp.rect,                      new Point(  ), new DropShadowFilter(  ));

See Also

Recipes 8.13, 8.14, and 8.15 for other ways to manipulate the content in a bitmap.




ActionScript 3. 0 Cookbook
ActionScript 3.0 Cookbook: Solutions for Flash Platform and Flex Application Developers
ISBN: 0596526954
EAN: 2147483647
Year: 2007
Pages: 351

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net