java image processing - grayscale, transparency (alpha channel) processing
Recently, as an intern in a small company, my boss asked me to write a graphic editor that involves working with images in java.Usually python is used for image processing, so I don't feel that there is much information about java image processing on the Internet (maybe because I didn't flip it carefully...)So I want to record some ideas I've handled.
Grayscale
I will not go into details about the image's rgb channel alpha channel for the moment, there are a lot of information on the Internet.First tell me how to read a picture.
private BufferedImage initBufferedImage(String imagePath) {
File file = new File(imagePath);
BufferedImage image = null;
try {
image = ImageIO.read(file);
} catch (IOException e) {
e.printStackTrace();
}
return image;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Graying pictures is really easy
private BufferedImage grayProcess(BufferedImage sourceImage){
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
BufferedImage grayImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);// BufferedImage.TYPE_BYTE_GRAY specifies that this is a grayscale picture
for(int i= 0 ; i < width ; i++){
for(int j = 0 ; j < height; j++){
int rgb = image.getRGB(i, j);
grayImage.setRGB(i, j, rgb);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
Next, of course, I want to write the picture as a file
private void writeBufferedImage(BufferedImage img,String filePath){
String format = filePath.substring(filePath.indexOf('.')+1);
//Get Picture Format
System.out.println(format);
try {
ImageIO.write(img,format,new File(filePath));
} catch (IOException e) {
e.printStackTrace();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Set Picture Transparency
The code below makes the background color of the picture transparent. Of course, the picture can't be too complex and the background color is lighter than the outline color.For example, the original image on the left and the processed image on the right.(
/**
Briefly introduce the idea, first traverse all the pixels, calculate the grayMean of the whole picture, the outline color is deep, the grayscale value is small, the background color is light, the grayscale value is large, after weighted average the total average value will be slightly lower than the background grayscale value, then traverse all the pixels again, and calculate the grayscale of each pixel point, if its grayscale valueLarger than grayMean, set its alpha value to 0, which is fully transparent, otherwise it will not be processed.
*/
package imageprocess;
import java.awt.image.BufferedImage;
/**
* Created by alex on 7/24/16.
*/
public class AlphaProcessor {
/**
* Processing transparency
*/
public BufferedImage alphaProcess(BufferedImage bufferedImage) {
//Get the width and height of the source image
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
System.out.println(width+" "+height);
//Instantiate a picture of the same size and set the type to BufferedImage.TYPE_4BYTE_ABGR, which supports rgb images for alpha channels
BufferedImage resImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
double grayMean = 0;
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int rgb = bufferedImage.getRGB(i,j);
int r = (0xff&rgb);
int g = (0xff&(rgb>>8));
int b = (0xff&(rgb>>16));
//This is the formula for calculating the gray value
grayMean += (r*0.299+g*0.587+b*0.114);
}
}
//Calculate average gray level
grayMean = grayMean/(width*height);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int rgb = bufferedImage.getRGB(i,j);
//An int is 32 bits, which is stored in java in the order of abgr, i.e., alpha is the first 8 bits, and r is the last 8 bits, so you can get the rgb value as follows
int r = (0xff&rgb);
int g = (0xff&(rgb>>8));
int b = (0xff&(rgb>>16));
double gray = (r*0.299+g*0.587+b*0.114);
//If the gray value is greater than the average gray value previously requested, set its alpha to 0, and the following should be r g b = R + (g << 8) + (b << 16) + (0 << 24);
if (gray>grayMean){
rgb = r + (g << 8) + (b << 16);
}
resImage.setRGB(i,j,rgb);
}
}
//ok, the result is a transparent BufferedImage with a light background, which can be written as a file in the way mentioned in Grayscale
return resImage;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
Processing within a specified area
Imagine people who have seen this blog have touched photoshop. Photoshop can first select an area with a checkbox tool and then do a series of actions within that area, such as setting transparency and grayscale as mentioned earlier.(
Let's start by putting the picture on a JLabel, listening for the mouse click event, getting the coordinates of the mouse click for this JLabel, linking the points together to form a checkbox, then setting a mask to determine which points are inside the checkbox, then you can just target the pixel points inside the checkbox or outside the checkboxPixel point operation of.Talk is cheap, show me the code.
Let's start with this demo after running.
I clicked three points, then clicked ok, and then the program would set the transparency of the image to 100 in the area surrounded by the three points. Of course, you can also do other things with this pixel point in this area.(
An important piece is the getMask() method
package view;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
/**
* Created by alex on 7/25/16.
*/
public class FrameForBlog extends JFrame {
JPanel contentPanel;
LabelForBlog labelForBlog;//This is my newly written class, which follows
Button okButton;
FrameForBlog() {
contentPanel = new JPanel();
contentPanel.setLayout(new FlowLayout());
//I put the picture in this relative path, please change it before using it
ImageIcon icon = new ImageIcon("src/data/cartoon.jpg");
icon.setImage(icon.getImage().getScaledInstance(1000, icon.getIconHeight() * 1000 / icon.getIconWidth(), Image.SCALE_AREA_AVERAGING));//Scale pictures equally or the interface will not display completely
labelForBlog = new LabelForBlog(icon);
labelForBlog.setBounds(0, 0, icon.getIconWidth(), icon.getIconHeight());
contentPanel.add(labelForBlog);
okButton = new Button("OK");
contentPanel.add(okButton);
okButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
labelForBlog.process();
}
});
add(contentPanel);
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
this.setVisible(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new FrameForBlog();
}
}
class LabelForBlog extends JLabel {
//to record the coordinates
List<int[]> coordinates;
LabelForBlog() {
super();
coordinates = new ArrayList<>();
}
LabelForBlog(ImageIcon imageIcon) {
super(imageIcon);
coordinates = new ArrayList<>();
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
System.out.println(e.getX() + " " + e.getY());
int[] coor = new int[]{e.getX(), e.getY()};
boolean contain = false;
//If the clicked point repeats, it will not be added
for (int[] c : coordinates) {
if (c[0] == coor[0] && c[1] == coor[1]) {
contain = true;
break;
}
}
if (!contain) {
coordinates.add(coor);
System.out.println("not contain");
repaint();
}
}
});
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("paint comComponent");
if (coordinates.size() > 0) {
int x0 = coordinates.get(0)[0];
int y0 = coordinates.get(0)[1];
int x1 = 0;
int y1 = 0;
//If you don't add this -3 and + 5* line, it doesn't exactly coincide. That's why drawString works
g.drawString("*", x0 - 3, y0 + 5);
for (int i = 1; i < coordinates.size(); i++) {
x1 = coordinates.get(i)[0];
y1 = coordinates.get(i)[1];
g.drawString("*", x1 - 3, y1 + 5);
g.drawLine(x0, y0, x1, y1);
x0 = x1;
y0 = y1;
}
}
}
//Get the mask, this is more important
private int[][] getMask() {
int x = this.getX();
int y = this.getY();
int[][] points = new int[coordinates.size()][2];
for (int i = 0; i < coordinates.size(); i++) {
points[i][0] = coordinates.get(i)[0];
points[i][1] = coordinates.get(i)[1];
}
//GeneralPath is used to determine if a pixel point is in a checkbox
GeneralPath path = new GeneralPath();
path.moveTo(points[0][0], points[0][1]);
for (int i = 1; i < points.length; i++) {
path.lineTo(points[i][0], points[i][1]);
}
int[][] mask = new int[this.getIcon().getIconHeight()][this.getIcon().getIconWidth()];
for (int i = 0; i < this.getIcon().getIconHeight(); i++) {
for (int j = 0; j < this.getIcon().getIconWidth(); j++) {
//It is worth noting that contains(j,i)
mask[i][j] = path.contains(j, i) ? 1 : 0;
}
}
return mask;
}
public void process(){
int[][] mask = getMask();
//Here's how to turn Bufferedimage into Image
BufferedImage img = new BufferedImage(this.getIcon().getIconWidth(), this.getIcon().getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g = img.createGraphics();
g.drawImage(((ImageIcon) this.getIcon()).getImage(),0,0,null);
g.dispose();
//Transparency processing based on mask s
BufferedImage resImage = alphaProcess(mask,img);
this.setIcon(new ImageIcon(resImage));
}
//Slightly changed on the previous alphaProcess, deleting the step of judging from the average gray value, adding a sentence to the judgment of the mask, if the mask is 1 then changing the transparency, otherwise not changing
private BufferedImage alphaProcess(int[][] mask, BufferedImage bufferedImage) {
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
System.out.println(width + " " + height);
BufferedImage resImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int rgb = bufferedImage.getRGB(i, j);
int r = (0xff & rgb);
int g = (0xff & (rgb >> 8));
int b = (0xff & (rgb >> 16));
//Set Transparency Based on mask
if (mask[j][i] == 1)
rgb = r + (g << 8) + (b << 16) + (100 << 24);
else{
rgb = r + (g<<8) + (b<<16)+(255<<24);
}
resImage.setRGB(i, j, rgb);
}
}
return resImage;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183