Lorenzo Bussotti
Lorenzo Bussotti

Reputation: 72

How to get the average value of RGB single channel of multiple images with Numpy Python?

I am trying to extract features of multiple images located in a specific folder ('image'). I want to insert this features (grayscale, R,G,B, alpha, height and width) into a table using tabulate package. The main issue is to iterate over the folder and extract the average values of the single Red, Green, Blue channels and, also to obtain the value of gray (if an image is present in that scale). After that, I would like to insert all information into the table. I am not able to do any of this operation. I've tried a this code, but it gives me many pixels values. I'd like to get the average value, so JUST ONE NUMBER for each channel. Please, anybody can help?

import os
import numpy as np
import cv2

for img in os.listdir(image_path):        
    img = cv2.imread(os.path.join(image_path, img))     
    r,g,b = cv2.split(img)
    rgb_img = cv2.merge((r,g,b))
    x,y,z = np.shape(img)
    red = np.zeros((x,y,z),dtype=int)
    green = np.zeros((x,y,z),dtype=int)
    blue = np.zeros((x,y,z),dtype=int)
    for i in range(0,x):
        for j in range(0,y):
            red[i][j][0] = rgb_img[i][j][0]
            green[i][j][1]= rgb_img[i][j][1]
            blue[i][j][2] = rgb_img[i][j][2]

I don't know any method else, can anybody suggests one? I would really appreciate. Thank you

Upvotes: 2

Views: 4219

Answers (2)

A. Bollans
A. Bollans

Reputation: 167

According to https://sighack.com/post/averaging-rgb-colors-the-right-way the correct way to average RGB color values is to sum their squares rather than just take the mean. Example code in python is given below. Could probably be optimised but works for me.

def get_avg_rgb(img_file: str):
    import cv2

    img = cv2.imread(img_file)
    r_values = img[:, :, 2].flatten()
    g_values = img[:, :, 1].flatten()
    b_values = img[:, :, 0].flatten()

    Rsum = 0
    for r in r_values:
        Rsum += (float(r) * float(r))

    Gsum = 0
    for g in g_values:
        Gsum += (float(g) * float(g))

    Bsum = 0
    for b in b_values:
        Bsum += (float(b) * float(b))
    avgR = math.sqrt((float(Rsum) / len(r_values)))
    avgG = math.sqrt((float(Gsum) / len(g_values)))
    avgB = math.sqrt((float(Bsum) / len(b_values)))

    avgs = [avgR, avgG, avgB]

    return avgs

Upvotes: 0

XXDIL
XXDIL

Reputation: 320

If you want the average values of the channels(R, G, B), and finally want to store it in a table using tabulate, you could do the following:

I will be using OpenCV(to load the images) and numpy(cuz why not)

import cv2
import numpy as np
import os
from tabulate import tabulate

images = os.listdir('./Test')
num_images = len(images)

data = [] # using an array is more convenient for tabulate.

for i in range(num_images):
    img = cv2.imread('./Test/' + images[i])
        
    avgR = np.mean(img[:,:,2])
    avgG = np.mean(img[:,:,1])
    avgB = np.mean(img[:,:,0])
    
    data.append([images[i], avgR, avgG, avgB])
    
print(tabulate(data, headers=['img_name','R', 'G', 'B'], tablefmt='fancy_grid'))

'''
╒════════════╤══════════╤══════════╤══════════╕
│ img_name   │        R │        G │        B │
╞════════════╪══════════╪══════════╪══════════╡
│ test1.jpg  │  49.3213 │ 112.408  │ 145.949  │
├────────────┼──────────┼──────────┼──────────┤
│ test2.jpeg │  93.0038 │  94.4466 │  95.0824 │
├────────────┼──────────┼──────────┼──────────┤
│ test3.jpg  │ 100.181  │  71.6575 │  66.4233 │
╘════════════╧══════════╧══════════╧══════════╛
'''


This is my Directory Structure:

dir structure

The code is present in the movie scraper directory. Hence i have used the path './Test'. The dot '.' represents the current dir.

Upvotes: 2

Related Questions