Muneeb Ahmad Khurram
Muneeb Ahmad Khurram

Reputation: 670

Computing Colorfulness of an Image in Python (Fast)

I am asking this question because I have a suggestion about https://pyimagesearch.com/2017/06/05/computing-image-colorfulness-with-opencv-and-python/

Here, they are citing Hasler and Süsstrunk’s 2003 paper, Measuring colorfulness in natural images. They are using NumPy to perform calculations but I'm a bit concerned about the speed at which one can compute the colorfulness of an image.

Original Method

from imutils import build_montages
from imutils import paths
import numpy as np
import argparse
import imutils
import cv2

def image_colorfulness(image):
    # split the image into its respective RGB components
    (B, G, R) = cv2.split(image.astype("float"))
    # compute rg = R - G
    rg = np.absolute(R - G)
    # compute yb = 0.5 * (R + G) - B
    yb = np.absolute(0.5 * (R + G) - B)
    # compute the mean and standard deviation of both `rg` and `yb`
    (rbMean, rbStd) = (np.mean(rg), np.std(rg))
    (ybMean, ybStd) = (np.mean(yb), np.std(yb))
    # combine the mean and standard deviations
    stdRoot = np.sqrt((rbStd ** 2) + (ybStd ** 2))
    meanRoot = np.sqrt((rbMean ** 2) + (ybMean ** 2))
    # derive the "colorfulness" metric and return it
    return stdRoot + (0.3 * meanRoot)

Upvotes: 1

Views: 749

Answers (1)

Mark Setchell
Mark Setchell

Reputation: 207345

I had a try at speeding this up, just by using OpenCV functions and got a 6.5x speed-up over your Numba version on my machine:

#!/usr/bin/env python3
import numpy as np
import cv2
from numba import *

def me(image,B,G,R):
    # Use OpenCV methods wherever possible
    rg = cv2.absdiff(R,G)
    rgMean, rgStd  = cv2.meanStdDev(rg)

    avg = cv2.addWeighted(R, 0.5, G, 0.5, 0)
    yb  = cv2.absdiff(avg, B)
    ybMean, ybStd  = cv2.meanStdDev(yb)

    # combine the mean and standard deviations
    stdRoot = np.sqrt((rgStd ** 2) + (ybStd ** 2))
    meanRoot = np.sqrt((rgMean ** 2) + (ybMean ** 2))
    # derive the "colorfulness" metric and return it
    return stdRoot + (0.3 * meanRoot), rgMean, rgStd, ybMean, ybStd

@njit(parallel=True)
def image_colorfulness(image,B,G,R):
    # compute rg = R - G
    rg = np.absolute(R - G)
    # compute yb = 0.5 * (R + G) - B
    yb = np.absolute(0.5 * (R + G) - B)
    # compute the mean and standard deviation of both `rg` and `yb`
    rgMean, rgStd = np.mean(rg), np.std(rg)
    ybMean, ybStd = np.mean(yb), np.std(yb)
    # combine the mean and standard deviations
    stdRoot = np.sqrt((rgStd ** 2) + (ybStd ** 2))
    meanRoot = np.sqrt((rgMean ** 2) + (ybMean ** 2))
    # derive the "colorfulness" metric and return it
    return stdRoot + (0.3 * meanRoot), rgMean, rgStd, ybMean, ybStd


image   = cv2.imread('Oscars-selfie_620x349.png')

# OP's original method
B, G, R = cv2.split(image.astype("float"))
score, *others   = image_colorfulness(image,B=B,G=G,R=R)
print(score, others)

%timeit image_colorfulness(image,B=B,G=G,R=R)

# Using OpenCV and avoiding promotion to float
B, G, R = cv2.split(image)
score, *others   = me(image,B=B,G=G,R=R)
print(score, others)

%timeit  me(image,B=B,G=G,R=R)

Timings for original and OpenCV methods

1.11 ms ± 43.7 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

171 µs ± 1.49 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Upvotes: 4

Related Questions