From Pixels to Pictures: A Guide to Image Manipulation in Java

Shubham Singh
19 min readFeb 8, 2023

--

Think about your last scroll through your social media feed. What did you see? Chances are, you were inundated with pictures of your friends, family, and pets. From filtered selfies to perfectly curated landscapes, we’re surrounded by images every day. But have you ever wondered how these images are created and transformed on a computer? How does a picture go from an ordinary snap to a work of art? Well, the secret behind all the magic lies in the pixels. That’s right! Every image is just a collection of tiny dots, called pixels, and by manipulating these pixels, we can create stunning transformations.

And, guess what? With just a few lines of code, you too can harness this power and unleash your inner artist. So, buckle up and get ready to embark on a journey to discover the wonders of pixel manipulation. Whether you’re a seasoned programmer or just starting out, this guide will take you step-by-step through the process of transforming images in Java.

What You Will Learn:

  • Understanding image processing and manipulation techniques
  • The basics of pixels and how they make up an image
  • Overview of pixel-based image manipulation techniques
  • How to use Java code to apply filters and effects to an image
  • And more!

Understanding Pixels and Their Role in Image Processing

We live in a world where images are everywhere, from social media to advertisements, from online articles to digital art. And what lies at the heart of every single one of these images? Pixels!

The transformation of an image from a clear picture to a pixelated version.

A pixel is a tiny dot of color that, when combined with millions of others, forms a complete image. Just like how individual bricks come together to make a magnificent structure, individual pixels come together to form a beautiful image.

Have you ever wondered how social media filters work their magic? How they make your eyes sparkle, or your skin look flawless? Well, the answer is pixel manipulation! By changing just a few pixels here and there, you can transform a photo into a work of art.

The Power of Pixels — A Look at the Fine Details

And, this is where image processing comes into play. It’s a field that deals with the creation, manipulation, and analysis of digital images.This could include adjusting the brightness and contrast, resizing the image, and even changing the color scheme. Pixel manipulation plays a significant role in image processing, as it allows us to control the individual pixels in an image to achieve our desired outcome.

In short, pixels are the building blocks of images, and by manipulating them, we have the power to transform ordinary images into truly stunning masterpieces.

Setting Up the Development Environment

To get started with pixel manipulation in Java, you will need the following tools:

  • Java Development Kit (JDK)
  • Integrated Development Environment (IDE) like Eclipse or IntelliJ IDEA
  • Java AWT (Abstract Window Toolkit) and Java Spring library for image processing
  • Any other libraries or tools you prefer to use for image manipulation (optional)

Here are the steps to set up your development environment:

  1. Install the latest JDK on your computer. You can download it from the official Java website.
  2. Download and install an IDE of your choice.
  3. Import the required libraries for image processing: Java AWT and Spring libraries.

Note: You can use any language and library for image processing, but for the purpose of this article, we’ll be using Java AWT and Spring libraries. If you are not familiar with these libraries, take a quick reference before proceeding further. The main goal of this article is to teach the concept of image processing and pixel manipulation, not a specific language or library.

Image Processing Techniques

There are many techniques available to transform images , but in this guide, we’ll be focusing on some of the most impactful and accessible methods.We’ll discuss each technique in detail, breaking down the code and explaining the concepts behind each step.We encourage you to follow along and try out each of the techniques we’ll be discussing. The hands-on experience is key to truly understanding the power of image processing.So, grab your toolkit and let’s get started!

Activity 1 : Viewing the pixel values of an image

The Beauty in Simplicity: A pixelated Lotus

Understanding the underlying structure of an image is crucial to making meaningful transformations. In this activity, we’ll learn how to view the RGB values of each pixel in an image, and use that information to make simple modifications to the image.

The first step in viewing the pixel values of an image is to load the image from a given URL. Then, using a loop, we traverse through all the pixels in the image and extract the red, green, and blue values using bit masking. Finally, we print out the extracted values for each pixel, giving us a complete representation of the image in terms of its RGB values.Here’s an example of how to do it:

// Java code to read an image and display its pixels and RGB values
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class PixelValues {

public static void main(String[] args) {

try {
// Read the image file
BufferedImage image = ImageIO.read(new File("image.jpg"));

// Get the image width and height
int width = image.getWidth();
int height = image.getHeight();

// Loop through all the pixels in the image
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = image.getRGB(x, y);
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = pixel & 0xff;
System.out.println("Pixel values at (" + x + "," + y + "): Red = " + red + ", Green = " + green + ", Blue = " + blue);
}
}

} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}

