修改Google-Maps-iOS-Utils框架实现热力图按平均权重着色
Got it, let's tackle this! The GMUHeatmapTileLayer's default behavior sums weighted intensity values across the convolution, but to switch to an average weight per pixel, we need to track two things for each pixel: the total weighted intensity and the sum of the kernel weights that contributed to it. Then we can divide the total intensity by the kernel sum to get the average.
Here's how to modify the -tileForX:y:zoom: method's convolution logic:
Step 1: Track both total intensity and kernel contribution counts
We'll add two new arrays to keep track of the sum of kernel weights (so we can compute the average later) — one for the horizontal convolution phase, one for the vertical phase.
Modified Horizontal Convolution Code
- (UIImage *)tileForX:(NSUInteger)x y:(NSUInteger)y zoom:(NSUInteger)zoom { // ... (existing code before convolution) // Convolve data. int lowerLimit = (int)data->_radius; int upperLimit = paddedTileSize - (int)data->_radius - 1; // Convolve horizontally first. float *intermediate = calloc(paddedTileSize * paddedTileSize, sizeof(float)); // NEW: Array to track sum of kernel weights for horizontal phase float *intermediateCount = calloc(paddedTileSize * paddedTileSize, sizeof(float)); for (int y = 0; y < paddedTileSize; y++) { for (int x = 0; x < paddedTileSize; x++) { float value = intensity[y * paddedTileSize + x]; if (value != 0) { int start = MAX(lowerLimit, x - (int)data->_radius); int end = MIN(upperLimit, x + (int)data->_radius); for (int x2 = start; x2 <= end; x2++) { float kernelValue = [data->_kernel[x2 - x + data->_radius] floatValue]; float scaledKernel = value * kernelValue; // Accumulate weighted intensity intermediate[y * paddedTileSize + x2] += scaledKernel; // Accumulate kernel weight count intermediateCount[y * paddedTileSize + x2] += kernelValue; } } } } // NEW: Compute horizontal average by dividing total intensity by kernel sum for (int y = 0; y < paddedTileSize; y++) { for (int x = 0; x < paddedTileSize; x++) { int index = y * paddedTileSize + x; if (intermediateCount[index] > 0.0001) { // Avoid division by zero intermediate[index] /= intermediateCount[index]; } } } free(intensity); free(intermediateCount); // Clean up the count array // ...
Modified Vertical Convolution Code
// Convole vertically to get final intensity. float *finalIntensity = calloc(kGMUTileSize * kGMUTileSize, sizeof(float)); // NEW: Array to track sum of kernel weights for vertical phase float *finalCount = calloc(kGMUTileSize * kGMUTileSize, sizeof(float)); for (int x = lowerLimit; x <= upperLimit; x++) { for (int y = 0; y < paddedTileSize; y++) { float value = intermediate[y * paddedTileSize + x]; if (value != 0) { int start = MAX(lowerLimit, y - (int)data->_radius); int end = MIN(upperLimit, y + (int)data->_radius); for (int y2 = start; y2 <= end; y2++) { float kernelValue = [data->_kernel[y2 - y + data->_radius] floatValue]; float scaledKernel = value * kernelValue; int finalIndex = (y2 - lowerLimit) * kGMUTileSize + x - lowerLimit; // Accumulate weighted intensity finalIntensity[finalIndex] += scaledKernel; // Accumulate kernel weight count finalCount[finalIndex] += kernelValue; } } } } // NEW: Compute final average by dividing total intensity by kernel sum for (int i = 0; i < kGMUTileSize * kGMUTileSize; i++) { if (finalCount[i] > 0.0001) { // Avoid division by zero finalIntensity[i] /= finalCount[i]; } } free(intermediate); free(finalCount); // Clean up the count array // ... (existing code to render the tile from finalIntensity) }
Key Changes Explained
- Tracking Kernel Counts: We added
intermediateCountandfinalCountarrays to sum up the Gaussian kernel values applied to each pixel. This tells us how much each point's weight contributed to the pixel (via the kernel's falloff). - Calculating Averages: After each convolution phase, we divide the total weighted intensity by the sum of kernel weights for that pixel. This gives us the weighted average of the nearby points' intensities, using the Gaussian kernel as the weighting factor.
- Division by Zero Safety: We check if the count is greater than a small threshold (
0.0001) instead of just0to avoid floating-point precision issues.
This modification will make the heatmap color each pixel based on the average weight of points in its surrounding area (smoothed by the Gaussian kernel), instead of the total summed intensity.
内容的提问来源于stack exchange,提问作者IHaveAQuestion

