千图成像(用图片拼图片)的java教程

大题思路我在知乎有回答

在这里大概讲下代码。我实现的比较粗糙,只能使用正方形的图片,如有其他需要可以自行改动。

下面是主要代码。
这里面有俩自定义的类,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.
有什么说的不清楚的地方随时提问。

你可能感兴趣的:(java)