当前位置: 首页 > news >正文

基于SVD实现PCA的图像识别

为什么80%的码农都做不了架构师?>>>   hot3.png

        本文实现基于SVD奇异矩阵分解的PCA主成分分析,使用该算法来完成对人脸图像的识别,主要讲解SVD实现PCA的原理,如何利用SVD实现图像特征的降维,以及SVD在文本聚类方面的使用,例如弱化同义词、多义词的影响,解决传统文本向量空间无法解决的问题。

需求分析

        本次实验需求分析很简单,实现人脸图像识别,简单地模仿谷歌、百度的识图搜索功能。

特征表示

        特征用来区别一个事物属于哪种类别,例如“是否有翅膀”可以拿来区别麻雀和哈士奇。如何判别两幅图是否是同一个人,我们可以选取图像的像素矩阵构成特征向量,例如一副180 * 200的jpg图像,根据其像素矩阵可以构成一个特征向量vector[180 * 200],有了特征向量我们就可以使用欧氏距离、余弦相似度等计算两幅图的相似度,从而得出是否属于同一个人。

特征选取

        直接使用像素矩阵构成特征向量,当图像很大时计算难免耗时Time Limited,我们将像素称为原始特征。如何将原始特征向量降维,同时又保存它的主要特性,我们可以联想到PCA主成分分析。在PCA主成分分析中,有一种奇异矩阵分解SVD算法,原矩阵可以分解为 M = U x S x V',然后选取前 k 个重要的特征组成新的特征向量完成降维。例如上例,k=20时,可以组成新的特征向量vec'[180 * 20 + 200 * 20],计算量大大减少又不影响比较结果。接下来,我们就来看一下SVD是个是么东西。

        SVD入门基础三步曲:

(1)机器学习中的数学(5)-强大的矩阵奇异值分解(SVD)及其应用

(2)【译】从几何角度看SVD

(3)奇异值分解和图像压缩

        看完上面3篇也就大概知道SVD的原理是什么了,矩阵U由左奇异特征向量组成(描述y轴方向的变化趋势),矩阵S代表对于左(右)特征向量的重要性,矩阵V' 由右奇异特征向量组成(描述x轴方向的变化趋势)。

002031_Y2yh_1451225.png

        由SVD原理可知,我们可以选取前r 个左奇异特征向量、前r 个右奇异特征向量,组成一个新的特征向量vec[ m * k + n * k],从而完成降维,减少计算量而又保佑原有人脸图像特性。

模型建立

        模型特征向量选取完成后,我们就可以拿来比较两幅人脸图像的相似性了。在计算图像相似性时,本文采用余弦相似度算法进行比较,算法代码实现如下:

Pca.java

package key;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import Jama.*;

public class Pca {
    public double Cosine(double[] v1, double[] v2) {
        double ans = 0;

        int n = v1.length;
        double a = 0;
        for (int i = 0; i < n; i++) {
            a += v1[i] * v2[i];
        }
        double b = 0;
        for (int i = 0; i < n; i++) {
            b += v1[i] * v1[i];
        }
        b = Math.sqrt(b);
        double c = 0;
        for (int i = 0; i < n; i++) {
            c += v2[i] * v2[i];
        }
        c = Math.sqrt(c);
        ans = a / b / c;

        return ans;
    }

    public double[] PcaVector(double[][] pixels, int k) {
        Matrix ps = Matrix.constructWithCopy(pixels);
        if (ps.getRowDimension() < ps.getColumnDimension()) {
            ps = ps.transpose();
        }

        SingularValueDecomposition svd = ps.svd();
        Matrix u = svd.getU();
        Matrix s = svd.getS();
        Matrix vt = svd.getV().transpose();

        double[] vec = new double[u.getRowDimension() * k
                + vt.getColumnDimension() * k];
        int cur = 0;
        for (int i = 0; i < k; i++) {
            for (int j = 0; j < u.getRowDimension(); j++) {
                vec[cur + i * u.getRowDimension() + j] = u.get(j, i);
            }
        }
        cur += u.getRowDimension() * k;
        for (int i = 0; i < k; i++) {
            for (int j = 0; j < vt.getColumnDimension(); j++) {
                vec[cur + i * vt.getColumnDimension() + j] = vt.get(i, j);
            }
        }

        return vec;
    }

