The next button is the Sharpen button, which sharpens an image by accenting the borders between colors. You can see image.gif after it has been sharpened in Figure 3.5 (the sharpening may not be totally evident with the limited-resolution image in the figure, but it's very clear when you run the Graphicizer and click the Sharpen button). Figure 3.5. Sharpening an image.As with embossing an image, you have to work pixel by pixel to sharpen an image. That could mean a lot of work, as you just saw when embossing. However, if you don't want to do anything too fancy, there's an easier way to work pixel by pixel and combine a pixel with its surrounding neighborsyou can use the Kernel class and the ConvolveOp class to do the work for you. The Kernel class lets you define a matrix that specifies how a pixel should be combined with the other pixels around it to produce a new result, and the ConvolveOp class lets you apply a kernel to a BufferedImage object, pixel by pixel. You can see the significant methods of the Kernel object in Table 3.6 and the significant methods of the ConvolveOp class in Table 3.7.
Here's how this all works for sharpening an image when the Sharpen button is clicked. After storing the present buffered image in the image backup, bufferedImageBackup (in case the user wants to undo the sharpening operation), the code creates a new kernel for the operation. A kernel is really a matrix that will multiply a pixel and its neighbors. Here is the kernel you can use to sharpen the image; you pass the Kernel constructor thee dimensions of the matrix and then the matrix itself: public void actionPerformed(ActionEvent event) { . . . if(event.getSource() == button2){ bufferedImageBackup = bufferedImage; Kernel kernel = new Kernel(3, 3, new float[] { 0.0f, -1.0f, 0.0f, -1.0f, 5.0f, -1.0f, 0.0f, -1.0f, 0.0f }); . . . Now you've got to apply the new kernel to the image, which you do with the ConvolveOp class's filter method. As you'll recall, there were problems when embossing the image with the pixels at the edge of the image, because what we did involved combining pixels with their neighbors. To handle that situation when filtering with ConvolveOp, you can pass the filter method the constant ConvolveOp.EDGE_NO_OP, which means that pixels at the edge of the image will be copied to the destination image without modification. (The other option is ConvolveOp.EDGE_ZERO_FILL, which means that pixels at the edge of the destination image will be set to zero.) You also can pass an object to the ConvolveOp constructor that will give ConvolveOp some hints on how to draw the image, but that's not needed here. Therefore, the code just passes null as the third parameter to the ConvolveOp constructor: public void actionPerformed(ActionEvent event) { . . . if(event.getSource() == button2){ bufferedImageBackup = bufferedImage; Kernel kernel = new Kernel(3, 3, new float[] { 0.0f, -1.0f, 0.0f, -1.0f, 5.0f, -1.0f, 0.0f, -1.0f, 0.0f }); ConvolveOp convolveOp = new ConvolveOp( kernel, ConvolveOp.EDGE_NO_OP, null); . . . Now you're ready to sharpen the image with the filter method. You pass this method a source image and a destination image, and after the filtering is done, the code will copy the new image over into the image displayed by Graphicizer, bufferedImage, and repaint that image this way: public void actionPerformed(ActionEvent event) { . . . if(event.getSource() == button2){ bufferedImageBackup = bufferedImage; Kernel kernel = new Kernel(3, 3, new float[] { 0.0f, -1.0f, 0.0f, -1.0f, 5.0f, -1.0f, 0.0f, -1.0f, 0.0f }); ConvolveOp convolveOp = new ConvolveOp( kernel, ConvolveOp.EDGE_NO_OP, null); BufferedImage temp = new BufferedImage( bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_INT_ARGB); convolveOp.filter(bufferedImage, temp); bufferedImage = temp; repaint(); } That's all it takes; the results appear in Figure 3.5. |