Extracting the red, green, and blue values from a pixel can be accomplished using a process called bit masking. Essentially, a pixel is stored as a number, usually represented as 32 bits in our case. These bits are divided into sections, with each section representing a different color component. By applying a “mask” that only selects a specific section of the bits, we can extract the value for that color component.

In the code snippet above, we first extract the value of the pixel by calling the getRGB() method. Then, we use the bit shifting operator >> to shift the bits 16 places to the right for red, 8 places to the right for green, and do not shift the bits for blue. The bit masking operator & 0xff is used to keep only the last 8 bits of the number, which represents the value of the color channel. Finally, the values of red, green, and blue are extracted and printed out.

Note : Exceptions are errors that occur during the execution of a program. They can be due to a variety of reasons, such as incorrect file paths or invalid image data. By using try-catch blocks, we can handle these exceptions and prevent the program from crashing. In this case, if something goes wrong while reading the image or manipulating its pixels, the exception will be caught and a friendly error message will be displayed, instead of crashing the program.

Activity 2 : Experimenting with pixel values of the image

Now that you have viewed the pixel values of your image, it’s time to have some fun with them! In this activity, you’ll experiment with the pixel values of your image and see how it affects the overall appearance of the image.

Here’s what you need to do:

  1. Choose an image of your choice.
Original image

2. Write a code that manipulates the color values of individual pixels in the image.

3. Observe how the change in color values of the pixels affects the overall appearance of the image.

4. Repeat the above steps and experiment with different color values to see the different effects it has on the image.

Here’s an example for you:

try {
BufferedImage img = ImageIO.read(new File("path/to/your/image"));
int width = img.getWidth();
int height = img.getHeight();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int p = img.getRGB(x, y);

int a = (p>>24) & 0xff;
int r = (p>>16) & 0xff;
int g = (p>>8) & 0xff;
int b = p & 0xff;

// manipulate the color values of the pixels here
// in this case we are inverting the color values
r = 255 - r;
g = 255 - g;
b = 255 - b;

p = (a<<24) | (r<<16) | (g<<8) | b;
img.setRGB(x, y, p);
}
}
} catch (Exception e) {
System.out.println("Oops! Something went wrong: " + e.getMessage());
}

Note: The code snippet above inverts the color values of the pixels in the image. You can experiment with different color values to see the different effects it has on the image.

Congratulations! You have now successfully manipulated the pixels of your image. It’s time to witness the transformation. Here is a code snippet to help you out.

  1. Create a JFrame object to display the image.
JFrame frame = new JFrame();

2. Set the properties of the frame such as size, location, and close operation.

frame.setSize(width, height);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

3. Create a JLabel object and set the image as its icon.

JLabel label = new JLabel();
label.setIcon(new ImageIcon(img));

4. Add the label to the frame.

frame.add(label);

5. Make the frame visible.

frame.setVisible(true);

Let’s take a look at the new version of your picture.

Image generated by manipulating pixel values of original image.

Activity 3 : Brightness and Contrast Adjustment

In this activity, we’ll be adjusting the brightness and contrast of an image. This can be useful for improving the visual quality of an image, especially in cases where the original image is too dark or too bright.

The code to adjust the brightness of an image involves looping through all the pixels and adding a constant value to the red, green, and blue values of each pixel. Similarly, to adjust the contrast, we can multiply the red, green, and blue values by a constant value.

A beach on a sunny day

Here is a code snippet to adjust the brightness of an image:

for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = image.getRGB(x, y);
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = pixel & 0xff;

// adjust brightness by adding a constant value
red += brightnessValue;
green += brightnessValue;
blue += brightnessValue;

// ensure that the values do not exceed the maximum value of 255
red = Math.min(255, red);
green = Math.min(255, green);
blue = Math.min(255, blue);

// set the pixel value with the adjusted values
int newPixel = (red << 16) | (green << 8) | blue;
image.setRGB(x, y, newPixel);
}
}

