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