How to Find the Average Colour of an Image in Python With Opencv

Python - Fastest way to compute average color of an image

frame.mean(axis=(0,1))

gives you the mean BGR (or RGB) value of that frame, assuming it's a 3-channel numpy array.

Find average colour of each section of an image

This works for 4 sections, but you'll need to figure out how to make it work for 'n' sections:

import cv2

img = cv2.imread('image.png')

def fourSectionAvgColor(image):
rows, cols, ch = image.shape
colsMid = int(cols/2)
rowsMid = int(rows/2)

numSections = 4
section0 = image[0:rowsMid, 0:colsMid]
section1 = image[0:rowsMid, colsMid:cols]
section2 = image[rowsMid: rows, 0:colsMid]
section3 = image[rowsMid:rows, colsMid:cols]
sectionsList = [section0, section1, section2, section3]

sectionAvgColorList = []
for i in sectionsList:
pixelSum = 0
yRows, xCols, chs = i.shape
pixelCount = yRows*xCols
totRed = 0
totBlue = 0
totGreen = 0
for x in range(xCols):
for y in range(yRows):
bgr = i[y,x]
b = bgr[0]
g = bgr[1]
r = bgr[2]
totBlue = totBlue+b
totGreen = totGreen+g
totRed = totRed+r

avgBlue = int(totBlue/pixelCount)
avgGreen = int(totGreen/pixelCount)
avgRed = int(totRed/pixelCount)
avgPixel = (avgBlue, avgGreen, avgRed)
sectionAvgColorList.append(avgPixel)
return sectionAvgColorList

print(fourSectionAvgColor(img))
cv2.waitKey(0)
cv2.destroyAllWindows()

Python - average color of part of an image

As your region of interest (ROI) is only a simple rectangle, I think you just want to use Numpy slicing to identify it.

So, I have made a test image that is green where you want to measure:

Sample Image

Then the code would go like this:

import cv2
import numpy as np

# Load the image
im = cv2.imread('start.png')

# Calculate mean of green area
A = np.mean(im[600:640, 20:620], axis=(0,1))

That gets green, unsurprisingly:

array([  0., 255.,   0.])

Now include some of the black area above the green to reduce the mean "greenness"

B = np.mean(im[500:640, 20:620], axis=(0,1))

That gives... "a bit less green":

aarray([ 0.        , 72.85714286,  0.        ])

The full sampling of every pixel in the green area takes 214 microsecs on my Mac, as follows:

IIn [5]: %timeit A = np.mean(im[600:640, 20:620], axis=(0,1))
214 µs ± 150 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Note that you could almost certainly sample every 4th pixel down and every 4th pixel across as follows in 50.6 microseconds and still get a very indicative result:

In [11]: %timeit A = np.mean(im[500:640:4, 20:620:4], axis=(0,1))
50.6 µs ± 29.3 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

You can make every pixel you are sampling into a red dot like this - look carefully:

im[600:640:4, 20:620:4] = [255,0,0]

Sample Image


As suggested by Fred (@fmw42), it is even faster if you replace np.mean() with cv2.mean():

So, 11.4 microseconds with cv2.mean() versus 214 microseconds with np.mean():

In [22]: %timeit cv2.mean(im[600:640, 20:620])
11.4 µs ± 11.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

And 7.85 microseconds with cv2.mean() versus 50.6 microseconds with np.mean() if sampling every 4th pixel:

In [23]: %timeit cv2.mean(im[600:640:4, 20:620:4])
7.85 µs ± 6.42 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Get the average color inside a contour with Open CV

You can create a mask by first creating a new image with the same dimensions as your input image and pixel values set to zero.

You then draw the contour(s) onto this image with pixel value 255. The resulting image can be used as a mask.

mask = np.zeros(frame.shape, np.uint8)
cv2.drawContours(mask, c, -1, 255, -1)

mask can then be used as a parameter to cv.mean like

mean = cv.mean(frame, mask=mask)

Just one word of caution, the mean of RGB colors does not always make sense. Maybe try converting to HSV color space and solely use the H channel for detecting the color of your objects.

Get average-dominant color from a rectangle on screen (live/python)

You can do this task more efficiently but even if you do the way you describe, these are not computationally intensive operations. All should take less than 0.1 seconds. As @fmw42 described, you don't need to save, do the analysis on the fly.

The libraries you mention are good.

  1. Get screenshot. Store it in memory (not disk)
  2. mean: get the mean of each channel color, and get the dominant color.
  3. save image on disk

Grid on Image to compute the average color

One way is to resize the image using block averaging. To do that one has to compute the new size such that each pixel in the new image represent a 10x10 block of pixels in the original. Then just print out the list of values in the resized image. Those will be the average colors for each 10x10 block.

Input:

enter image description here

import cv2

img = cv2.imread('lena_crop.png')

# get shape
h, w, c = img.shape
print (h,w,c)


# compute scale size so that each pixel in the resize image corresponds to 10x10 original pixels
hs = round(h/10)
ws = round(w/10)
print(hs,ws)

# resize image using block averaging
resized = cv2.resize(img, (ws,hs), interpolation = cv2.INTER_AREA)

cv2.imshow("Resized image", resized)
cv2.waitKey(0)
cv2.destroyAllWindows()

print(list(resized))


We start with a 250x250 sized image. The new size will be 25x25. The first few values that result are:

[array([[112, 132, 225],
[109, 132, 225],
[111, 138, 231],
[ 85, 69, 173],
[ 83, 73, 178],
[ 87, 83, 188],
[ 93, 96, 204],
[ 95, 99, 206],
[ 97, 101, 210],
[ 97, 101, 209],
[ 99, 101, 206],
[ 95, 99, 206],
[ 97, 101, 208],
[ 96, 98, 204],
[ 96, 97, 203],
[ 94, 89, 190],
[101, 103, 201],
[111, 132, 223],
[107, 131, 224],
[106, 129, 221],
[133, 176, 237],
[106, 117, 197],
[ 94, 91, 189],
[ 94, 93, 193],
[ 93, 92, 193]], dtype=uint8), array([[110, 133, 228],
[112, 140, 230],
[105, 130, 227],
[ 78, 67, 173],
[ 80, 71, 178],
[ 84, 80, 189],
[ 91, 93, 203],
[ 94, 96, 206],
[ 95, 96, 209],
[ 96, 97, 209],
[ 90, 92, 206],
[ 92, 93, 203],
[ 98, 98, 205],
[ 95, 96, 205],
[ 92, 93, 205],
[ 94, 90, 197],
[ 97, 89, 191],
[117, 132, 223],
[110, 133, 225],
[109, 129, 223],
[110, 131, 220],
[140, 185, 236],
[ 92, 89, 187],
[ 94, 91, 190],
[ 72, 40, 118]], dtype=uint8), array([[111, 138, 231],
...


Related Topics



Leave a reply



Submit