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
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:
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:
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. ])