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:// ...
随机推荐
- Android图表库MPAndroidChart(二)——线形图的方方面面,看完你会回来感谢我的
Android图表库MPAndroidChart(二)--线形图的方方面面,看完你会回来感谢我的 在学习本课程之前我建议先把我之前的博客看完,这样对整体的流程有一个大致的了解 Android图表库MP ...
- ROS(indigo) 语音工具 科大讯飞 百度 pocketsphinx julius rospeex 16.11.22更新 ROS中文语音
ROS语音工具汇总,目前先给出链接,只用过一些简单的命令. 中文语音: 参考链接:使用科大讯飞库 1 http://www.ncnynl.com/archives/201611/1069.html 2 ...
- eval和列表解析的一处陷阱
>>> def f(): a=1 return [i+a for i in range(3)] >>> f() [1, 2, 3] >>> def ...
- 【伯乐在线】Java线程面试题 Top 50
本文由 ImportNew - 李 广 翻译自 javarevisited.欢迎加入翻译小组.转载请见文末要求. 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特 ...
- 会声会影小成果分享(那段青春岁月)——校学习部宣传视频制作&生日祝福
大二的时候在校学习部当副部长,没有给干事们带去好的工作经验和管理方法,我净在折腾新媒体方面的东西,很惭愧的说,那时候申请了一个微信的公众号(HGXXB1314),我那时候以为自己很叼,最后是发现自己装 ...
- 14 Fragment 注意点
API 过时问题 API 23过时 public void onAttach(Activity activity)替换为public void onAttach(Context context) 注意 ...
- Nginx中502和504错误详解
在使用Nginx时,经常会碰到502 Bad Gateway和504 Gateway Time-out错误,下面以Nginx+PHP-FPM来分析下这两种常见错误的原因和解决方案. 1.502 Bad ...
- Dynamics CRM 2015 Online Update1 UI界面的更新变化
听说出 Dynamics CRM 2015 Online Update1了,立马跑去申请了个30天试用版简单的看了下,UI上的变化还是让人耳目一新的,也可能是被CRM2013的UI蹂躏太久了没 ...
- Android的DatePicker和TimePicker-android学习之旅(三十八)
DatePicker和TimePicker简介 DatePicker和TimePicker是从FrameLayout继承而来,他们都是比较简单的组件.时间改变时间分别添加OnDateChangeLis ...
- mysql进阶(二十五)解决数据库NO CONNECTION问题
解决数据库NO CONNECTION问题 前言 数据库版本类型:Mysql5.5 在应用程序连接数据库时,提示数据库连接失败.打开数据库查看,显示如下. 究其原因,是因为mysql服务出现了问题,重启 ...