Brightness refers to the overall lightness or darkness of an image. Imagine a photo of a beach on a sunny day. If the brightness is increased, the photo becomes lighter and the details in the bright areas may be washed out. On the other hand, if the brightness is decreased, the photo becomes darker and the details in the darker areas may be lost.

Brightness adjustment using pixel manipulation

And here is a code snippet to adjust the contrast of an image:

for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = image.getRGB(x, y);
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = pixel & 0xff;

// adjust contrast by multiplying with a constant value
red *= contrastValue;
green *= contrastValue;
blue *= contrastValue;

// ensure that the values do not exceed the maximum value of 255
red = Math.min(255, red);
green = Math.min(255, green);
blue = Math.min(255, blue);

// set the pixel value with the adjusted values
int newPixel = (red << 16) | (green << 8) | blue;
image.setRGB(x, y, newPixel);
}
}

Contrast refers to the difference in brightness between the lightest and darkest areas of an image. In the beach photo example, if the contrast is increased, the difference between the bright areas (e.g. the sky) and the darker areas (e.g. the shadows) becomes more pronounced. If the contrast is decreased, the difference becomes less pronounced and the photo appears flat and dull.

Contrast adjustment of the image

Activity 4: Converting an image to grayscale

In this activity, we will explore how to convert an image from its original color to grayscale. Grayscale images are the images that consist of shades of gray, and they are often used in various applications such as text recognition, facial detection, and more. Converting an image to grayscale helps simplify the image processing process and makes it easier to extract features and perform image analysis.

A comparison of the original image and its greyscale version, showcasing the transformation from full-color to shades of grey.

Here is a code snippet for converting an image to grayscale using pixel manipulation:

// Loop through all the pixels in the image
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = img.getRGB(x, y);
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = pixel & 0xff;
// Calculate the gray value based on weighted averaging technique
// Using the formula 0.3 * red + 0.59 * green + 0.11 * blue
// int gray = (int)(0.3 * red + 0.59 * green + 0.11 * blue);
// Calculate the gray value by simple averaging the red, green, and blue values
int gray = (red + green + blue) / 3;
// Combine the gray value into a single int representing the gray pixel
int newPixel = (gray << 16) | (gray << 8) | gray;
// Set the new pixel value at (x, y)
img.setRGB(x, y, newPixel);
}
}

In this code, we first get the RGB values of each pixel and then convert it to grayscale using a simple formula. The formula takes into account the human eye’s sensitivity to different colors and calculates a weighted average of the RGB values. After converting the pixel to grayscale, we set the new grayscale value to the corresponding pixel in the image.

We can use the spring framework to display the original and the modified image side by side for comparison.

JFrame frame = new JFrame();
frame.setSize(width, height);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JLabel label = new JLabel(new ImageIcon(img));
frame.add(label);
frame.setVisible(true);

Also, we can save the modified image as shown

ImageIO.write(img, "png", new File("Grayscale.png"));

Activity 5 : Rotating and flipping image

In this activity, we will learn how to rotate and flip an image using pixel manipulation techniques. The ability to rotate and flip images is crucial in many image processing applications. From creating mirror images to correcting image orientation, rotation and flipping play an important role in image manipulation.

To rotate an image, we need to determine the new coordinates of each pixel after the rotation.For instance, in a 90 degree clockwise rotation, the pixel located at (x, y) will be positioned at (y, image_height-x).

BufferedImage img = ImageIO.read(new File("image_path"));

// get the width and height of the image
int width = img.getWidth();
int height = img.getHeight();

// create a new BufferedImage object with the same height and width as the original image
BufferedImage rotatedImage = new BufferedImage(height, width, img.getType());

// loop through all the pixels of the original image
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// get the RGB value of the current pixel
int p = img.getRGB(x, y);
// set the RGB value of the corresponding pixel in the rotated image
// the new x-coordinate is equal to the height minus 1 minus the y-coordinate of the original pixel
// the new y-coordinate is equal to the x-coordinate of the original pixel
rotatedImage.setRGB(height-1-y, x, p);
}
}

// save the rotated image to a file
ImageIO.write(rotatedImage, "png", new File("rotated_image.png"));

Similarly, flipping an image is also straightforward. To flip an image vertically, the new x value of a pixel will be equal to the width of the image minus the old x value, and the new y value of the pixel will be equal to the old y value.

BufferedImage img = ImageIO.read(new File("image_path"));

