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实现图像LBP特征提取的操作方法

《使用Python实现图像LBP特征提取的操作方法》LBP特征叫做局部二值模式,常用于纹理特征提取,并在纹理分类中具有较强的区分能力,本文给大家介绍了如何使用Python实现图像LBP特征提取的操作方... 目录一、LBP特征介绍二、LBP特征描述三、一些改进版本的LBP1.圆形LBP算子2.旋转不变的LB

Java程序进程起来了但是不打印日志的原因分析

《Java程序进程起来了但是不打印日志的原因分析》:本文主要介绍Java程序进程起来了但是不打印日志的原因分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java程序进程起来了但是不打印日志的原因1、日志配置问题2、日志文件权限问题3、日志文件路径问题4、程序

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

OpenCV图像形态学的实现

《OpenCV图像形态学的实现》本文主要介绍了OpenCV图像形态学的实现,包括腐蚀、膨胀、开运算、闭运算、梯度运算、顶帽运算和黑帽运算,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起... 目录一、图像形态学简介二、腐蚀(Erosion)1. 原理2. OpenCV 实现三、膨胀China编程(

Python 迭代器和生成器概念及场景分析

《Python迭代器和生成器概念及场景分析》yield是Python中实现惰性计算和协程的核心工具,结合send()、throw()、close()等方法,能够构建高效、灵活的数据流和控制流模型,这... 目录迭代器的介绍自定义迭代器省略的迭代器生产器的介绍yield的普通用法yield的高级用法yidle

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n