_ OpenCV is 1.4 Times faster than PIL _
Image is simply a matrix of pixels and each pixel is a single, square-shaped point of colored light. This can be explained quickly with a grayscaled image. grayscaled image is the image where each pixel represents different shades of a gray color.
I mostly use OpenCV to complete my tasks as I find it 1.4 times quicker than PIL.
Let’s see, how the image can be processed using both — OpenCV and PIL.
## Installation & importing
# cv2
pip install opencv-python
import cv2
---
# PIL
pip install Pillow
from PIL import Image, ImageEnhance
## Read the image
# Read/open a colorful image
pil_img = Image.open("your_image.jpg") # RGB
cv2_img = cv2.imread("your_image.jpg") # BGR
# Read/open a grayscale image:
pil_img = Image.open("your_image.jpg").convert("L")
cv2_img = cv2.imread("your_image.jpg", cv2.IMREAD_GRAYSCALE)
## Write/save an image
pil_img.save("new_image.jpg")
cv2.imwrite("new_image.jpg", cv2_img)
# Write/save a JPEG image with specific quality:
pil_img.save("new_image.jpg", quality=95)
cv2.imwrite("new_image.jpg", cv2_img, [int(cv2.IMWRITE_JPEG_QUALITY), 95])
## Conversion between both
# Pillow image to OpenCV image:
cv2_img = np.array(pil_img)
cv2_img = cv2.cvtColor(cv2_img, cv2.COLOR_RGB2BGR)
# OpenCV image to Pillow image
cv2_img = cv2.cvtColor(cv2_img, cv2.COLOR_BGR2RGB)
pil_img = Image.fromarray(cv2_img)
Note: OpenCV images are in BGR color format, while Pillow images are in RGB color format. So we have to manually convert the color format from one to another.
## Shape / Size
# cv2
if cv2_img.ndim == 2:
height, width = cv2_img.shape
depth = 1
else:
height, width, depth = cv2_img.shape
# PIL
width, height = pil_img.size
cv2_img = np.array(pil_img)
if cv2_img.ndim == 2:
depth = 1
else:
depth = cv2_img.shape[-1]
Note: It is hard to get the depth/channels directly from a Pillow image object, the easier way to do this would be to first convert it to an OpenCV image (ndarray) and then get the shape.
## Resize
# Resize without preserving the aspect ratio:
pil_img_resized = pil_img.resize((NEW_WIDTH, NEW_HEIGHT))
cv2_img_resized = cv2.resize(cv2_img, (NEW_WIDTH, NEW_HEIGHT))
Resize and preserve the aspect ratio:
# OpenCV:
scale_ratio = 0.6
width = int(img.shape[1] * scale_ratio)
height = int(img.shape[0] * scale_ratio)
dim = (width, height)
cv2_img_resized = cv2.resize(cv2_img, dim, interpolation=cv2.INTER_AREA)
# Pillow:
# scale ratio = min(max_width/width, max_height/height)
max_width = 256
max_height = 256
pil_img.thumbnail((max_width, max_height), Image.ANTIALIAS)
## RGBA to RGB
# Convert transparent pixels to white pixels (by pasting the RGBA image on a white RGB image).
#cv2
def cv2_RGBA2RGB(img):
b, g, r, a = cv2.split(img)
alpha = a / 255
r = (255 * (1 - alpha) + r * alpha).astype(np.uint8)
g = (255 * (1 - alpha) + g * alpha).astype(np.uint8)
b = (255 * (1 - alpha) + b * alpha).astype(np.uint8)
new_img = cv2.merge((b, g, r))
return new_img
# PIL
def pil_RGBA2RGB(img):
img.load() # for png.split()
bg = Image.new("RGB", img.size, (255, 255, 255))
bg.paste(img, mask=img.split()[3]) # 3 is the alpha channel
return bg
## Read an image from a URL.
# without request headers
url = ''
# cv2
import cv2
import numpy as np
import requests
cv2_img = cv2.imdecode(np.asarray(requests.get(url, stream=True).content, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
# PIL
importt io;
import requests
pil_img = Image.open(io.BytesIO(requests.get(url, stream=True).content))
## Base64 Conversions
# Read image file as base64:
import base64
with open("your_image.jpg", "rb") as f:
base64_str = base64.b64encode(f.read())
# Conversion between Pillow & base64:
import base64
from io import BytesIO
from PIL import Image
def pil_to_base64(pil_img):
img_buffer = BytesIO()
pil_img.save(img_buffer, format='JPEG')
byte_data = img_buffer.getvalue()
base64_str = base64.b64encode(byte_data)
return base64_str
def base64_to_pil(base64_str):
pil_img = base64.b64decode(base64_str)
pil_img = BytesIO(pil_img)
pil_img = Image.open(pil_img)
return pil_img
# Conversion between OpenCV & base64:
import base64
import numpy as np
import cv2
def cv2_base64(cv2_img):
base64_str = cv2.imencode('.jpg', cv2_img)[1].tostring()
base64_str = base64.b64encode(base64_str)
return base64_str
def base64_cv2(base64_str):
imgString = base64.b64decode(base64_str)
nparr = np.fromstring(imgString, np.uint8)
cv2_img= cv2.imdecode(nparr, cv2.IMREAD_COLOR)
return cv2_img
- Pillow (PIL Fork) 9.4.0 documentation
- Image Processing — OpenCV Vs PIL – By Suraj Gurav
- The Ultimate Handbook for OpenCV & Pillow – By Steins
- https://note.nkmk.me/en/python-pillow-rotate/
- https://www.pyimagesearch.com/2021/02/03/opencv-image-translation/
- https://www.pyimagesearch.com/2017/01/02/rotate-images-correctly-with-opencv-and-python/
- https://stackoverflow.com/questions/14177744/how-does-perspective-transformation-work-in-pil
- https://www.pyimagesearch.com/2014/05/05/building-pokedex-python-opencv-perspective-warping-step-5-6/
- https://note.nkmk.me/python-opencv-warp-affine-perspective/
- https://stackoverflow.com/questions/25618756/how-to-convert-alpha-channel-of-the-image-to-white-color-using-opencv-python
- https://stackoverflow.com/questions/9166400/convert-rgba-png-to-rgb-with-pil