// get the width and height of the image
int width = img.getWidth();
int height = img.getHeight();

// create a new BufferedImage object with the same height and width as the original image
BufferedImage flippedImage = new BufferedImage(height, width, img.getType());

// loop through all the pixels of the original image
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// get the RGB value of the current pixel
int p = img.getRGB(x, y);
// set the RGB value of the corresponding pixel in the flipped image
int newX = width - x - 1;
int newY = y;
flippedImage.setRGB(newX, newY, p);
}
}

// save the rotated image to a file
ImageIO.write(flippedImage, "png", new File("flipped_image.png"));

By rotating and flipping an image, we can achieve a wide range of new perspectives and views of the original image, making it a valuable tool for image processing applications.

Now, let’s give your image a spin and see what it looks like!

Original image
Transforming the original image by manipulating its pixel values results in a 90-degree rotation
Flipping the original image vertically

Activity 6: Enhancing the Image with Filters

Have you ever wondered how a photo can be transformed to look like an oil painting or a sketch? This is where filters come into play! Filters are a set of instructions applied to an image to achieve a desired effect. They can change the look, feel and mood of an image in an instant.

Sepia filter is a popular filter that gives the image a vintage look. The filter works by darkening the red, green and blue values of the pixels and adding a little bit of brown.Try this code and see the difference in your image after applying the Sepia filter.

Original image
BufferedImage img = ImageIO.read(new File("path/to/your/image"));
int width = img.getWidth();
int height = img.getHeight();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int p = img.getRGB(x, y);

int a = (p>>24) & 0xff;
int r = (p>>16) & 0xff;
int g = (p>>8) & 0xff;
int b = p & 0xff;

// Sepia filter calculation
int tr = (int)(0.393 * r + 0.769 * g + 0.189 * b);
int tg = (int)(0.349 * r + 0.686 * g + 0.168 * b);
int tb = (int)(0.272 * r + 0.534 * g + 0.131 * b);

// ensuring the calculated values are within range
r = tr > 255 ? 255 : tr;
g = tg > 255 ? 255 : tg;
b = tb > 255 ? 255 : tb;

p = (a<<24) | (r<<16) | (g<<8) | b;
img.setRGB(x, y, p);
}
}
The transformation of a vibrant image into a nostalgic sepia-toned memory, achieved by manipulating the individual pixel values

Activity 7: Thresholding an Image — Binarizing the Image

Have you ever noticed the black and white photographs from the old days? They have a certain charm and timelessness to them, don’t they? That’s because the simplicity of a black and white image can bring out the true essence of a picture. In this activity, we will explore the world of image binarization, where we convert a grayscale or a colored image into a black and white one.

Thresholding is one of the most simple and effective ways to perform image binarization. The idea behind thresholding is simple. We set a threshold value, and any pixel with a value greater than this threshold is set to white and any pixel with a value less than the threshold is set to black. In other words, we separate the image into two parts — the parts that are important (usually the object of interest) and the parts that are not important (usually the background).

Original image
public static BufferedImage thresholdImage(BufferedImage img, int threshold) {
int width = img.getWidth();
int height = img.getHeight();
BufferedImage thresholdedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int p = img.getRGB(x, y);
int r = (p >> 16) & 0xff;
int g = (p >> 8) & 0xff;
int b = p & 0xff;
int avg = (r + g + b) / 3;
if (avg > threshold) {
// Set pixel to white
thresholdedImage.setRGB(x, y, 0xffffff);
} else {
// Set pixel to black
thresholdedImage.setRGB(x, y, 0x000000);
}
}
}
return thresholdedImage;
}
Bringing clarity to the image with Thresholding: A Black and White transformation

In the above code, we iterate over all the pixels in the image and calculate the average of the red, green, and blue values. If the average is greater than the threshold, we set the pixel to white (255, 255, 255), and if the average is less than the threshold, we set the pixel to black (0, 0, 0).

Thresholding has several real-life applications, such as document scanning, where the document is thresholded to separate the text from the background, and medical imaging, where images are thresholded to separate tumors from normal tissue.

Activity 7: Adjusting the Colors of an Image

Have you ever wanted to make a picture pop with more vivid colors or tone it down with a more muted palette? Color adjustment is a powerful tool in image processing that allows you to do just that! Whether you want to enhance the overall color balance, increase or decrease the saturation, or change the hue of your image, color adjustment is the way to go.

