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

来源:互联网 发布:iphone美图软件 编辑:程序博客网 时间:2024/05/18 21:43

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


0 0
原创粉丝点击