LIRe 源代码分析 7:算法类[以颜色布局为例]
=====================================================
LIRe源代码分析系列文章列表:
LIRe 源代码分析 2:基本接口(DocumentBuilder)
LIRe 源代码分析 3:基本接口(ImageSearcher)
LIRe 源代码分析 4:建立索引(DocumentBuilder)[以颜色布局为例]
LIRe 源代码分析 6:检索(ImageSearcher)[以颜色布局为例]
=====================================================
前面关于LIRe的文章,介绍的都是架构方面的东西,没有细研究具体算法。本文以颜色布局为例,介绍一下算法类的实现。
颜色布局描述符以一种非常紧密的形式有效地表示了图像的颜色空间分布信息。它以非常小的计算代价, 带来高的检索效率。因此, 颜色布局特征在视频镜头关键帧提取中有很重要的意义。颜色布局提取方法如下:
1 将图像从RGB 空间映射到YCbCr空间, 映射公式为
Y= 0.299* R + 0.587* G + 0.114* B
Cb= - 0.169* R – 0.331* G + 0.500* B
Cr = 0.500* R –0.419* G – 0.081* B
2 将整幅图像分成64块, 每块尺寸为(W /8) *(H/8), 其中W 为整幅图像的宽度, H 为整幅图像的高度, 计算每一块中所有像素的各个颜色分量( Y, Cb, Cr )的平均值, 并以此作为该块的代表颜色( Y, Cb, Cr );
3 对帧图像中各块的颜色分量平均值进行DCT 变换, 得到各分量的一系列DCT 系数;
4 对各分量的DCT 系数, 通过之字形扫描和量化, 取出各自DCT 变换的低频分量, 这三组低频分量共同构成该帧图像的颜色布局描述符。
颜色布局算法的实现位于ColorLayoutImpl类中,该类处于“net.semanticmetadata.lire.imageanalysis.mpeg7”包中,如图所示:
ColorLayoutImpl类的代码量很大,很多地方都还没有研究,在这里仅展示部分已经看过的代码:
/* 雷霄骅
* 中国传媒大学/数字电视技术
* leixiaohua1020@126.com
*
*/
/**
* Class for extrcating & comparing MPEG-7 based CBIR descriptor ColorLayout
*
* @author Mathias Lux, mathias@juggle.at
*/
public class ColorLayoutImpl {
// static final boolean debug = true;
protected int[][] shape;
protected int imgYSize, imgXSize;
protected BufferedImage img;
protected static int[] availableCoeffNumbers = {1, 3, 6, 10, 15, 21, 28, 64};
//特征向量(Y,Cb,Cr)
public int[] YCoeff;
public int[] CbCoeff;
public int[] CrCoeff;
//特征向量的大小
protected int numCCoeff = 28, numYCoeff = 64;
protected static int[] arrayZigZag = {
0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
};
protected static double[][] arrayCosin = {
...
};
protected static int[][] weightMatrix = new int[3][64];
protected BufferedImage colorLayoutImage;
/**
* init used by all constructors
*/
private void init() {
shape = new int[3][64];
YCoeff = new int[64];
CbCoeff = new int[64];
CrCoeff = new int[64];
colorLayoutImage = null;
extract();
}
public void extract(BufferedImage bimg) {
this.img = bimg;
imgYSize = img.getHeight();
imgXSize = img.getWidth();
init();
}
private void createShape() {
int y_axis, x_axis;
int i, k, x, y, j;
long[][] sum = new long[3][64];
int[] cnt = new int[64];
double yy = 0.0;
int R, G, B;
//init of the blocks
for (i = 0; i < 64; i++) {
cnt[i] = 0;
sum[0][i] = 0;
sum[1][i] = 0;
sum[2][i] = 0;
shape[0][i] = 0;
shape[1][i] = 0;
shape[2][i] = 0;
}
WritableRaster raster = img.getRaster();
int[] pixel = {0, 0, 0};
for (y = 0; y < imgYSize; y++) {
for (x = 0; x < imgXSize; x++) {
raster.getPixel(x, y, pixel);
R = pixel[0];
G = pixel[1];
B = pixel[2];
y_axis = (int) (y / (imgYSize / 8.0));
x_axis = (int) (x / (imgXSize / 8.0));
k = (y_axis << 3) + x_axis;
//RGB to YCbCr, partition and average-calculation
yy = (0.299 * R + 0.587 * G + 0.114 * B) / 256.0;
sum[0][k] += (int) (219.0 * yy + 16.5); // Y
sum[1][k] += (int) (224.0 * 0.564 * (B / 256.0 * 1.0 - yy) + 128.5); // Cb
sum[2][k] += (int) (224.0 * 0.713 * (R / 256.0 * 1.0 - yy) + 128.5); // Cr
cnt[k]++;
}
}
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
for (k = 0; k < 3; k++) {
if (cnt[(i << 3) + j] != 0)
shape[k][(i << 3) + j] = (int) (sum[k][(i << 3) + j] / cnt[(i << 3) + j]);
else
shape[k][(i << 3) + j] = 0;
}
}
}
}
......(其他代码都已经省略)
private int extract() {
createShape();
Fdct(shape[0]);
Fdct(shape[1]);
Fdct(shape[2]);
YCoeff[0] = quant_ydc(shape[0][0] >> 3) >> 1;
CbCoeff[0] = quant_cdc(shape[1][0] >> 3);
CrCoeff[0] = quant_cdc(shape[2][0] >> 3);
//quantization and zig-zagging
for (int i = 1; i < 64; i++) {
YCoeff[i] = quant_ac((shape[0][(arrayZigZag[i])]) >> 1) >> 3;
CbCoeff[i] = quant_ac(shape[1][(arrayZigZag[i])]) >> 3;
CrCoeff[i] = quant_ac(shape[2][(arrayZigZag[i])]) >> 3;
}
setYCoeff(YCoeff);
setCbCoeff(CbCoeff);
setCrCoeff(CrCoeff);
return 0;
}
/**
* Takes two ColorLayout Coeff sets and calculates similarity.
*
* @return -1.0 if data is not valid.
*/
public static double getSimilarity(int[] YCoeff1, int[] CbCoeff1, int[] CrCoeff1, int[] YCoeff2, int[] CbCoeff2, int[] CrCoeff2) {
int numYCoeff1, numYCoeff2, CCoeff1, CCoeff2, YCoeff, CCoeff;
//Numbers of the Coefficients of two descriptor values.
numYCoeff1 = YCoeff1.length;
numYCoeff2 = YCoeff2.length;
CCoeff1 = CbCoeff1.length;
CCoeff2 = CbCoeff2.length;
//take the minimal Coeff-number
YCoeff = Math.min(numYCoeff1, numYCoeff2);
CCoeff = Math.min(CCoeff1, CCoeff2);
setWeightingValues();
int j;
int[] sum = new int[3];
int diff;
sum[0] = 0;
for (j = 0; j < YCoeff; j++) {
diff = (YCoeff1[j] - YCoeff2[j]);
sum[0] += (weightMatrix[0][j] * diff * diff);
}
sum[1] = 0;
for (j = 0; j < CCoeff; j++) {
diff = (CbCoeff1[j] - CbCoeff2[j]);
sum[1] += (weightMatrix[1][j] * diff * diff);
}
sum[2] = 0;
for (j = 0; j < CCoeff; j++) {
diff = (CrCoeff1[j] - CrCoeff2[j]);
sum[2] += (weightMatrix[2][j] * diff * diff);
}
//returns the distance between the two desciptor values
return Math.sqrt(sum[0] * 1.0) + Math.sqrt(sum[1] * 1.0) + Math.sqrt(sum[2] * 1.0);
}
public int getNumberOfCCoeff() {
return numCCoeff;
}
public void setNumberOfCCoeff(int numberOfCCoeff) {
this.numCCoeff = numberOfCCoeff;
}
public int getNumberOfYCoeff() {
return numYCoeff;
}
public void setNumberOfYCoeff(int numberOfYCoeff) {
this.numYCoeff = numberOfYCoeff;
}
public String getStringRepresentation() {
StringBuilder sb = new StringBuilder(256);
StringBuilder sbtmp = new StringBuilder(256);
for (int i = 0; i < numYCoeff; i++) {
sb.append(YCoeff[i]);
if (i + 1 < numYCoeff) sb.append(' ');
}
sb.append("z");
for (int i = 0; i < numCCoeff; i++) {
sb.append(CbCoeff[i]);
if (i + 1 < numCCoeff) sb.append(' ');
sbtmp.append(CrCoeff[i]);
if (i + 1 < numCCoeff) sbtmp.append(' ');
}
sb.append("z");
sb.append(sbtmp);
return sb.toString();
}
public void setStringRepresentation(String descriptor) {
String[] coeffs = descriptor.split("z");
String[] y = coeffs[0].split(" ");
String[] cb = coeffs[1].split(" ");
String[] cr = coeffs[2].split(" ");
numYCoeff = y.length;
numCCoeff = Math.min(cb.length, cr.length);
YCoeff = new int[numYCoeff];
CbCoeff = new int[numCCoeff];
CrCoeff = new int[numCCoeff];
for (int i = 0; i < numYCoeff; i++) {
YCoeff[i] = Integer.parseInt(y[i]);
}
for (int i = 0; i < numCCoeff; i++) {
CbCoeff[i] = Integer.parseInt(cb[i]);
CrCoeff[i] = Integer.parseInt(cr[i]);
}
}
public int[] getYCoeff() {
return YCoeff;
}
public int[] getCbCoeff() {
return CbCoeff;
}
public int[] getCrCoeff() {
return CrCoeff;
}
}
下面介绍几个主要的函数:
提取:
1.extract(BufferedImage bimg):提取特征向量的函数,里面调用了init()。
2.init():初始化了 YCoeff,CbCoeff, CrCoeff。调用extract()(注意这个extract()是没有参数的)
3.extract():完成了提取特征向量的过程,其中调用了createShape()。
4.createShape():未研究。
获取/设置特征向量(注意:有参数为String和byte[]两种类型的特征向量,按照原代码里的说法,byte[]的效率要高一些):
1.getStringRepresentation():获取特征向量
2.setStringRepresentation():设置特征向量
计算相似度:
getSimilarity(int[] YCoeff1, int[] CbCoeff1, int[] CrCoeff1, int[] YCoeff2, int[] CbCoeff2, int[] CrCoeff2)
主要的变量:
3个存储特征向量(Y,Cb,Cr)的数组:
public int[] YCoeff;
public int[] CbCoeff;
public int[] CrCoeff;
特征向量的大小:
protected int numCCoeff = 28, numYCoeff = 64;
LIRe 源代码分析 7:算法类[以颜色布局为例]的更多相关文章
- LIRe 源代码分析 6:检索(ImageSearcher)[以颜色布局为例]
===================================================== LIRe源代码分析系列文章列表: LIRe 源代码分析 1:整体结构 LIRe 源代码分析 ...
- LIRe 源代码分析 5:提取特征向量[以颜色布局为例]
===================================================== LIRe源代码分析系列文章列表: LIRe 源代码分析 1:整体结构 LIRe 源代码分析 ...
- LIRe 源代码分析 4:建立索引(DocumentBuilder)[以颜色布局为例]
===================================================== LIRe源代码分析系列文章列表: LIRe 源代码分析 1:整体结构 LIRe 源代码分析 ...
- 转:LIRe 源代码分析
1:整体结构 LIRE(Lucene Image REtrieval)提供一种的简单方式来创建基于图像特性的Lucene索引.利用该索引就能够构建一个基于内容的图像检索(content- based ...
- LIRe 源代码分析 3:基本接口(ImageSearcher)
===================================================== LIRe源代码分析系列文章列表: LIRe 源代码分析 1:整体结构 LIRe 源代码分析 ...
- LIRe 源代码分析 2:基本接口(DocumentBuilder)
===================================================== LIRe源代码分析系列文章列表: LIRe 源代码分析 1:整体结构 LIRe 源代码分析 ...
- LIRe 源代码分析 1:整体结构
===================================================== LIRe源代码分析系列文章列表: LIRe 源代码分析 1:整体结构 LIRe 源代码分析 ...
- Hadoop源代码分析
http://wenku.baidu.com/link?url=R-QoZXhc918qoO0BX6eXI9_uPU75whF62vFFUBIR-7c5XAYUVxDRX5Rs6QZR9hrBnUdM ...
- Hadoop源代码分析(完整版)
Hadoop源代码分析(一) 关键字: 分布式云计算 Google的核心竞争技术是它的计算平台.Google的大牛们用了下面5篇文章,介绍了它们的计算设施. GoogleCluster:http:// ...
随机推荐
- PGM:基于模板的表示
http://blog.csdn.net/pipisorry/article/details/52537660 引言 概率图模型(无论贝叶斯网或马尔可夫网)在一个固定的随机变量集X上具体指定了一个联合 ...
- OpenResty修改Nginx默认autoindex页面
Nginx的autoindex 命令可以自动列出目录下的文件,一些网站用这个功能做文件下载,但是Nginx又没有提供这个页面的 自定义的功能,后来看到别人提及 ngx_openresty,才想到 bo ...
- paypal的IPN机制
paypal对接时发现有这么一个机制,看起来还不错,起到了防止篡改欺诈行为,保证了通信的安全性,但会增加几次通信.
- ORACLE数据库学习之备份与恢复
oracle数据库的备份与恢复 第一部分:数据库的备份 备份的必要性 因为各种人为或外界的因素可能会造成数据库中灾难性的数据丢失,为了保证数据库中数据的安全,必须采取备份措施保证RDBMS中包含 ...
- velocity中加载模板文件的方式
velocity有多中种方式供我们去加载我们自定义的模板文件,下面详细的介绍使用的方法. 1.1.1. 加载classpath目录下的模板文件 使用classpath方式加载,是我们经常用到的一种方式 ...
- iOS下JS与OC互相调用(二)--WKWebView 拦截URL
在上篇文章中讲述了使用UIWebView拦截URL的方式来处理JS与OC交互. 由于UIWebView比较耗内存,性能上不太好,而苹果在iOS 8中推出了WKWebView. 同样的用WKWebVie ...
- 2.QT中操作word文档
Qt/Windows桌面版提供了ActiveQt框架,用以为Qt和ActiveX提供完美结合.ActiveQt由两个模块组成: A QAxContainer模块允许我们使用COM对象并且可以 ...
- 【java线程系列】java线程系列之java线程池详解
一线程池的概念及为何需要线程池: 我们知道当我们自己创建一个线程时如果该线程执行完任务后就进入死亡状态,这样如果我们需要在次使用一个线程时得重新创建一个线程,但是线程的创建是要付出一定的代价的,如果在 ...
- Android简易实战教程--第四话《最简单的短信发送器》
首先配置一个布局: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmln ...
- Error running app: Instant Run requires 'Tools | Android | Enable ADB integration' to be enabled.
废了半天劲才解决... 就三步:菜单栏,Tools -> Adnroid -> enable ADB integration