Home > other >  Python - average color of part of an image
Python - average color of part of an image

Time:05-12

I need to find the average color of a specified part of the image. Specifically I need to know If the color in there is red, green, brown, black or blue.

The images are 640x640, and the region I need to analyze is the rectangle between pixel x1=20 y1=600 and pixel x2=620 y2=640. (where x0y0 is top left corner)

I found several examples, like this one enter image description here

Test for Yellow Region:

import cv2
import numpy as np
import math

# load image
img = cv2.imread("sailboat.png")
hh, ww = img.shape[:2]

# threshold
lower = (0,200,200)
upper = (50,255,255)
thresh = cv2.inRange(img, lower, upper)

# apply open morphology
#kernel = np.ones((5,5), np.uint8)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)

# get bounding box coordinates from largest external contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)

# draw white filled contour on black background
mask = np.zeros((hh,ww), dtype=np.uint8)
cv2.drawContours(mask, [big_contour], 0, 255, cv2.FILLED)

# compute mean color for region
mean = cv2.mean(img, mask=mask)[0:3]
blue_mean = mean[0]
green_mean = mean[1]
red_mean = mean[2]
print("region_mean_color:", mean)
print("")

# define colors
red = np.array(["red",(0,0,255)],dtype=object)
green = np.array(["green",(0,255,0)],dtype=object)
brown = np.array(["brown",(20,70,140)],dtype=object)
black = np.array(["black",(0,0,0)],dtype=object)
blue = np.array(["blue",(255,0,0)],dtype=object)
yellow = np.array(["yellow",(0,255,255)],dtype=object)

min_rmse = 1000000
colors = np.array([red, green, brown, black, blue, yellow])
print("colorname", "rmse")
for color in colors:
    bb = color[1][0]
    gg = color[1][1]
    rr = color[1][2]
    rmse = math.sqrt( ( (red_mean-rr)*(red_mean-rr)   (green_mean-gg)*(green_mean-gg)   (blue_mean-bb)*(blue_mean-bb) )/3 )
    colorname = color[0]
    print(colorname,rmse)
    if rmse < min_rmse:
        min_rmse = rmse
        match_color = color[0]
print("")
print("match_color:", match_color)
print("rmse:", min_rmse)

# write result to disk
cv2.imwrite("sailboat_thresh.jpg", thresh)
cv2.imwrite("sailboat_morph.jpg", morph)
cv2.imwrite("sailboat_mask.jpg", mask)

# display results
cv2.imshow("THRESH", thresh)
cv2.imshow("MORPH", morph)
cv2.imshow("MASK", mask)
cv2.waitKey(0)
cv2.destroyAllWindows()

Mask Image:

enter image description here

Textual Information:

region_mean_color: (0.0, 254.65158457426497, 254.65158457426497)

colorname rmse
red 147.02329851590747
green 147.02329851590747
brown 126.01745055239607
black 207.92214813271502
blue 254.7677759924176
yellow 0.2844800038551275

match_color: yellow
rmse: 0.2844800038551275

CodePudding user response:

I think you just want to use Numpy slicing to indicate your area of interest.

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

enter image description here

Then the code would go like this:

import cv2

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

# Calculate mean of green area
A = np.mean(im[200: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[100:640, 20:620], axis=(0,1))

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

array([  0.        , 207.77777778,   0.        ])
  • Related