    public double[][] Pixels(File file) throws IOException {
        BufferedImage bi = ImageIO.read(file);

        int h = bi.getHeight();
        int w = bi.getWidth();
        double arr[][] = new double[w][h];

        for (int i = 0; i < w; i++) {
            for (int j = 0; j < h; j++) {
                arr[i][j] = bi.getRGB(i, j);
            }
        }

        return arr;
    }
}

Keyven.java

package key;

import java.io.File;
import java.io.IOException;

public class Keyven {
    public static void main(String[] args) throws IOException {
        Pca pk = new Pca();
        int k = 20;

        File key = new File("data/key.jpg");
        double[] vec_key = pk.PcaVector(pk.Pixels(key), k);

        File folder = new File("data/faces");
        if (folder.isDirectory()) {
            for (File f : folder.listFiles()) {
                double[] vec_f = pk.PcaVector(pk.Pixels(f), k);
                System.out.println(f.getName() + ":\t"
                        + pk.Cosine(vec_key, vec_f));
            }
        }
    }
}

实验效果

        原图像集和候选搜索图像如下:

003711_pv6Y_1451225.jpg

003711_AKtU_1451225.jpg

        我们来看一下实验效果:

003806_043N_1451225.jpg

003951_GlHJ_1451225.jpg

        对比还是蛮不错的^_^!

测试数据集下载

实验扩展

        上面讲到左奇异特征向量代表y轴的变化趋势,右奇异向量代表x轴的变化趋势,想象用在自然语言处理文本聚类中,有一个文档-词项共现矩阵,使用SVD作主成分分析,有可能使得原共现矩阵里正交的向量变得不正交,从而弱化了同义词、多义词的影响,而不是简简单单地依靠一个词是否在一篇文档中出现过来造特征……

转载于:https://my.oschina.net/keyven/blog/513396

相关文章:

  • zw·准专利·高保真二值图细部切分算法
  • [ IOS ] iOS-控制器View的创建和生命周期
  • 使用Java对文件进行解压缩
  • 《自信力~成为更好的自己》晨读笔记
  • Spring aop:decare-parent 为类增加新的方法
  • 在resin配置參数实现JConsole远程监控JVM
  • 同样加班 不同收获(转)
  • 使用Java语言开发微信公众平台(八)——自定义菜单功能
  • SPRING-MVC 访问静态资源
  • IE6下position:fixed不支持问题及其解决方式
  • Erlang库 -- 有意思的库汇总
  • 《大数据算法》一2.3 时间亚线性判定算法概述
  • 获取一个数二进制序列中所有的偶数位和奇数位,分别输出二进制序列
  • Setfocus - IE 需要使用setTimeout
  • linux 文件名编码批量转换
  • [译]前端离线指南(上)
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • Android开源项目规范总结
  • Angular 响应式表单 基础例子
  • java8-模拟hadoop
  • javascript 总结(常用工具类的封装)
  • mysql常用命令汇总
  • MySQL-事务管理(基础)
  • 从伪并行的 Python 多线程说起
  • 规范化安全开发 KOA 手脚架
  • 记一次删除Git记录中的大文件的过程
  • 聊聊sentinel的DegradeSlot
  • 如何选择开源的机器学习框架?
  • Semaphore
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • #pragma data_seg 共享数据区(转)
  • #pragma 指令
  • (1)(1.8) MSP(MultiWii 串行协议)(4.1 版)
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (16)Reactor的测试——响应式Spring的道法术器
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (pt可视化)利用torch的make_grid进行张量可视化
  • (八)c52学习之旅-中断实验
  • (分类)KNN算法- 参数调优
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (一)Dubbo快速入门、介绍、使用
  • (转)程序员疫苗:代码注入
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • 、写入Shellcode到注册表上线
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .net Application的目录
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON
  • .NET Micro Framework初体验(二)
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .project文件
  • @media screen 针对不同移动设备
  • @synthesize和@dynamic分别有什么作用?