android - 使用 jfeaturelib 计算 Haralick 特征

标签 android opencv image-processing

我想使用 jfeaturelib(基本上是用于 java)计算 android 中的 haralick 功能,但我发现没有ImageIOBufferedImage 在 android 中的实现,因为这些用于计算波纹管代码中的 haralick 特征。这些仅在纯 JAVA 中可用。

public void haralickFeatures(){
    InputStream stream = HaralickDemo.class.getClassLoader().getResourceAsStream("test.jpg");
    ColorProcessor image = new ColorProcessor(ImageIO.read(stream));

    // initialize the descriptor
    Haralick descriptor = new Haralick();

    // run the descriptor and extract the features
    descriptor.run(image);

    // obtain the features
    List<double[]> features = descriptor.getFeatures();

    // print the features to system out
    for (double[] feature : features) {
        System.out.println(Arrays2.join(feature, ", ", "%.5f"));
      }
   }

有没有办法计算 android 中的 haralick 特征。任何代码示例都会有很大帮助。提前致谢。

最佳答案

正如您提到的,您不能使用 jfeaturelib 来计算haralick 功能,因为该库使用某些类,这些类仅在纯 java 而不是 android 中实现。 您可以使用我从 jfeaturelib 中获取的代码,并对其进行修改以适合 android。

  • 首先,您必须在您的 android 项目中创建一个 java 类,并将其命名为您想要的名称(在我的例子中,我将其命名为 GLCM)

    public class GLCM {
             static int totalPixels=0;
             /**
              * The number of gray values for the textures
              */
             private final int NUM_GRAY_VALUES = 32;
             /**
              * p_(x+y) statistics
              */
             private final double[] p_x_plus_y = new double[2 * NUM_GRAY_VALUES - 1];
             /**
              * p_(x-y) statistics
              */
             private final double[] p_x_minus_y = new double[NUM_GRAY_VALUES];
             /**
              * row mean value
              */
    private double mu_x = 0;
    /**
     * column mean value
     */
    private double mu_y = 0;
    /**
     * row variance
     */
    private double var_x = 0;
    /**
     * column variance
     */
    private double var_y = 0;
    /**
     * HXY1 statistics
     */
    private double hx = 0;
    /**
     * HXY2 statistics
     */
    private double hy = 0;
    /**
     * HXY1 statistics
     */
    private double hxy1 = 0;
    /**
     * HXY2 statistics
     */
    private double hxy2 = 0;
    /**
     * p_x statistics
     */
    private final double[] p_x = new double[NUM_GRAY_VALUES];
    /**
     * p_y statistics
     */
    private final double[] p_y = new double[NUM_GRAY_VALUES];
    // -
    public List<double[]> data;
    public int haralickDist;
    double[] features = null;
    static byte[] imageArray;
    public void addData(double[] data) {
    
        this.data.add(data);
    }
    public List<double[]> getFeatures() {
        return data;
    }
    public void process(Bitmap b) {
    
        features = new double[14];
    
        Coocurrence coocurrence = new Coocurrence(b, NUM_GRAY_VALUES, this.haralickDist);
        coocurrence.calculate();
        double[][] cooccurrenceMatrix = coocurrence.getCooccurrenceMatrix();
        double meanGrayValue = coocurrence.getMeanGrayValue();
    
    
        normalize(cooccurrenceMatrix, coocurrence.getCooccurenceSums());
    
        calculateStatistics(cooccurrenceMatrix);
        double[][] p = cooccurrenceMatrix;
        double[][] Q = new double[NUM_GRAY_VALUES][NUM_GRAY_VALUES];
        for (int i = 0; i < NUM_GRAY_VALUES; i++) {
            double sum_j_p_x_minus_y = 0;
            for (int j = 0; j < NUM_GRAY_VALUES; j++) {
                double p_ij = p[i][j];
    
                sum_j_p_x_minus_y += j * p_x_minus_y[j];
    
                features[0] += p_ij * p_ij;
                features[2] += i * j * p_ij - mu_x * mu_y;
                features[3] += (i - meanGrayValue) * (i - meanGrayValue) * p_ij;
                features[4] += p_ij / (1 + (i - j) * (i - j));
                features[8] += p_ij * log(p_ij);
    
                // feature 13
                if (p_ij != 0 && p_x[i] != 0) { // would result in 0
                    for (int k = 0; k < NUM_GRAY_VALUES; k++) {
                        if (p_y[k] != 0 && p[j][k] != 0) { // would result in NaN
                            Q[i][j] += (p_ij * p[j][k]) / (p_x[i] * p_y[k]);
                        }
                    }
                }
            }
    
            features[1] += i * i * p_x_minus_y[i];
            features[9] += (i - sum_j_p_x_minus_y) * (i - sum_j_p_x_minus_y) * p_x_minus_y[i];
            features[10] += p_x_minus_y[i] * log(p_x_minus_y[i]);
        }
    
        // feature 13: Max Correlation Coefficient
        double[] realEigenvaluesOfQ = new Matrix(Q).eig().getRealEigenvalues();
        Arrays2.abs(realEigenvaluesOfQ);
        Arrays.sort(realEigenvaluesOfQ);
        features[13] = Math.sqrt(realEigenvaluesOfQ[realEigenvaluesOfQ.length - 2]);
    
        features[2] /= Math.sqrt(var_x * var_y);
        features[8] *= -1;
        features[10] *= -1;
        double maxhxhy = Math.max(hx, hy);
        if (Math.signum(maxhxhy) == 0) {
            features[11] = 0;
        } else {
            features[11] = (features[8] - hxy1) / maxhxhy;
        }
        features[12] = Math.sqrt(1 - Math.exp(-2 * (hxy2 - features[8])));
    
        for (int i = 0; i < 2 * NUM_GRAY_VALUES - 1; i++) {
            features[5] += i * p_x_plus_y[i];
            features[7] += p_x_plus_y[i] * log(p_x_plus_y[i]);
    
            double sum_j_p_x_plus_y = 0;
            for (int j = 0; j < 2 * NUM_GRAY_VALUES - 1; j++) {
                sum_j_p_x_plus_y += j * p_x_plus_y[j];
            }
            features[6] += (i - sum_j_p_x_plus_y) * (i - sum_j_p_x_plus_y) * p_x_plus_y[i];
        }
    
        features[7] *= -1;
    }
    
    /**
     * Calculates the statistical properties.
     */
    private void calculateStatistics(double[][] cooccurrenceMatrix) {
        // p_x, p_y, p_x+y, p_x-y
        for (int i = 0; i < NUM_GRAY_VALUES; i++) {
            for (int j = 0; j < NUM_GRAY_VALUES; j++) {
                double p_ij = cooccurrenceMatrix[i][j];
    
                p_x[i] += p_ij;
                p_y[j] += p_ij;
    
                p_x_plus_y[i + j] += p_ij;
                p_x_minus_y[Math.abs(i - j)] += p_ij;
            }
        }
    
        // mean and variance values
        double[] meanVar;
        meanVar = meanVar(p_x);
        mu_x = meanVar[0];
        var_x = meanVar[1];
        meanVar = meanVar(p_y);
        mu_y = meanVar[0];
        var_y = meanVar[1];
    
        for (int i = 0; i < NUM_GRAY_VALUES; i++) {
            // hx and hy
            hx += p_x[i] * log(p_x[i]);
            hy += p_y[i] * log(p_y[i]);
    
            // hxy1 and hxy2
            for (int j = 0; j < NUM_GRAY_VALUES; j++) {
                double p_ij = cooccurrenceMatrix[i][j];
                hxy1 += p_ij * log(p_x[i] * p_y[j]);
                hxy2 += p_x[i] * p_y[j] * log(p_x[i] * p_y[j]);
            }
        }
        hx *= -1;
        hy *= -1;
        hxy1 *= -1;
        hxy2 *= -1;
    }
    
    /**
     * Compute mean and variance of the given array
     *
     * @param a inut values
     * @return array{mean, variance}
     */
    private double[] meanVar(double[] a) {
        // VAR(X) = E(X^2) - E(X)^2
        // two-pass is numerically stable.
        double ex = 0;
        for (int i = 0; i < NUM_GRAY_VALUES; i++) {
            ex += a[i];
        }
        ex /= a.length;
        double var = 0;
        for (int i = 0; i < NUM_GRAY_VALUES; i++) {
            var += (a[i] - ex) * (a[i] - ex);
        }
        var /= (a.length - 1);
    
        return new double[]{ex, var};
    }
    
    /**
     * Returns the bound logarithm of the specified value.
     *
     * If Math.log would be Double.NEGATIVE_INFINITY, 0 is returned
     *
     * @param value the value for which the logarithm should be returned
     * @return the logarithm of the specified value
     */
    private double log(double value) {
        double log = Math.log(value);
        if (log == Double.NEGATIVE_INFINITY) {
            log = 0;
        }
        return log;
    }
    
    /**
     * Normalizes the array by the given sum. by dividing each 2nd dimension
     * array componentwise by the sum.
     *
     * @param A
     * @param sum
     */
    private void normalize(double[][] A, double sum) {
        for (double[] A1 : A) {
            Arrays2.div(A1, sum);
        }
    }
    
    //<editor-fold defaultstate="collapsed" desc="getter/Setter">
    /**
     * Getter for haralick distributions
     *
     * @return haralick distributions
     */
    public int getHaralickDist() {
        return haralickDist;
    }
    
    /**
     * Setter for haralick distributions
     *
     * @param haralickDist int for haralick distributions (must be >= 1)
     */
    public void setHaralickDist(int haralickDist) {
        if (haralickDist <= 0) {
            throw new IllegalArgumentException("the distance for haralick must be >= 1 but was " + haralickDist);
        }
        this.haralickDist = haralickDist;
    }
    //</editor-fold>
    
    static class Coocurrence {
    
        /**
         * The number of gray values for the textures
         */
        private final int NUM_GRAY_VALUES;
        /**
         * The number of gray levels in an image
         */
        int GRAY_RANGES = 256;
        /**
         * The scale for the gray values for conversion rgb to gray values.
         */
        double GRAY_SCALE;
        /**
         * gray histogram of the image.
         */
        double[] grayHistogram;
        /**
         * Quantized gray values of each pixel of the image.
         *
         * Use int instead of byte as there is no unsigned byte in Java.
         * Otherwise you'll have a hard time using white = 255. Alternative:
         * replace with ImageJ ByteProcessor.
         */
        private final int[] grayValue;
        /**
         * mean gray value
         */
        private double meanGrayValue = 0;
        /**
         * The cooccurrence matrix
         */
        private final double[][] cooccurrenceMatrices;
        /**
         * The value for one increment in the gray/color histograms.
         */
        private final int HARALICK_DIST;
        private final Bitmap image;
    
        public Coocurrence(Bitmap b, int numGrayValues, int haralickDist) {
            this.NUM_GRAY_VALUES = numGrayValues;
            this.HARALICK_DIST = haralickDist;
            this.cooccurrenceMatrices = new double[NUM_GRAY_VALUES][NUM_GRAY_VALUES];
            this.image = b;
            totalPixels=b.getHeight()*b.getWidth();
            this.grayValue = new int[totalPixels];
        }
    
        void calculate() {
            this.GRAY_SCALE = (double) GRAY_RANGES / (double) NUM_GRAY_VALUES;
            this.grayHistogram = new double[GRAY_RANGES];
    
            calculateGreyValues();
    
            final int imageWidth = image.getWidth();
            final int imageHeight = image.getHeight();
            final int d = HARALICK_DIST;
            final int yOffset = d * imageWidth;
            int i, j, pos;
    
            // image is not empty per default
            for (int y = 0; y < imageHeight; y++) {
                for (int x = 0; x < imageWidth; x++) {
                    pos = imageWidth * y + x;
    
                    // horizontal neighbor: 0 degrees
                    i = x - d;
                    if (i >= 0) {
                        increment(grayValue[pos], grayValue[pos - d]);
                    }
    
                    // vertical neighbor: 90 degree
                    j = y - d;
                    if (j >= 0) {
                        increment(grayValue[pos], grayValue[pos - yOffset]);
                    }
    
                    // 45 degree diagonal neigbor
                    i = x + d;
                    j = y - d;
                    if (i < imageWidth && j >= 0) {
                        increment(grayValue[pos], grayValue[pos + d - yOffset]);
                    }
    
                    // 135 vertical neighbor
                    i = x - d;
                    j = y - d;
                    if (i >= 0 && j >= 0) {
                        increment(grayValue[pos], grayValue[pos - d - yOffset]);
                    }
                }
            }
        }
    
        private void calculateGreyValues() {
            final int size = grayValue.length;
            double graySum = 0;
            for (int pos = 0; pos < size; pos++) {
                int gray = imageArray[pos]&0xff;
                graySum += gray;
                grayValue[pos] = (int) (gray / GRAY_SCALE);  // quantized for texture analysis
                assert grayValue[pos] >= 0 : grayValue[pos] + " > 0 violated";
                grayHistogram[gray]++;
            }
            Arrays2.div(grayHistogram, size);
            meanGrayValue = Math.floor(graySum / size / GRAY_SCALE)*GRAY_SCALE;
        }
    
        /**
         * Incremets the coocurrence matrix at the specified positions (g1,g2)
         * and (g2,g1) if g1 and g2 are in range.
         *
         * @param g1 the gray value of the first pixel
         * @param g2 the gray value of the second pixel
         */
        private void increment(int g1, int g2) {
            cooccurrenceMatrices[g1][g2]++;
            cooccurrenceMatrices[g2][g1]++;
        }
    
        public double getMeanGrayValue() {
            return this.meanGrayValue;
        }
    
        public double[][] getCooccurrenceMatrix() {
            return this.cooccurrenceMatrices;
        }
    
        public double getCooccurenceSums() {
            // divide by R=8 neighbours
            // see p.613, §2 of Haralick paper
            return totalPixels * 8;
        }
      }
    }
    
  • 现在在您的主要 Activity 或您想要的 Activity 中创建该 GLCM 类的对象

     GLCM glcm=new GLCM();
    
  • 下一步是在您的主要 Activity 或您想要的 Activity 中复制过去的此功能。此函数提取特征,因为您必须将图像作为位图传递,并且此函数将在 float 组中返回 14 haralick 特征。这是那个函数

    public void haralickFeatures(Bitmap b) throws IOException {
    glcm.haralickDist=1;
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    b.compress(Bitmap.CompressFormat.PNG, 90, stream); // what 90 does ??
    GLCM.imageArray=new byte[]{};
    GLCM.imageArray = stream.toByteArray();
    glcm.process(b);
    glcm.data = new ArrayList<>(1);
    glcm.addData(glcm.features);
    List<double[]> featuresHar=glcm.getFeatures();
    
    for (double[] feature : featuresHar) {
        featureString=Arrays2.join(feature, ",", "%.5f");
    }
    String[] featureStr=featureString.split(Pattern.quote(","));
    float[] featureFlot = new float[featureStr.length];
    for (int i=0;i<featureStr.length;i++){
        featureFlot[i]=Float.parseFloat(featureStr[i]);
       }
    //featureFlot is array that contain all 14 haralick features
    
     }
    

关于android - 使用 jfeaturelib 计算 Haralick 特征,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50659080/

相关文章:

android - 获取安卓:padding attribute programmatically

ios - Objective-C - 图像处理 - 修复 Blob 画笔

visual-c++ - OpenCV MatchTemplate 仅限于 roi

c++ - 在 vector<Point> 中存储非零元素的坐标时 findnonzero() 出错

c++ - opencv加载图像的两种方式有什么不同?

python - 重新调整视频帧之间的时间差

java - 启动 Intent "silently"

java - 我想从图库中选择多个图像,但是选择图像后,当我单击“打开”时崩溃

opencv - 您能否改进此解决方案以将 OpenCV 2.4+ 连接到 Zxing 1D 条形码阅读器

android - 将快速滚动添加到 AlertDialog.Builder 滚动列表