LIRe图像检索:Tamura纹理特征算法源码分析

2023-10-23 19:51

本文主要是介绍LIRe图像检索:Tamura纹理特征算法源码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 Tamura概述

Tamura纹理特征包括了粗糙度(coarseness)、对比度(contrast)、方向度(directionality)、线性度(linelikeness)、规则度(regularity)、粗略度(roughness)。最原始的Tamura论文有《Textural Features Correspondingto Visual Perception》。Tamura纹理特征要比灰度共生矩阵得到的纹理特征更直观,在视觉效果上更有优势。LIRe实现了Tamura纹理特征,包括粗糙度、对比度和方向。

2 源码分析

在lire.jar中Tamura源码的位置如下:


以下为我对源码的分析和解读。

public class Tamura implements GlobalFeature {private static final int MAX_IMG_HEIGHT = 64;private int[][] grayScales;private int imgWidth;private int imgHeight;private double[] histogram;private static final double[][] filterH = new double[][]{{-1.0D, 0.0D, 1.0D}, {-1.0D, 0.0D, 1.0D}, {-1.0D, 0.0D, 1.0D}};private static final double[][] filterV = new double[][]{{-1.0D, -1.0D, -1.0D}, {0.0D, 0.0D, 0.0D}, {1.0D, 1.0D, 1.0D}};private static final String TAMURA_NAME = "tamura";public Tamura() {}//第一个指标coarseness 粗糙度public double coarseness(int n0, int n1) {double result = 0.0D;for(int i = 1; i < n0 - 1; ++i) {for(int j = 1; j < n1 - 1; ++j) {result += Math.pow(2.0D, (double)this.sizeLeadDiffValue(i, j));}}result = 1.0D / (double)(n0 * n1) * result;return result;}public double averageOverNeighborhoods(int x, int y, int k) {double result = 0.0D;double border = Math.pow(2.0D, (double)(2 * k));boolean x0 = false;boolean y0 = false;for(int i = 0; (double)i < border; ++i) {for(int j = 0; (double)j < border; ++j) {int var12 = x - (int)Math.pow(2.0D, (double)(k - 1)) + i;int var13 = y - (int)Math.pow(2.0D, (double)(k - 1)) + j;if(var12 < 0) {var12 = 0;}if(var13 < 0) {var13 = 0;}if(var12 >= this.imgWidth) {var12 = this.imgWidth - 1;}if(var13 >= this.imgHeight) {var13 = this.imgHeight - 1;}result += (double)this.grayScales[var12][var13];}}result = 1.0D / Math.pow(2.0D, (double)(2 * k)) * result;return result;}public double differencesBetweenNeighborhoodsHorizontal(int x, int y, int k) {double result = 0.0D;result = Math.abs(this.averageOverNeighborhoods(x + (int)Math.pow(2.0D, (double)(k - 1)), y, k) - this.averageOverNeighborhoods(x - (int)Math.pow(2.0D, (double)(k - 1)), y, k));return result;}public double differencesBetweenNeighborhoodsVertical(int x, int y, int k) {double result = 0.0D;result = Math.abs(this.averageOverNeighborhoods(x, y + (int)Math.pow(2.0D, (double)(k - 1)), k) - this.averageOverNeighborhoods(x, y - (int)Math.pow(2.0D, (double)(k - 1)), k));return result;}public int sizeLeadDiffValue(int x, int y) {double result = 0.0D;int maxK = 1;for(int k = 0; k < 3; ++k) {double tmp = Math.max(this.differencesBetweenNeighborhoodsHorizontal(x, y, k), this.differencesBetweenNeighborhoodsVertical(x, y, k));if(result < tmp) {maxK = k;result = tmp;}}return maxK;}//第二个指标Contrast,对比度public double contrast() {double result = 0.0D;double my4 = 0.0D;double alpha4 = 0.0D;double my = this.calculateMy();double sigma = this.calculateSigma(my);if(sigma <= 0.0D) {return 0.0D;} else {for(int x = 0; x < this.imgWidth; ++x) {for(int y = 0; y < this.imgHeight; ++y) {my4 += Math.pow((double)this.grayScales[x][y] - my, 4.0D);}}alpha4 = my4 / Math.pow(sigma, 4.0D);result = sigma / Math.pow(alpha4, 0.25D);return result;}}public double calculateMy() {double mean = 0.0D;for(int x = 0; x < this.imgWidth; ++x) {for(int y = 0; y < this.imgHeight; ++y) {mean += (double)this.grayScales[x][y];}}mean /= (double)(this.imgWidth * this.imgHeight);return mean;}public double calculateSigma(double mean) {double result = 0.0D;for(int x = 0; x < this.imgWidth; ++x) {for(int y = 0; y < this.imgHeight; ++y) {result += Math.pow((double)this.grayScales[x][y] - mean, 2.0D);}}result /= (double)(this.imgWidth * this.imgHeight);return Math.sqrt(result);}//第三个指标 Directionality,方向度public double[] directionality() {double[] histogram = new double[16];double maxResult = 3.0D;double binWindow = maxResult / (double)(histogram.length - 1);boolean bin = true;for(int x = 1; x < this.imgWidth - 1; ++x) {for(int y = 1; y < this.imgHeight - 1; ++y) {int var9 = (int)((1.5707963267948966D + Math.atan(this.calculateDeltaV(x, y) / this.calculateDeltaH(x, y))) / binWindow);++histogram[var9];}}return histogram;}public double calculateDeltaH(int x, int y) {double result = 0.0D;for(int i = 0; i < 3; ++i) {for(int j = 0; j < 3; ++j) {result += (double)this.grayScales[x - 1 + i][y - 1 + j] * filterH[i][j];}}return result;}public double calculateDeltaV(int x, int y) {double result = 0.0D;for(int i = 0; i < 3; ++i) {for(int j = 0; j < 3; ++j) {result += (double)this.grayScales[x - 1 + i][y - 1 + j] * filterV[i][j];}}return result;}public double getDistance(double[] targetFeature, double[] queryFeature) {double result = 0.0D;for(int i = 2; i < targetFeature.length; ++i) {result += Math.pow(targetFeature[i] - queryFeature[i], 2.0D);}return result;}public void extract(BufferedImage image) {this.histogram = new double[18];ColorConvertOp op = new ColorConvertOp(image.getColorModel().getColorSpace(), ColorSpace.getInstance(1003), new RenderingHints(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY));BufferedImage bimg = op.filter(image, (BufferedImage)null);bimg = ImageUtils.scaleImage(bimg, 64);WritableRaster raster = bimg.getRaster();int[] tmp = new int[3];this.grayScales = new int[raster.getWidth()][raster.getHeight()];int i;for(i = 0; i < raster.getWidth(); ++i) {for(int j = 0; j < raster.getHeight(); ++j) {raster.getPixel(i, j, tmp);this.grayScales[i][j] = tmp[0];}}this.imgWidth = bimg.getWidth();this.imgHeight = bimg.getHeight();//第一个指标 Coarseness,粗糙度this.histogram[0] = this.coarseness(bimg.getWidth(), bimg.getHeight());//第二个指标 Contrast,对比度this.histogram[1] = this.contrast();//第三个指标 Directionality,方向度double[] directionality = this.directionality();for(i = 2; i < this.histogram.length; ++i) {this.histogram[i] = directionality[i - 2];}}public byte[] getByteArrayRepresentation() {return SerializationUtils.toByteArray(this.histogram);}public void setByteArrayRepresentation(byte[] in) {this.histogram = SerializationUtils.toDoubleArray(in);}public void setByteArrayRepresentation(byte[] in, int offset, int length) {this.histogram = SerializationUtils.toDoubleArray(in, offset, length);}public double[] getFeatureVector() {return this.histogram;}public double getDistance(LireFeature feature) {if(!(feature instanceof Tamura)) {throw new UnsupportedOperationException("Wrong descriptor.");} else {Tamura tamura = (Tamura)feature;return this.getDistance(tamura.histogram, this.histogram);}}public String getFeatureName() {return "Tamura Features";}public String getFieldName() {return "TAMURA";}
}
Reference:

