使用PIL模块加载图像遇KeyboardInterrupt错误,求技术支持
Hey there, let's figure out why you're hitting that KeyboardInterrupt in the loadImage function when running your test code—especially since it works fine when you call loadImage alone!
Let's break down the possible causes and fixes:
1. First, check the @exit_after(4) decorator
That KeyboardInterrupt is almost certainly being triggered by the timeout decorator you're using. Here's why:
- When you call
loadImagealone, it runs fast enough to finish well under 4 seconds. But when wrapped intestContrastSharpeningwith the decorator, the combined setup (even before yourcontrastSharpenruns) might be pushing right up against that 4-second limit, and theastype(float)line is where the timer happens to cut off.
Quick test to confirm:
Remove the decorator temporarily and run the test function:
# Remove @exit_after(4) for this test def testContrastSharpening(): # load an image i0 = loadImage('Data/bokehCircular.jpg', 100) # run student code s0 = contrastSharpen(i0, 3, 0.5) # collect test data rTest = s0[:, int(i0.shape[1]/2), 0] gTest = s0[:, int(i0.shape[1]/4), 1] bTest = s0[int(i0.shape[0]/5), :, 2] # load and compare to reference result l0 = load('Data/t0.npz') return allclose(rTest, l0['r']) and allclose(gTest, l0['g']) and allclose(bTest, l0['b'])
If this runs without the KeyboardInterrupt, the decorator's tight 4-second timeout is the culprit.
Fixes for the decorator issue:
- Extend the timeout: Try
@exit_after(10)instead of 4 seconds—this gives the function enough time to complete all steps including image loading and processing. - Check the decorator's implementation: If
exit_afteruses Python'ssignalmodule, it might behave unpredictably with numpy operations (likeastype(float)) since numpy runs some code in C that doesn't always handle signals gracefully. If you're using a custom decorator, consider switching to a thread-based timeout implementation instead.
2. Optimize the loadImage function for speed
Even if the decorator is the trigger, speeding up loadImage will help avoid hitting timeouts in the first place. Your current code has a slow line that's adding unnecessary overhead:
Slow line:
image = image / max(image)
The built-in Python max() function iterates over every element of your 3D image array manually, which is slow for large images. Replace it with numpy's vectorized max() method:
Optimized line:
image = image / image.max()
This will drastically speed up the normalization step, cutting down the total runtime of loadImage.
3. Diagnose exactly where time is being spent
If you want to pinpoint which part of loadImage is taking the most time, add simple timing checks to the function:
import time import numpy as np from PIL import Image def loadImage(path, scale): start = time.time() image = Image.open(path, mode = 'r') print(f"Opening image took: {time.time() - start:.4f} seconds") start = time.time() image = image.resize((int(image.width * scale / 100), int(image.height * scale / 100)), resample=Image.LANCZOS) print(f"Resizing took: {time.time() - start:.4f} seconds") start = time.time() image = np.array(image.getdata()).reshape(image.size[1], image.size[0], 3) print(f"Reshaping took: {time.time() - start:.4f} seconds") start = time.time() image = image.astype(float) print(f"Converting to float took: {time.time() - start:.4f} seconds") start = time.time() image = image / image.max() print(f"Normalizing took: {time.time() - start:.4f} seconds") return image
Run your test code (with the decorator) and check the print outputs—this will show you exactly which step is pushing the runtime close to the 4-second limit.
Final Notes
If you're running this in a Jupyter notebook, keep in mind that signal-based timeout decorators can behave weirdly in notebook environments. Thread-based timeouts are more reliable there if you need to keep the timeout restriction.
内容的提问来源于stack exchange,提问作者Ahsan Niaz

