Android 等高线绘图

来源:互联网 发布:java第一阶段测试题 编辑:程序博客网 时间:2024/04/28 18:34

Android 等高线绘图(又称热力图)

注:以下数据为一个一维的图片数组
注: 绘制方法来自

https://github.com/ChristianFF/HeatMapForAndroid
https://github.com/HeartlandSoftware/AndroidHeatMap

注:可使用两种方法绘制

使用高斯核密度估计方法绘制
使用绘制点阴影的方式绘制

使用高斯核密度估计方法绘制

  • 主要流程:
    • 处理数据
    • 使用高斯核密度估计算计进行数组插值
    • 根据所得数组绘制Bitmap

一、处理数据

根据一维的图片数组,转换成点坐标和值,封装到点对象里

        //循环遍历数组        for (int i = 0; i < WIDTH; i++) {            for (int j = 0; j < HEIGHT; j++) {                n = i * HEIGHT + j;                if (data[n] > startValue) {                    tmp_sum += data[n];                }                tmp = (data[n] - startValue) / (endValue - 0);                if (tmp > filter) {                    //根据数组值所在位置和值转换为点坐标和压力值                    //clamp为一个工具方法,可根据(百分比,最小值,最大值),得出具体数值                    addData(new DataPoint((int) (clamp((float) j / 60, 0.0f, mWidth)),                            (int) (clamp((float) i / 50, 0.0f, mHeight)),                            clamp(tmp, 0.0, 100.0)));                }            }        }

二、使用高斯核密度估计算计进行数组插值

1.创建一个二维数组,大小依据要生成的bitmap大小相等,如
 double[][] intensity = new double[mWidth + mRadius * 2][mHeight + mRadius * 2];
2.将上面处理好的点数据填充到该数组里面
        for (DataPint w : mData) {            int bucketX = w.x;            int bucketY = w.y;            if (bucketX < mWidth && bucketX >= 0                    && bucketY < mHeight && bucketY >= 0)                intensity[bucketX][bucketY] += w.intensity;        }
3.使用高斯核密度估计算法处理该数组
  double[][] convolved = convolve(intensity, mKernel);  //高斯核密度估计算法  static double[][] convolve(double[][] grid, double[] kernel) {        int radius = (int) Math.floor((double) kernel.length / 2.0);        int dimOldW = grid.length;        int dimOldH = grid[0].length;        int dimW = dimOldW - 2 * radius;        int dimH = dimOldH - 2 * radius;        int lowerLimit = radius;        int upperLimitW = radius + dimW - 1;        int upperLimitH = radius + dimH - 1;        double[][] intermediate = new double[dimOldW][dimOldH];        int x, y, x2, xUpperLimit, initial;        double val;        for (x = 0; x < dimOldW; x++) {            for (y = 0; y < dimOldH; y++) {                val = grid[x][y];                if (val != 0) {                    xUpperLimit = ((upperLimitW < x + radius) ? upperLimitW : x + radius) + 1;                    initial = (lowerLimit > x - radius) ? lowerLimit : x - radius;                    for (x2 = initial; x2 < xUpperLimit; x2++) {                        intermediate[x2][y] += val * kernel[x2 - (x - radius)];                    }                }            }        }        double[][] outputGrid = new double[dimW][dimH];        int y2, yUpperLimit;        for (x = lowerLimit; x < upperLimitW + 1; x++) {            for (y = 0; y < dimOldH; y++) {                val = intermediate[x][y];                if (val != 0) {                    yUpperLimit = ((upperLimitH < y + radius) ? upperLimitH : y + radius) + 1;                    initial = (lowerLimit > y - radius) ? lowerLimit : y - radius;                    for (y2 = initial; y2 < yUpperLimit; y2++) {                        outputGrid[x - radius][y2 - radius] += val * kernel[y2 - (y - radius)];                    }                }            }        }        return outputGrid;    }

