This solution is inspired by TomB's post. There is a slight change. Tom's post is based on RGB color space, while mine is based on the LAB color space. To know more about LAB space please go through this post and the mentioned link within.
Advantage of using LAB space
LAB has 3 channels just like RGB. But only 2 channels have color information (A and B), while L channel represents brightness value. Unlike RGB where we have to analyze all three channels, using LAB we can analyze only 2 channels. The benefit will be apparent when one has to analyze a large number of images.
Method:
The method is no different compared to Tom's post. Here we will:
- obtain A and B channels of the image
- find the mean value of the difference between them
- determine a threshold above which all images can be labelled as color.
Code
Images used:
Gray image:

Color image:

einstein_img = cv2.imread('Einstein.jpg')
flower_img = cv2.imread('flower.jpg')
# convert to LAB space
elab = cv2.cvtColor(einstein_img, cv2.COLOR_BGR2LAB)
flab = cv2.cvtColor(flower_img, cv2.COLOR_BGR2LAB)
# split the channels
el, ea, eb = cv2.split(elab)
# obtain difference between A and B channel at every pixel location
de = abs(ea-eb)
# find the mean of this difference
mean_e = np.mean(de)
# same as above for the color image:
fl, fa, fb = cv2.split(flab)
df = abs(fa-fb)
mean_f = np.mean(df)
# for gray image
print(mean_e)
0.0
# for color image
print(mean_f)
83.5455
Why does this work?
This works because images that contain predominantly white, gray and black do not show much variation in the dual color channels of LAB space. It has been designed to segment/isolate dominant colors well. But can work well for less colored images also.
A and B channel of colored flower
image placed beside each other:

Since there are differences between the two at each pixel we obtain a non-zero mean value.
A and B channel of gray Einstein
image placed beside each other:

Here however we obtain no mean value.
Note: Although 0 is the ideal mean value, there may be cases where non-zero value may appear for gray image. The value though won't be as large as a color image. One can define a threshold in such scenarios.