{"cells":[{"metadata":{"_cell_guid":"fe6837af-968d-4153-990f-3b36765f55bc","_uuid":"c043b438a55a9e789fdd74ce6aa3df21be9490eb"},"cell_type":"markdown","source":"# Fast benchmark: Pillow vs OpenCV\n\n*Background: when we deal with images in image-based problems and deploy a deep learning solution, it is better to have a fast image reading and transforming library. Let's compare Pillow and OpenCV python libraries on image loading and some basic transformations on source images from Carvana competition.*\n\n[OpenCV](https://github.com/opencv/opencv): C++, python-wrapper\n\n[Pillow](https://github.com/python-pillow/Pillow): Python, C\n\n`\n`\n\nIntuition says that Opencv should be a little faster, let's see this by examples\n\n`\n`\n\n*This question I asked myself after reading the PyTorch [documentation on image transformation](http://pytorch.org/docs/0.2.0/_modules/torchvision/transforms.html). Most of transformations take as input a PIL image.*\n"},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"!pip uninstall -y pillow\n!CC=\"cc -mavx2\" pip install -U --force-reinstall pillow-simd\n!unzip ../input/carvana-image-masking-challenge/train.zip\n","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"8147c7e9-5d88-46d6-a6b7-cf85d8f8fd05","_uuid":"302855e43533de243af523aaa6e9dfd1a6461319","trusted":true},"cell_type":"code","source":"import PIL\nimport cv2","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"b9c0daa3-fb76-4c38-8f44-b64197a3c4fc","_uuid":"14d4e6e2ed7f1090385e26cfd04c8796fafc74fe"},"cell_type":"markdown","source":"At first, let's get packages versions, specs and some info on the machine"},{"metadata":{"_cell_guid":"c2363288-f996-4445-877d-7e5357e2971c","_uuid":"f8e881a0591118816970c6fe633eaab55ab9fd7f","trusted":true},"cell_type":"code","source":"print(cv2.__version__, cv2.__spec__)\nprint(cv2.getBuildInformation())","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"95e124b5-2c97-4d23-b0a5-0265b730c1aa","_uuid":"550681ecb1c3236816a95fd40d58bd7deaddc4fc","trusted":true},"cell_type":"code","source":"PIL.__version__, PIL.__spec__","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"9dcd6558-e1cc-45fd-aad8-c7654bdb017b","_uuid":"9772ac75e3fe345885e8160f2ec616f24768cd38","trusted":true},"cell_type":"code","source":"!cat /proc/cpuinfo | egrep \"model name\"","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"eba30b38-58a6-4599-955e-7ffdde7d5048","_uuid":"650350164b5863b1a2f3adab27f9cb19fef33341"},"cell_type":"markdown","source":"Data storage info: `ROTA 1` means rotational device"},{"metadata":{"_cell_guid":"aa073f57-b5de-4423-b13c-4424951d60b9","_uuid":"0adda47f72406997368fe72790eb49007b84cf79","trusted":true},"cell_type":"code","source":"!lsblk -o name,rota,type,mountpoint","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"ed34bcb0-1d98-4a38-a991-cf0dbe97621a","_uuid":"76face6ed26c085584c53445e2a93d12fc4f2ed6"},"cell_type":"markdown","source":"Now let's setup the input data"},{"metadata":{"_cell_guid":"0674883d-3e89-4e72-b49f-202c61091cfe","_uuid":"d0c55dda3dd0e6785403ea11ee8c3fa6e0db6ebd","trusted":true},"cell_type":"code","source":"import os\nthis_path = os.path.dirname('.')\n\n# INPUT_PATH = os.path.abspath(os.path.join(this_path, '..', 'input'))\nTRAIN_DATA = \"train/\" #os.path.join(INPUT_PATH, \"train\")\nfrom glob import glob\nfilenames = glob(os.path.join(TRAIN_DATA, \"*.jpg\"))\nlen(filenames)","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"3a552595-4091-451e-8c65-ecf3d1e72677","_uuid":"7c0d218540603c08239f247e38c7e3a3509bb3de","trusted":true},"cell_type":"code","source":"import matplotlib.pylab as plt\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"d0236dcd-7807-49d7-a929-27ef1ff2e73f","_uuid":"b7c8248d5dcc2f4aec9d4a5823021a68b15b955e"},"cell_type":"markdown","source":"## 1 stage: 100 images, load image + blur + flip"},{"metadata":{"_cell_guid":"0c26f22f-e895-4bd5-86c1-a1b85583ac82","_uuid":"1f483b02a9800b54a2def10e1ce30cce28219e15","trusted":true},"cell_type":"code","source":"import numpy as np\nfrom PIL import Image, ImageOps\nsz = 224,224\ndef stage_1_PIL(filename):\n    img_pil = Image.open(filename)\n#     img_pil = ImageOps.box_blur(img_pil, radius=1)\n    img_pil = img_pil.transpose(Image.FLIP_LEFT_RIGHT)\n    return np.asarray(img_pil)\n\ndef stage_1_cv2(filename):\n    img = cv2.imread(filename)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n#     img = cv2.blur(img, ksize=(3, 3))\n    img = cv2.flip(img, flipCode=1)\n    return img","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"5343a843-8186-4400-a323-3b2298153cc6","_uuid":"b398a9c0d768d7b908a490585fc90f1900749a13"},"cell_type":"markdown","source":"Let's compare briefly results of transformations on the first image. Results are not perfectly the same, but it is not important for the benchmark  "},{"metadata":{"_cell_guid":"df805da8-62e2-4cd9-a13f-33c5c93e0917","_uuid":"47ddadc3a89c6f7c9a84862c0e95fc92ada2b76d","trusted":true},"cell_type":"code","source":"f = filenames[0]\nr1 = stage_1_PIL(f) \nr2 = stage_1_cv2(f)\n\nplt.figure(figsize=(16, 16))\nplt.subplot(131)\nplt.imshow(r1)\nplt.subplot(132)\nplt.imshow(r2)\nplt.subplot(133)\nplt.imshow(np.abs(r1 - r2))","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"e1895aa0-db81-4acb-8ed2-2b218e3f1c5d","_uuid":"69928316afdeac5b21359ffe776d4390ea29c249","trusted":true},"cell_type":"code","source":"%timeit -n5 -r3 [stage_1_PIL(f) for f in filenames[:100]]","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"f09d8ba9-3f6d-40cc-a1c3-b3da8b17db82","_uuid":"ee161fb1bd1602577be77acc29c0d3de5eaaa078","trusted":true},"cell_type":"code","source":"%timeit -n5 -r3 [stage_1_cv2(f) for f in filenames[:100]]","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"7a9366e9-4bfb-4a28-b69e-42ede1ad6355","_uuid":"41150c7b15d793e7f00ce66e2e4f3b8e5f62b233"},"cell_type":"markdown","source":"## 2 stage: 500 images, load image + resize + 2 flips"},{"metadata":{"_cell_guid":"d2859361-fec6-4131-a549-32d154219ea8","_uuid":"4a446a5aceee4c8c3d8701226075a798edc103c8","trusted":true},"cell_type":"code","source":"import numpy as np\nfrom PIL import Image, ImageOps\n\n\ndef stage_2_PIL(filename):\n    img_pil = Image.open(filename)\n    img_pil = img_pil.resize((512, 512), Image.BICUBIC)\n    img_pil = img_pil.transpose(Image.FLIP_LEFT_RIGHT)\n    img_pil = img_pil.transpose(Image.FLIP_TOP_BOTTOM)\n    return np.asarray(img_pil)\n\ndef stage_2_cv2(filename):\n    img = cv2.imread(filename)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)    \n    img = cv2.resize(img, dsize=(512, 512), interpolation=cv2.INTER_CUBIC)\n    img = cv2.flip(img, flipCode=1)\n    img = cv2.flip(img, flipCode=0)\n    return img","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"746878fa-298e-4a35-a3bd-19ccc0cd5c6a","_uuid":"0947ead8055720f2468fda1a249f5a4ad322265e"},"cell_type":"markdown","source":"Again let's compare briefly results of transformations on the first image:"},{"metadata":{"_cell_guid":"a2b3d205-3a41-4870-abd7-fa853dd2b12e","_uuid":"c533a191e91ba66d4d64c28fccdb1a0b6e3264ba","trusted":true},"cell_type":"code","source":"f = filenames[0]\nr1 = stage_2_PIL(f) \nr2 = stage_2_cv2(f)\n\nplt.figure(figsize=(16, 16))\nplt.subplot(131)\nplt.imshow(r1)\nplt.subplot(132)\nplt.imshow(r2)\nplt.subplot(133)\nplt.imshow(np.abs(r1 - r2))","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"bec7dfa2-0625-4a54-811d-75945c5ef2ca","_uuid":"b2a1628e5277819323f459ea08f01d6b45fc19de","trusted":true},"cell_type":"code","source":"%timeit -n5 -r3 [stage_2_PIL(f) for f in filenames[:200]]","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"c569bf0a-87d1-4809-bf89-29f5c4237287","_uuid":"5625c60e74365aac58cace6b9394f6342590f84d","trusted":true},"cell_type":"code","source":"%timeit -n5 -r3 [stage_2_cv2(f) for f in filenames[:200]]","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"6cca2d73-8be7-432c-95a3-fea9bd8d84dc","_uuid":"5edded39d8f9514e1f7aa9fd234ba2d320fd96da","collapsed":true},"cell_type":"markdown","source":""},{"metadata":{"_cell_guid":"92ab8207-e2a0-462f-94f0-9a0e20dacddd","_uuid":"a664fbc231befdb9864bfc5b2bc6c5953e8276bd"},"cell_type":"markdown","source":""}],"metadata":{"language_info":{"codemirror_mode":{"name":"ipython","version":3},"mimetype":"text/x-python","name":"python","pygments_lexer":"ipython3","file_extension":".py","nbconvert_exporter":"python","version":"3.6.3"},"kernelspec":{"language":"python","name":"python3","display_name":"Python 3"}},"nbformat":4,"nbformat_minor":4}