Let’s look at an example of how to adjust the saturation of an image. To do this, we’ll first convert the image from the RGB color space to the HSL color space. This will give us access to the hue, saturation, and lightness channels of the image, which we can then manipulate individually.

Original image
BufferedImage img = ImageIO.read(new File("image_path"));
int width = img.getWidth();
int height = img.getHeight();

// Adjust the saturation of the image
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = img.getRGB(x, y);

// Convert the pixel from RGB to HSL
int r = (pixel >> 16) & 0xff;
int g = (pixel >> 8) & 0xff;
int b = pixel & 0xff;
float[] hsl = fromRGB(r, g, b);

// Increase the saturation
hsl[1] = Math.min(1.0f, hsl[1] * 1.5f);
// Similarly you can manipulate hsl[0] or hsl[2] to witness the changes
// Convert the pixel back to RGB
int[] rgb = toRGB(hsl);
int newPixel = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
img.setRGB(x, y, newPixel);
}
}

ImageIO.write(img, "jpg", new File("output.jpg"));
private static float[] fromRGB(int r, int g, int b) {
float h, s, l;
float[] hsl = new float[3];
float cMax = (float) Math.max(r, Math.max(g, b));
float cMin = (float) Math.min(r, Math.min(g, b));
float delta = cMax - cMin;

// calculate hue
if (delta == 0) {
h = 0;
} else if (cMax == r) {
h = (float) (((g - b) / delta) % 6);
} else if (cMax == g) {
h = (float) (((b - r) / delta) + 2);
} else {
h = (float) (((r - g) / delta) + 4);
}

// convert hue to degrees
h = (float) (h * 60);
if (h < 0) {
h = h + 360;
}

// calculate lightness
l = (cMax + cMin) / 2;

// calculate saturation
if (delta == 0) {
s = 0;
} else {
s = (delta / (1 - Math.abs(2 * l - 1)));
}

hsl[0] = h;
hsl[1] = s;
hsl[2] = l;
return hsl;
}
private static int[] toRGB(float[] hsl) {
int[] rgb = new int[3];
float h = hsl[0];
float s = hsl[1];
float l = hsl[2];
float c = (1 - Math.abs(2 * l - 1)) * s;
float x = c * (1 - Math.abs((h / 60) % 2 - 1));
float m = l - c / 2;
float r1, g1, b1;

if (h >= 0 && h < 60) {
r1 = c;
g1 = x;
b1 = 0;
} else if (h >= 60 && h < 120) {
r1 = x;
g1 = c;
b1 = 0;
} else if (h >= 120 && h < 180) {
r1 = 0;
g1 = c;
b1 = x;
} else if (h >= 180 && h < 240) {
r1 = 0;
g1 = x;
b1 = c;
} else if (h >= 240 && h < 300) {
r1 = x;
g1 = 0;
b1 = c;
} else {
r1 = c;
g1 = 0;
b1 = x;
}

int r = (int) ((r1 + m) * 255);
int g = (int) ((g1 + m) * 255);
int b = (int) ((b1 + m) * 255);
rgb[0] = r;
rgb[1] = g;
rgb[2] = b;
return rgb;
}

In this code, we’re first reading in the image and storing its width and height. Then, for each pixel in the image, we convert it from the RGB color space to the HSL color space using the fromRGB function. Next, we increase the saturation of the pixel by multiplying it by 1.5. Finally, we convert the pixel back to RGB and set it in the output image.

The Result of Saturation Boost

With color adjustment, you have the power to make your images truly stand out. So go ahead and experiment with the different color channels and see what kind of results you can achieve!

We have explored various image processing techniques that can be achieved through the manipulation of pixels using code. While it is not the most convenient method to bring out the desired effects in an image, it is a great way to familiarize ourselves with how things work internally. Through this journey, we have learned how filters can be applied, how to binarize the image, adjust the color and saturation of an image and much more. While there are numerous libraries and software available that make the task easier, it is always good to understand the fundamentals. This understanding can help us make informed decisions and appreciate the power of these tools even more. Thank you for joining us on this exciting journey.

--

--

Shubham Singh

Dedicated to sharing my insights and experiences through writing, with a passion for creating informative and engaging articles and tutorials.