基于Pylab的森林火势演化图像程序运行缓慢及崩溃问题排查求助
Hey there! Let's break down why your forest fire simulation is running sluggishly and crashing, plus fix it up to run smoothly. The core issues boil down to inefficient loops, non-vectorized operations, and suboptimal visualization updates—here's how to tackle each:
1. Python Nested Loops Are Killing Performance
Your code relies heavily on nested for loops (e.g., Initialise, Affiche, Evolution, Voisins) to iterate over every pixel individually. Python is slow at looping, and when you stack multiple loops (like checking 8 layers of neighbors in Evolution), the time complexity skyrockets. This is the biggest culprit for slowdowns.
Fix: Use NumPy Vectorization
NumPy operations are implemented in C, so they’re way faster than Python loops. Replace your per-pixel loops with vectorized logic:
Example: Optimized Initialise
import numpy as np def Initialise(n,p,t,c,r): # Generate tree matrix in one go with numpy random R = np.random.choice([0, 1], size=(n,p), p=[1-t, t]) # Protected trees area (70-100, 60-100) protected_area = R[70:100, 60:100] mask = np.random.random(protected_area.shape) <= c protected_area[mask & (protected_area == 1)] = 10 # Clear area with random trees (10-40,10-40) clear_area = R[10:40,10:40] clear_area[:] = 0 tree_mask = np.random.random(clear_area.shape) <= r clear_area[tree_mask] = 1 # Geologic site (20-40,80-90) R[20:40,80:90] = 4 return R
Example: Optimized Affiche
def Affiche(M): n,p = M.shape img = np.zeros((n,p,3), dtype=np.uint8) # Vectorized condition assignments img[M == 0] = sol img[M == 1] = arbre img[M == 10] = arbreprotege img[M == 4] = ressourceprotegee return img
2. Inefficient Neighbor Checking (Voisins Function)
Your Voisins function uses multiple loops to check each neighbor layer one by one. This is redundant and slow, especially when called for every pixel in Evolution.
Fix: Use Sliding Window/Convolution for Batch Neighbor Checks
Instead of checking each pixel individually, use NumPy slicing or scipy.ndimage to detect burning areas in bulk:
from scipy.ndimage import binary_dilation def get_burning_mask(M): # Create a boolean mask of burning pixels (rouge, orange, jaune) is_burning = (M == rouge).all(axis=2) | (M == orange).all(axis=2) | (M == jaune).all(axis=2) return is_burning def Evolution(M): R = M.copy() n,p = M.shape[:2] # Get burning mask and expand it for each neighbor distance (1-8) burning_mask = get_burning_mask(M) for k in range(1,9): # Expand burning area by k pixels expanded = binary_dilation(burning_mask, structure=np.ones((2*k+1, 2*k+1))) # Find trees that are in expanded area and haven't caught fire yet trees_to_burn = (expanded) & ((R == arbre).all(axis=2) | (R == arbreprotege).all(axis=2)) # Apply ignition probability (decreasing with k) proba = 0.6 - (k-1)*0.05 ignition_mask = np.random.random(trees_to_burn.shape) < proba R[trees_to_burn & ignition_mask] = rouge # Update burning stages (rouge → orange → jaune → noir) R[(R == rouge).all(axis=2)] = orange R[(R == orange).all(axis=2)] = jaune R[(R == jaune).all(axis=2)] = noir return R
3. Slow Fire Status Check (Feu Function)
Your Feu function loops through every pixel to check for burning trees. Replace it with a vectorized check:
def Feu(M): is_burning = (M == rouge).all(axis=2) | (M == orange).all(axis=2) | (M == jaune).all(axis=2) return np.any(is_burning)
4. Visualization Updates Causing Crashes
Your ForetBrule function calls pl.show() and image.changed() (which isn’t a valid Matplotlib method) repeatedly. This overloads the GUI thread, leading to crashes.
Fix: Streamline Visualization
def ForetBrule(M): plt.ion() fig, ax = plt.subplots() image = ax.imshow(M) plt.show(block=False) while plt.fignum_exists(fig.number) and Feu(M): M = Evolution(M) image.set_data(M) fig.canvas.draw_idle() # Efficiently update the plot plt.pause(0.1) plt.ioff()
5. Miscellaneous Fixes
- Remove the unused
global Emline inEvolution—it’s unnecessary and could cause unexpected behavior. - Use
numpy.randominstead of the standardrandommodule for faster, vectorized random number generation. - Ensure all color tuples are compatible with NumPy array operations (they are in your code, but double-check for type mismatches).
After applying these changes, your simulation should run orders of magnitude faster without crashing—vectorized operations eliminate most of the Python loop overhead, and the visualization updates are optimized to avoid GUI overload.
内容的提问来源于stack exchange,提问作者Bastien