http://blog.sina.com.cn/s/blog_5ae7a1de01012r03.html

http://blog.csdn.net/jzwong/article/details/51584535


这篇关于LIRe图像检索:Tamura纹理特征算法源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/270106

相关文章

基于Python开发一个图像水印批量添加工具

《基于Python开发一个图像水印批量添加工具》在当今数字化内容爆炸式增长的时代,图像版权保护已成为创作者和企业的核心需求,本方案将详细介绍一个基于PythonPIL库的工业级图像水印解决方案,有需要... 目录一、系统架构设计1.1 整体处理流程1.2 类结构设计(扩展版本)二、核心算法深入解析2.1 自

SpringBoot中六种批量更新Mysql的方式效率对比分析

《SpringBoot中六种批量更新Mysql的方式效率对比分析》文章比较了MySQL大数据量批量更新的多种方法,指出REPLACEINTO和ONDUPLICATEKEY效率最高但存在数据风险,MyB... 目录效率比较测试结构数据库初始化测试数据批量修改方案第一种 for第二种 case when第三种

解决1093 - You can‘t specify target table报错问题及原因分析

《解决1093-Youcan‘tspecifytargettable报错问题及原因分析》MySQL1093错误因UPDATE/DELETE语句的FROM子句直接引用目标表或嵌套子查询导致,... 目录报js错原因分析具体原因解决办法方法一:使用临时表方法二:使用JOIN方法三:使用EXISTS示例总结报错原

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

MySQL中的表连接原理分析

《MySQL中的表连接原理分析》:本文主要介绍MySQL中的表连接原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、表连接原理【1】驱动表和被驱动表【2】内连接【3】外连接【4编程】嵌套循环连接【5】join buffer4、总结1、背景

python中Hash使用场景分析

《python中Hash使用场景分析》Python的hash()函数用于获取对象哈希值,常用于字典和集合,不可变类型可哈希,可变类型不可,常见算法包括除法、乘法、平方取中和随机数哈希,各有优缺点,需根... 目录python中的 Hash除法哈希算法乘法哈希算法平方取中法随机数哈希算法小结在Python中,

Java Stream的distinct去重原理分析

《JavaStream的distinct去重原理分析》Javastream中的distinct方法用于去除流中的重复元素,它返回一个包含过滤后唯一元素的新流,该方法会根据元素的hashcode和eq... 目录一、distinct 的基础用法与核心特性二、distinct 的底层实现原理1. 顺序流中的去重