大题思路我在知乎有回答
在这里大概讲下代码。我实现的比较粗糙,只能使用正方形的图片,如有其他需要可以自行改动。
下面是主要代码。
这里面有俩自定义的类,VectorParser(实现AimParser接口,用于像素替代算法的实现,其中parse()函数输入原料图片的rgb数组和目标图片对象,返回一个二维数组,其中每个数代表一个原料图片在其数组中的索引,将用该图片替换相应像素)和DefaultSamping(实现PicSampling接口,返回采样后的图片对象,我只是简单的用默认的采样方法改变了图片大小,大家可以根据需要修改)
public class ImageStitch {
public static int len = 25;
BufferedImage aim = null;
BufferedImage work = null;
BufferedImage srcsOld[] = null;
BufferedImage srcs[] = null;
int rgbs[][] = null;
int aimOfSrc[][];
int numSrc = 0;
public ImageStitch(File aim, File[] srcs) throws IOException {
//原料图片个数
numSrc = srcs.length;
// 初始化插值后原料图片数组
this.srcs = new BufferedImage[numSrc];
//初始化原料图片的数组
srcsOld = new BufferedImage[numSrc];
//初始化图片的rgb数组
this.rgbs = new int[numSrc][];
// 读入目标图片(要拼的图片)
this.aim = ImageIO.read(aim);
DefaultSampling sampling = new DefaultSampling();
for (int i = 0; i < numSrc; ++i) {
// 读入源(材料)图片并获取rgb数组
srcsOld[i] = ImageIO.read(srcs[i]);
//对图片进行插值
this.srcs[i] = sampling.sampling(srcsOld[i]);
int width = this.srcs[i].getWidth();
int height = this.srcs[i].getHeight();
this.rgbs[i] = new int[width * height];
//获取图片的rgb数组
this.rgbs[i] = this.srcs[i].getRGB(0, 0, width, height, this.rgbs[i], 0, width);
}
}
public void parseAim(AimParser aimParser) {
//得到替换像素的图片的索引的数组
aimOfSrc = aimParser.parse(rgbs, aim);
//作品图片初始化
work = new BufferedImage(aim.getWidth() * len, aim.getHeight() * len, BufferedImage.TYPE_INT_RGB);
int x = 0, y = 0;
for(int i = 0; i < aimOfSrc.length; ++i){
x = 0;
for(int j = 0; j < aimOfSrc[i].length; ++j){
//将小图片填入大图片中
work.setRGB(x, y, len, len, rgbs[aimOfSrc[j][i]], 0, len);
x += len;
}
y += len;
}
//写图片到硬盘
FileOutputStream ops;
try {
ops = new FileOutputStream(new File("D:/Photo/stitch/znh.jpg"));
ImageIO.write(work, "jpg", ops);
ops.flush();
ops.close();
System.out.println("Success!");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
File aim = new File("D:/Photo/stitch/z5.jpg");
File[] srcs = new File[6];
srcs[0] = new File("D:/Photo/stitch/s1.jpg");
srcs[1] = new File("D:/Photo/stitch/s4.jpg");
srcs[2] = new File("D:/Photo/stitch/s3.jpg");
srcs[3] = new File("D:/Photo/stitch/s5.jpg");
srcs[4] = new File("D:/Photo/stitch/5.jpg");
srcs[5] = new File("D:/Photo/stitch/2.jpg");
ImageStitch imageStitch = new ImageStitch(aim, srcs);
imageStitch.parseAim(new VectorParser());
}
}
AimParser接口和PicSampling接口
public interface AimParser {
public int[][] parse(int[][] rgbs, BufferedImage aim);
}
public interface PicSampling {
public BufferedImage sampling(BufferedImage aim);
}
VectorParser 回答中取平均色值和选取替换图片的过程
public class VectorParser implements AimParser {
int[][] rgbs = null;
int[] averageR = null;
int[] averageG = null;
int[] averageB = null;
@Override
public int[][] parse(int[][] r, BufferedImage aim) {
int width = aim.getWidth();
int height = aim.getHeight();
int[][] aimOfSrc = new int[height][width];
rgbs = r;
averageR = new int[rgbs.length];
averageG = new int[rgbs.length];
averageB = new int[rgbs.length];
for (int i = 0; i < rgbs.length; ++i) {
for (int j = 0; j < rgbs[i].length; ++j) {
averageR[i] += (rgbs[i][j] & 0xff0000) >> 16;
averageG[i] += (rgbs[i][j] & 0xff00) >> 8;
averageB[i] += rgbs[i][j] & 0xff;
}
averageR[i] /= rgbs[i].length;
averageG[i] /= rgbs[i].length;
averageB[i] /= rgbs[i].length;
}
for (int j = 0; j < height; ++j) {
for (int i = 0; i < width; ++i) {
int rgb = aim.getRGB(i, j);
aimOfSrc[j][i] = choose(rgb);
}
}
return aimOfSrc;
}
private int choose(int rgb) {
int index = 0;
int min = 2147483647;
int r = (rgb & 0xff0000) >> 16;
int g = (rgb & 0xff00) >> 8;
int b = rgb & 0xff;
for (int i = 0; i < rgbs.length; ++i) {
int temp = (int)(Math.pow(averageR[i] - r, 2) + Math.pow(averageG[i] - g, 2) + Math.pow(averageB[i] - b, 2));
if(temp < min){
min = temp;
index = i;
}
}
return index;
}
}
DefaultSampling
public class DefaultSampling implements PicSampling{
@Override
public BufferedImage sampling(BufferedImage aim) {
BufferedImage ret = new BufferedImage(ImageStitch.len, ImageStitch.len, BufferedImage.TYPE_INT_RGB);
ret.getGraphics().drawImage(aim, 0, 0, ImageStitch.len, ImageStitch.len, null);
return aim;
}
}
That’s all.
有什么说的不清楚的地方随时提问。