图像打码其实也是图像卷积操作中,空间域滤波的一种方式,用一定大小的滤波器对马赛克范围内像素进行操作。实现过程:将需要打马范围按照滤波器大小划分为多个区块,取滤波器范围内像素,求取均值,再将均值赋值给范围内每一个像素,滤波器再滑到下一个区块。从原理上看,图像马赛克特效非常简单,下面就来看一下具体实现过程。
对整张图像打码。对整张图片打码也叫做像素格特效,我们只需要考虑滤波器大小即可。
代码:
/**
* 对整个图片打码
* @param image
* @param length 马赛克大小
*/
public void imageMosaic(BufferedImage image,int length) {
int width = image.getWidth();
int height = image.getHeight();
int size = length * length;
int x = width / length;
int y = height / length;
for(int i = 0; i < x; i++) {
for(int j = 0; j < y; j++) {
int R=0,G=0,B=0;
for(int m = 0; m < length; m++) {
for(int n = 0; n < length; n++) {
int xCoordinate = i * length + m;
int yCoordinate = j * length + n;
int rgb = image.getRGB(xCoordinate, yCoordinate);
R += (rgb >> 16) & 0xff;
G += (rgb >> 8) & 0xff;
B += rgb & 0xff;
}
}
R = R / size;
G = G / size;
B = B / size;
int RGB = (255 & 0xff) << 24 | (clamp(R) & 0xff) << 16 | (clamp(G) & 0xff) << 8 | (clamp(B) & 0xff);
for(int m = 0; m < length; m++) {
for(int n = 0; n < length; n++) {
int xCoordinate = i * length + m;
int yCoordinate = j * length + n;
image.setRGB(xCoordinate, yCoordinate, RGB);
}
}
}
}
}
局部打码。局部打码需要先定义好打码起始位置,打码范围,马赛克大小。
代码:
/**
* 局部打码
* @param image
* @param xCoordinate 横坐标起始位置
* @param yCoordinate 纵坐标起始位置
* @param xLength x方向长度
* @param yLength y方向长度
* @param length 马赛克大小
*/
public void mosaic(BufferedImage image,int xCoordinate,int yCoordinate,int xLength,int yLength,int length) {
if ((xCoordinate + xLength) > image.getWidth() || (yCoordinate + yLength) > image.getHeight()) {
System.out.println("马赛克范围大于图像范围!");
return;
}
int size = length * length;
int x = xLength / length;
int y = yLength / length;
for(int m = 0; m < x; m++) {
for(int n = 0; n < y; n++) {
int R=0,G=0,B=0;
for(int i = 0; i < length; i++) {
for(int j = 0; j < length; j++) {
int x1 = xCoordinate + m * length + i;
int y1 = yCoordinate + n * length + j;
int rgb = image.getRGB(x1, y1);
R += (rgb >> 16) & 0xff;
G += (rgb >> 8) & 0xff;
B += rgb & 0xff;
}
}
R = R / size;
G = G / size;
B = B / size;
int RGB = (255 & 0xff) << 24 | (clamp(R) & 0xff) << 16 | (clamp(G) & 0xff) << 8 | (clamp(B) & 0xff);
for(int i = 0; i < length; i++) {
for(int j = 0; j < length; j++) {
int x1 = xCoordinate + m * length + i;
int y1 = yCoordinate + n * length + j;
image.setRGB(x1, y1, RGB);
}
}
}
}
}
完整的马赛克实现代码:
public class MosaicFilter {
/**
* 对整个图片打码
* @param image
* @param length 马赛克大小
*/
public void imageMosaic(BufferedImage image,int length) {
int width = image.getWidth();
int height = image.getHeight();
int size = length * length;
int x = width / length;
int y = height / length;
for(int i = 0; i < x; i++) {
for(int j = 0; j < y; j++) {
int R=0,G=0,B=0;
for(int m = 0; m < length; m++) {
for(int n = 0; n < length; n++) {
int xCoordinate = i * length + m;
int yCoordinate = j * length + n;
int rgb = image.getRGB(xCoordinate, yCoordinate);
R += (rgb >> 16) & 0xff;
G += (rgb >> 8) & 0xff;
B += rgb & 0xff;
}
}
R = R / size;
G = G / size;
B = B / size;
int RGB = (255 & 0xff) << 24 | (clamp(R) & 0xff) << 16 | (clamp(G) & 0xff) << 8 | (clamp(B) & 0xff);
for(int m = 0; m < length; m++) {
for(int n = 0; n < length; n++) {
int xCoordinate = i * length + m;
int yCoordinate = j * length + n;
image.setRGB(xCoordinate, yCoordinate, RGB);
}
}
}
}
}
/**
* 局部打码
* @param image
* @param xCoordinate 横坐标起始位置
* @param yCoordinate 纵坐标起始位置
* @param xLength x方向长度
* @param yLength y方向长度
* @param length 马赛克大小
*/
public void mosaic(BufferedImage image,int xCoordinate,int yCoordinate,int xLength,int yLength,int length) {
if ((xCoordinate + xLength) > image.getWidth() || (yCoordinate + yLength) > image.getHeight()) {
System.out.println("马赛克范围大于图像范围!");
return;
}
int size = length * length;
int x = xLength / length;
int y = yLength / length;
for(int m = 0; m < x; m++) {
for(int n = 0; n < y; n++) {
int R=0,G=0,B=0;
for(int i = 0; i < length; i++) {
for(int j = 0; j < length; j++) {
int x1 = xCoordinate + m * length + i;
int y1 = yCoordinate + n * length + j;
int rgb = image.getRGB(x1, y1);
R += (rgb >> 16) & 0xff;
G += (rgb >> 8) & 0xff;
B += rgb & 0xff;
}
}
R = R / size;
G = G / size;
B = B / size;
int RGB = (255 & 0xff) << 24 | (clamp(R) & 0xff) << 16 | (clamp(G) & 0xff) << 8 | (clamp(B) & 0xff);
for(int i = 0; i < length; i++) {
for(int j = 0; j < length; j++) {
int x1 = xCoordinate + m * length + i;
int y1 = yCoordinate + n * length + j;
image.setRGB(x1, y1, RGB);
}
}
}
}
}
// 判断r,g,b值,大于256返回256,小于0则返回0,0到256之间则直接返回原始值
private int clamp(int rgb) {
if (rgb > 255)
return 255;
if (rgb < 0)
return 0;
return rgb;
}
public static void main(String[] args) throws Exception{
File in = new File("C:/Users/admin/Desktop/1.jpg");
File out = new File("C:/Users/admin/Desktop/3.jpg");
BufferedImage image = ImageIO.read(in);
new MosaicFilter().imageMosaic(image, 5);
//new MosaicFilter().mosaic(image, 100, 70, 50, 50,10);
ImageIO.write(image, "jpg", out);
}
}
原图:
全局打码:
局部打码: