Open yuyu2172 opened 7 years ago
I made a simpler benchmark script to measure time to load images with crop.
from PIL import Image
import numpy as np
from chainercv.utils import write_image
import time
import cv2
def crop_pil(path):
img = Image.open(path).convert('RGB')
img = img.crop((0, 0, 224, 224))
img = np.asarray(img).transpose(2, 0, 1)
return img
def crop_numpy(path):
img = Image.open(path).convert('RGB')
img = np.asarray(img).transpose(2, 0, 1)
img = img[:, :224, :224]
return img
def crop_cv2(path):
img = cv2.imread(path, cv2.IMREAD_COLOR).transpose(2, 0, 1)
img = img[::-1, :224, :224]
return img
if __name__ == '__main__':
img = np.random.uniform(0, 255, size=(3, 4000, 4000))
path = 'a.jpg'
img = write_image(img, path)
times = []
for i in range(30):
start = time.time()
crop_cv2(path)
times.append(time.time() - start)
print('crop_cv2 mean={}'.format(np.mean(times)))
times = []
for i in range(30):
start = time.time()
crop_pil(path)
times.append(time.time() - start)
print('crop_pil mean={}'.format(np.mean(times)))
times = []
for i in range(30):
start = time.time()
crop_numpy(path)
times.append(time.time() - start)
print('crop_numpy mean={}'.format(np.mean(times)))
Results:
crop_cv2 mean=0.272049093246
crop_pil mean=0.301412550608
crop_numpy mean=0.324815416336
If using cv2.imread
is fastest, we can simply use cv2.imread
in read_image
. This doesn't require any changes of APIs. If you want to use PIL
, we have to change APIs.
Yes. That is my conclusion too.
I am guessing that most of the time is spent decoding jpg
image, and it seems that cv2
has a better decoder.
I am guessing that most of the time is spent decoding jpg image, and it seems that cv2 has a better decoder.
I guess this is depends on the configuration of OpenCV. I will try your benchmark in my environment.
In my environment, cv2 was fastest, too.
crop_cv2 mean=0.22242753505706786
crop_pil mean=0.34299739996592205
crop_numpy mean=0.38132399717966714
Currently, all images are assumed to be converted to
numpy.ndarray
right after loaded from the disk. However, this leads to unnecessary copy of images. For example, in the case when a crop of an image is needed, it is not necessary to load the entire image into a numpy array.By not copying the data to a numpy array right after image loading, this kind of optimization becomes possible. To verify that improvements can happen, I wrote a simple example. This example supplies a dataset to a
MultiprocessIterator
and measures the performance. The dataset crops an image by fixed size.NoPILDataset
uses the current method to load an image.PILDataset
callscrop
method from PIL.I tested the performance with train split of ImageNet. The spec of my machine is as follows.
After iterating for 500 iterations, the results are as follows. The proposed change was 1.56 times faster.
Note that this improvement is very important when training with a large batch (e.g. ImageNet). I was having a performance issue with training a model on ImageNet.