1. Detailed introduction to the project background
In the field of image processing, Sharpening is a common operation to enhance edges and details in an image, making the image look clearer and more layered. In contrast to Blur, sharpening highlights texture and contour by strengthening the contrast of local pixels, and is often used in scenes such as photography, medical image enhancement, and industrial detection.
Photography and post-production: fine-tune the photos to enhance the edge of the subject and enhance the visual impact.
Medical imaging: highlights tissue boundaries and assists in diagnosis.
Industrial inspection: Deepening the profile of cracks or defects for easy automatic identification.
Teaching and Demo: Understanding the principles of image convolution and filters.
This project will use Java SE native APIs (BufferedImage, ConvolveOp, Kernel, ImageIO) to achieve sharpening of images and save them as common format files. No third-party dependencies are required, cross-platform and easy to integrate.
2. Detailed introduction to project requirements
2.1 Functional Requirements
1. Read the image
- Supports common formats such as JPEG, PNG, BMP, GIF, etc.;
- A clear prompt is given when the file does not exist or cannot be parsed.
2. Image Sharpening
- Use the classic Laplace operator, Unsharp Mask (anti-sharp mask) or high-pass filtering method;
- Parameterized control: sharpening intensity (convolution kernel weight or mask ratio).
3. Save the output
- Write the sharpened BufferedImage into the specified format (PNG/JPEG), supporting JPEG quality parameters;
- Automatically create output directories.
4. Batch processing
- Support batch sharpening of all images in the directory;
- Maintain relative directory structure output;
- Parallel execution improves efficiency.
5. User interaction (optional)
- Command line mode: simple parameter call;
- Swing interface: Preview the original image and processing results.
6. Log and error handling
- Record logs of the processing results of each image;
- Capture and prompt I/O, handle exceptions.
2.2 Non-functional requirements
Zero dependencies: Use only the Java standard library.
Ease of use: Encapsulated into a tool class, callable by the command line or GUI.
Performance: Use multi-threading or block processing for large images or batch scenarios.
Scalable: Easy to replace sharpening algorithms or add new filters.
3. Detailed introduction to related technologies
Used to represent readable and writeable images in memory, supporting multiple pixel formats.
& ConvolveOp
- Kernel represents a convolution kernel matrix;
- ConvolveOp implements convolution operations on BufferedImage for various filtering.
3. Laplacian
Common 3×3 cores:
0 -1 0
-1 5 -1
0 -1 0
Center weight > 1, surrounding negative values, enhance edges.
Mask (anti-sharpening mask)
First do Gaussian Blur on the original image to get a smooth picture.
Then use the difference between the original and smooth images to enhance the details:
sharpen = original + amount × (original - blurred)。
& ImageWriter
Read and write to multiple formats;
JPEG supports quality settings.
Parallel batch processing improves efficiency.
(Optional)
JFileChooser, JSlider, etc. are used for parameter adjustment and real-time preview.
4. Detailed introduction to the implementation ideas
Read the source map
BufferedImage src = (new File(srcPath));
Select the sharpening algorithm
- Laplace convolution: Use ConvolveOp directly;
- Unsharp Mask: Customize Gaussian Blur + difference operation.
Laplace convolution implementation
float[] lap = {0,-1,0, -1,5,-1, 0,-1,0}; Kernel kernel = new Kernel(3,3,lap); ConvolveOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null); BufferedImage sharp = (src, null);
Unsharp Mask implementation
// 1. Gaussian Blur float[] gauss = createGaussianKernel(radius); Kernel gk = new Kernel(k, k, gauss); BufferedImage blurred = new ConvolveOp(gk).filter(src, null); // 2. Difference and enhancementfor each pixel: int orig = (x,y); int b = (x,y); int diff = orig - b; int result = clamp(orig + amount * diff);
Save the output
- Automatically select PNG or JPEG according to the extension;
- JPEG can be set quality:
ImageWriter writer = ("jpg").next(); ImageWriteParam param = (); (MODE_EXPLICIT); (q); (null,new IIOImage(sharp,null,null),param);
Batch and concurrency
- Traverse the directory to collect all pictures;
- Use ExecutorService to call the above process in parallel;
- Keep relative path output.
GUI Preview
- Use JSlider to control intensity parameters;
- Real-time BufferedImage update to JLabel.
5. Complete implementation of the code
import .*; import .*; import .*; import .*; import .*; import .*; import ; /** * ImageSharpenUtil: Image Sharpening Tool */ public class ImageSharpenUtil { // Default parameters private static final double UNSHARP_AMOUNT = 1.0; // Anti-sharpening mask strength private static final int GAUSS_RADIUS = 3; // Gaussian fuzzy radius private static final float JPEG_QUALITY = 0.9f; // JPEG output quality private static final int THREADS = ().availableProcessors(); public static void main(String[] args) throws Exception { if ( < 2) { ("Usage: java ImageSharpenUtil <src> <dest> [laplacian|unsharp]"); return; } Path src = (args[0]), dest = (args[1]); String mode = >= 3 ? args[2] : "laplacian"; if ((src)) { batchProcess(src, dest, mode); } else { processSingle((), (), mode); } ("Finish."); } // Single image processing public static void processSingle(File in, File out, String mode) throws IOException { BufferedImage src = (in); if (src == null) throw new IOException("Unable to read: " + in); BufferedImage result = "unsharp".equals(mode) ? unsharpMask(src, GAUSS_RADIUS, UNSHARP_AMOUNT) : laplacianSharpen(src); writeImage(result, out); ("deal with: " + in); } // Batch processing public static void batchProcess(Path srcDir, Path destDir, String mode) throws IOException, InterruptedException { List<Path> list = new ArrayList<>(); try (Stream<Path> s = (srcDir)) { (Files::isRegularFile) .filter(p->().matches(".*\\.(?i)(png|jpe?g|bmp|gif)$")) .forEach(list::add); } ExecutorService exec = (THREADS); for (Path p : list) { (() -> { try { Path rel = (p); File out = (rel).toFile(); ().mkdirs(); processSingle((), out, mode); } catch (Exception e) { ("fail: " + p + " " + ()); } }); } (); (1, ); } // Laplace Sharpening public static BufferedImage laplacianSharpen(BufferedImage src) { float[] lap = {0,-1,0, -1,5,-1, 0,-1,0}; Kernel kernel = new Kernel(3,3,lap); return new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null).filter(src, null); } // Anti-sharpening mask public static BufferedImage unsharpMask(BufferedImage src, int radius, double amount) { int size = radius * 2 + 1; float[] matrix = createGaussianKernel(radius); Kernel gk = new Kernel(size, size, matrix); BufferedImage blurred = new ConvolveOp(gk, ConvolveOp.EDGE_NO_OP, null).filter(src, null); BufferedImage dest = new BufferedImage((), (), ()); for (int y=0; y<(); y++){ for (int x=0; x<(); x++){ int rgb1 = (x,y), rgb2 = (x,y); int a = (rgb1>>24)&0xFF; int r = clamp(((rgb1>>16&0xFF) - (rgb2>>16&0xFF)) * amount + (rgb1>>16&0xFF)); int g = clamp(((rgb1>>8&0xFF) - (rgb2>>8&0xFF)) * amount + (rgb1>>8&0xFF)); int b = clamp(((rgb1&0xFF) - (rgb2&0xFF)) * amount + (rgb1&0xFF)); (x,y, (a<<24)|(r<<16)|(g<<8)|b ); } } return dest; } // Generate Gaussian core private static float[] createGaussianKernel(int radius) { int size = radius*2+1; float[] data = new float[size*size]; double sigma = radius/3.0; double twoSigmaSq = 2*sigma*sigma; double piSigma = * twoSigmaSq; double sum = 0; for(int y=-radius; y<=radius; y++){ for(int x=-radius; x<=radius; x++){ double v = (-(x*x+y*y)/twoSigmaSq)/piSigma; data[(y+radius)*size + (x+radius)] = (float)v; sum += v; } } for(int i=0;i<;i++) data[i] /= sum; return data; } // Write out the picture public static void writeImage(BufferedImage img, File out) throws IOException { String ext = getExt(()); ().mkdirs(); if ("jpg".equalsIgnoreCase(ext)||"jpeg".equalsIgnoreCase(ext)) { Iterator<ImageWriter> it = ("jpg"); ImageWriter w = (); try (ImageOutputStream ios = (out)) { (ios); ImageWriteParam p = (); if (()) { (ImageWriteParam.MODE_EXPLICIT); (JPEG_QUALITY); } (null, new IIOImage(img,null,null),p); } finally { (); } } else { (img, ext, out); } } private static int clamp(double v) { return v<0?0:(v>255?255:(int)v); } private static String getExt(String name) { int i=('.'); return i<0?"png":(i+1); } }
6. Detailed interpretation of the code
: parse command line parameters, judge single graph or batch mode, and select algorithm mode (Laplace or anti-sharpening mask).
: Use Laplace 3×3 convolution kernel to achieve one-line code sharpening through ConvolveOp.
:
- Call createGaussianKernel to generate a Gaussian fuzzy kernel and blur the original image.
- Calculate the difference between the original image and the blurred image pixel by pixel. Press amount to enlarge it and overwrite it with the original image to enhance details.
: Calculate the Gaussian distribution kernel based on the given radius and σ value and normalize it.
: Automatically select PNG or JPEG according to the output file extension; the latter sets the compression quality.
: Use ExecutorService to traverse the directory in parallel and process it to maintain the relative path output.
7. Detailed project summary
This project implements two classic sharpening algorithms: Laplace operator and Unsharp Mask. Core features:
Pure Java SE: No additional libraries required, easy integration.
Multi-mode: Algorithm is optional, batch and single graph are flexible.
Parameterization: Can configure Gaussian radius, mask strength, and JPEG mass.
Efficient parallelism: multi-threaded batch processing.
It can be used as an example of image processing, or as an automated sharpening pipeline in production environments.
8. Project FAQs and answers
Q1: Will the Laplace nuclear cause noise or oversharpen?
A: When the center weight is too large or the image noise is obvious, it is recommended to do mild Gaussian blur first and then sharpen, or use Unsharp Mask to control it more delicately.
Q2: Is the anti-sharpening mask processing slow?
A: You can reduce the fuzzy radius or use chunking parallelism; you can also use a smaller kernel.
Q3: Is the output JPEG quality different?
A: JPEG is for lossy compression, it is recommended to set JPEG_QUALITY between 0.8–0.95, or use PNG.
Q4: Memory growth during batch processing?
A: Ensure that the BufferedImage reference is released in time and the number of threads is set reasonably to avoid loading too many large images at the same time.
9. Expansion direction and performance optimization
GPU acceleration: Use OpenCL (JOCL) or CUDA version filter library to greatly improve the processing speed of large-pictures.
Block rendering: Cut the super-large image to reduce memory peaks.
More advanced operators: Integrate Canny edge detection + guided median filtering for more precise sharpening.
Real-time GUI: Add slider, preview, batch task management based on JavaFX or Swing.
Pipeline processing: Combining other filters (noise denoising, color correction) to build a complete image pipeline.
The above is the detailed content of Java implementing sharpening images and saving functions (with source code). For more information about Java sharpening images, please pay attention to my other related articles!