LIRe图像检索:Tamura纹理特征算法源码分析 - Go语言中文社区

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


版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/DaveBobo/article/details/70333469
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-07 15:09:46
  • 阅读 ( 1301 )
  • 分类:算法

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