其中mKernel为核数组,由以下方法所得

    mKernel = generateKernel(mRadius, mRadius / 3.0);    static double[] generateKernel(int radius, double sd) {        double[] kernel = new double[radius * 2 + 1];        for (int i = -radius; i <= radius; i++) {            kernel[i + radius] = (Math.exp(-i * i / (2 * sd * sd)));        }        return kernel;    }

最终返回处理好的二维数组

三、根据所得数组绘制Bitmap

根据所得数组值计算图片每个像素的颜色并保存为数组

        int i, j, index, col;        double val;        int colors[] = new int[dimW * dimH];        for (i = 0; i < dimH; i++) {            for (j = 0; j < dimW; j++) {                val = grid[j][i];                index = i * dimW + j;                //根据值计算颜色,并插入对应的颜色数组中的位置                col = (int) (val * colorMapScaling);                if (val != 0) {                    if (col < colorMap.length) colors[index] = colorMap[col];                    else colors[index] = maxColor;                } else {                    colors[index] = Color.TRANSPARENT;                }            }        }

根据颜色数组,绘制Bitmap

        Bitmap tile = Bitmap.createBitmap(dimW, dimH, Bitmap.Config.ARGB_8888);        tile.setPixels(colors, 0, dimW, 0, 0, dimW, dimH);

使用绘制点阴影的方式绘制

  • 主要流程
    • 处理数据
    • 绘制阴影
    • 描绘颜色
    • 生成Bitmap

一、处理数据处理数据

与上一种绘制方法相同

二、绘制阴影

创建一张bitmap,大小与最后所得bitmap相同

backBuffer = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888);//使图片变透明backBuffer.eraseColor(Color.TRANSPARENT);

创建Canvas,并封装上得bitmap,并根据点数据进行画圆,并使之渐变透明,形成阴影

        for (WeightedLatLng p : data) {            drawAlphaCircle(p.x, p.y, p.intensity);        }private void drawAlphaCircle(float x, float y, double intensity) {        RadialGradient g = new RadialGradient(x, y, radius, Color.argb(                (int) (intensity / maxIntensity * 255), 0, 0, 0), Color.TRANSPARENT,                Shader.TileMode.CLAMP);        Paint gp = new Paint();        gp.setShader(g);        myCanvas.drawCircle(x, y, radius, gp);    }

三、绘制颜色

创建渐变颜色条数组

    private int colors[] = new int[]{0xffff0000, 0xff00ff00};    private float positions[] = new float[]{0.0f, 1.0f};            Bitmap bit = Bitmap.createBitmap(256, 1, Bitmap.Config.ARGB_4444);            Canvas canvas = new Canvas(bit);            LinearGradient grad;            grad = new LinearGradient(0, 0, 256, 1, colors, positions, Shader.TileMode.CLAMP);            Paint paint = new Paint();            paint.setStyle(Paint.Style.FILL);            paint.setShader(grad);            canvas.drawLine(0, 0, 256, 1, paint);            palette = new int[256];            bit.getPixels(palette, 0, 256, 0, 0, 256, 1);

根据阴影透明度,绘制颜色

backBuffer.getPixels(pixels, 0, width, x, y, width, height); for (int j = 0; j < height; j++) {            for (int i = 0; i < width; i++) {                int pixel = pixels[i + (j * width)];                //the pixels alpha value (0-255)                int alpha = 0xff & (pixel >> 24);                //clamp the alpha value to user specified bounds                int clampAlpha;                    if (alpha < maxOpacity) {                        if (alpha < minOpacity) {                            clampAlpha = minOpacity;                        } else {                            clampAlpha = alpha;                        }                    } else {                        clampAlpha = maxOpacity;                    }                //set the pixels colour to its corresponding colour in the palette                pixels[i + (j * width)] = ((0xff & clampAlpha) << 24) | (0xffffff & palette[alpha]);            }        }

四、生成Bitmap

backBuffer.setPixels(pixels, 0, width, x, y, width, height);

backBUffer为最终所得图片

* 源码可在上面GitHub上获取 , 或在 http://download.csdn.net/download/z896435317/9955057 下载

原创粉丝点击