画像同士の距離がとれたら近い画像マップができるよね

鬼太郎ビール ヴァイツェン

CCVで画像同士の距離が取れたってことは、画像同士どれが近いかというマップができるよね。


ソースはこんな感じで

import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;

public class ColorCoherenceVectorMap extends javax.swing.JFrame {

    /** Creates new form ColorCoherenceVectorMap */
    public ColorCoherenceVectorMap() {
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        java.awt.Dimension screenSize = 
            java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width-800)/2, (screenSize.height-600)/2, 800, 600);

        readFile(new File("C:\\search"));

        final int[][] dists = new int[images.size()][images.size()];
        for(int i = 0; i < images.size(); ++i){
            int[] ccv1 = images.get(i).getValue();
            for(int j = i + 1; j < images.size(); ++j){
                int[] ccv2 = images.get(j).getValue();
                int total = 0;
                for(int k = 0; k < ccv1.length; ++k){
                    total += Math.abs(ccv1[k] - ccv2[k]);
                }
                dists[i][j] = total;
                dists[j][i] = total;
            }
        }

        final BufferedImage img = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);
        final JComponent comp = new JComponent() {
            @Override
            protected void paintComponent(Graphics g) {
                g.drawImage(img, 0, 0, this);
            }
        };
        add(comp);

        final Point2D[] pos = new Point2D[images.size()];
        Random r = new Random();
        final Image[] thumbs = new Image[pos.length];
        int limit = 40;
        for(int i = 0; i < pos.length; ++i){
            pos[i] = new Point2D.Double(r.nextInt(800), r.nextInt(600));
            try {
                BufferedImage im = ImageIO.read(new File(images.get(i).getKey()));
                int w = im.getWidth();
                int h = im.getHeight();
                if(w > h){
                    h = limit * h / w;
                    w = limit;
                }else{
                    w = limit * w / h;
                    h = limit;
                }
                BufferedImage imt = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
                Graphics2D g = (Graphics2D) imt.getGraphics();
                g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g.drawImage(im, 0, 0, w, h, this);
                g.dispose();
                thumbs[i] = imt;
            } catch (IOException ex) {
            }
        }

        new Thread(){
            @Override
            public void run() {
                long t = System.currentTimeMillis();
                for(;;){
                    for(int i = 0; i < pos.length; ++i){
                        for(int j = 0; j < pos.length; ++j){
                            if(i == j) continue;
                            double dx = pos[i].getX() - pos[j].getX();
                            double dy = pos[i].getY() - pos[j].getY();
                            if(dx == 0 && dy == 0){
                                pos[i].setLocation(pos[i].getX() + 1, pos[i].getY() + 1);
                                dx = 1;
                                dy = 1;
                            }
                            double d = Math.sqrt(dx * dx + dy * dy);
                            int nd = dists[i][j] / 8 + 15;
                            dx = (int)(dx * 2 / d);
                            dy = (int)(dy * 2 / d);
                            if(d > nd){
                                pos[i].setLocation(pos[i].getX() - dx, pos[i].getY() - dy);
                            }else{
                                pos[i].setLocation(pos[i].getX() + dx, pos[i].getY() + dy);
                            }
                        }
                    }
                    double mdx = 0;
                    double mdy = 0;
                    for(int i = 0; i < pos.length; ++i){
                        mdx += pos[i].getX();
                        mdy += pos[i].getY();
                    }
                    mdx = 400 - mdx / pos.length;
                    mdy = 300 - mdy / pos.length;
                    for(int i = 0; i < pos.length; ++i){
                        pos[i].setLocation(pos[i].getX() + mdx, pos[i].getY() + mdy);
                    }

                    long nt = System.currentTimeMillis();
                    if(nt - t > 200){
                        t = nt;
                        Graphics2D g = (Graphics2D) img.getGraphics();
                        g.setColor(Color.WHITE);
                        g.fillRect(0, 0, 800, 600);
                        g.setColor(Color.BLACK);
                        for(int i = 0; i < pos.length; ++i){
                            g.drawImage(thumbs[i], (int)pos[i].getX(), (int)pos[i].getY(), ColorCoherenceVectorMap.this);
                        }
                        g.dispose();
                        comp.repaint();
                    }
                }
            }

        }.start();
    }

    //ファイルのCCVを求める
    private void readFile(File f){
        if(f.isDirectory()){
            File[] files = f.listFiles();
            for(File file : files){
                readFile(file);
            }
        }else{
            try {
                BufferedImage img = ImageIO.read(f);
                if(img == null) return;
                int[] data = colorCoherenceVector(img);
                images.add(new AbstractMap.SimpleEntry(f.getCanonicalPath(), data));
            } catch (IOException ex) {
                System.out.println(ex.getMessage());
            }

        }
    }

    List<Map.Entry<String, int[]>> images = new ArrayList<Map.Entry<String, int[]>>();

    /** CCVを求める */
    public static int[] colorCoherenceVector(BufferedImage imgsrc){

        int w = imgsrc.getWidth();
        int h = imgsrc.getHeight();
        //サイズ正規化
        int limit = 200;
        if(w < h){
            w = w * limit / h;
            h = limit;
        }else{
            h = h * limit / w;
            w = limit;
        }
        BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Graphics2D grp = (Graphics2D) img.getGraphics();
        grp.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        grp.drawImage(imgsrc, 0, 0, w, h, null);
        grp.dispose();

        //ガウシアンフィルタ
        int[] ctemp = img.getRGB(0, 0, w, h, null, 0, w);
        int[] ctbl = new int[ctemp.length];
        int[][] filter = {
            {1, 2, 1},
            {2, 4, 2},
            {1, 2, 1}};
        for(int y = 0; y < h; ++y){
            for(int x = 0; x < w; ++x){
                int tr = 0;
                int tg = 0;
                int tb = 0;
                int t = 0;
                for(int i = -1; i < 2; ++i){
                    for(int j = -1; j < 2; ++j){
                        if(y + i < 0) continue;
                        if(x + j < 0) continue;
                        if(y + i >= h) continue;
                        if(x + j >= w) continue;
                        t += filter[i + 1][j + 1];
                        int adr = (x + j) + (y + i) * w;
                        tr += filter[i + 1][j + 1] * ((ctemp[adr] >> 16) & 255);
                        tg += filter[i + 1][j + 1] * ((ctemp[adr] >> 8)  & 255);
                        tb += filter[i + 1][j + 1] * ( ctemp[adr]        & 255);
                    }
                }
                ctbl[x + y * w] = ((tr / t) << 16) + ((tg / t) << 8) + tb / t;
            }
        }

        //減色
        for(int i = 0; i < ctbl.length; ++i){
            int r = (ctemp[i] >> 16) & 192;
            int g = (ctemp[i] >> 8) & 192;
            int b = ctemp[i] & 192;
            ctbl[i] = (r << 16) + (g << 8) + b;
        }

        //タグ付け
        int[][] lbl = new int[w][h];
        int id = 0;
        for(int y = 0; y < h; ++y){
            for(int x = 0; x < w; ++x){
                int col = ctbl[y * w + x];
                if(y > 0){
                    if(x > 0){
                        if(ctbl[(y - 1) * w + x - 1] == col){
                            //左上と一緒
                            lbl[x][y] = lbl[x - 1][y - 1];
                            continue;
                        }
                    }
                    if(ctbl[(y - 1) * w + x] == col){
                        //上と一緒
                        lbl[x][y] = lbl[x][y - 1];
                        continue;
                    }
                    if(x < w - 1){
                        if(ctbl[(y - 1) * w + x + 1] == col){
                            //右上と一緒
                            lbl[x][y] = lbl[x + 1][y - 1];
                            continue;
                        }
                    }
                }
                if(x > 0){
                    if(ctbl[y * w + x - 1] == col){
                        //左と一緒
                        lbl[x][y] = lbl[x - 1][y];
                        continue;
                    }
                }
                lbl[x][y] = id;
                ++id;
            }
        }
        //集計
        int[] count = new int[id];
        int[] color = new int[id];
        for(int x = 0; x < w; ++x){
            for(int y = 0; y < h; ++y){
                count[lbl[x][y]]++;
                color[lbl[x][y]] = ctbl[y * w + x];
            }
        }
        int[] data = new int[129];
        for(int i = 0; i < id; ++i){
            int d = color[i];
            color[i] = (((d >> 22) & 3) << 4) + (((d >> 14) & 3) << 2) + ((d >> 6) & 3);
            if(count[i] < 20){
                data[color[i] * 2 + 1] ++;
            }else{
                data[color[i] * 2] ++;
            }
        }
        return data;
    }

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new ColorCoherenceVectorMap().setVisible(true);
            }
        });
    }
}