Android 等高線繪圖

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 下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章