anastasia
anastasia

Reputation: 13

Merge RGB channel of images after normalizing color in each channel

I want to merge RGB channel in the function I created after I normalized each channel with the value of r,g,b that I define before, here is the equation enter image description here

def color_norm(image_norm):
  pixels = np.array(image_norm)
  ar_mean = np.mean(pixels, axis=(0,1)) 
  (H,W) = image_norm.shape[:2]

  for x in range(H):
    for y in range(W):
      Ri = image_norm[:,:,0]
      Gi = image_norm[:,:,1]
      Bi = image_norm[:,:,2]
      R = Ri[x,y] = np.min((Ri[x,y]/(ar_mean[0]))*(r))
      if R > 255:
           # saturate value
           R = 255
      else:
          # add normally
          R = R
      G = Gi[x,y] = np.min((Gi[x,y]/(ar_mean[1]))*(g))
      if G > 255:
           # saturate value
           G = 255
      else:
          # add normally
          G = G
      B = Bi[x,y] = np.min((Bi[x,y]/(ar_mean[2]))*(b))
      if B > 255:
           # saturate value
           B = 255
      else:
          # add normally
          B = B
      image_norm[x,y] = [R,G,B]

when I tried in single image it works,but when I pass this function to the dataset(contain 5 images) it raise an error TypeError: Image data of dtype object cannot be converted to float anyone knows how to merge the RGB channel so that I can pass the function?

Upvotes: 1

Views: 470

Answers (2)

balu
balu

Reputation: 1143

A full working code here

import cv2
import numpy as np

def color_norm(img, weights):
    kb, kg, kr = weights
    
    b = img[:, :, 0].astype(np.float32)
    g = img[:, :, 1].astype(np.float32)
    r = img[:, :, 2].astype(np.float32)
    
    bm = np.mean(b)
    gm = np.mean(g)
    rm = np.mean(r)     
 
    img_out = np.empty_like(img, dtype=np.uint8)
    
    img_out[:, :, 0] = np.minimum(b*kb/bm,255).astype(np.uint8)
    img_out[:, :, 1] = np.minimum(g*kg/gm,255).astype(np.uint8)
    img_out[:, :, 2] = np.minimum(r*kr/rm,255).astype(np.uint8)
    
    return img_out

fin = r'D:\ColorfulMacaws-640x480.jpg'
img_bgr = cv2.imread(fin, cv2.IMREAD_COLOR)
cv2.imshow('Image before norm', img_bgr)
ws = (40, 50, 60)
imout = color_norm(img_bgr, ws)
cv2.imshow('Image after norm', imout)
cv2.waitKey(0)
cv2.destroyAllWindows()

enter image description here

Upvotes: 1

Kirill Setdekov
Kirill Setdekov

Reputation: 331

Based on the code I tried, here's a solution to your question.

import numpy as np


def normalize_to_grayscale(image: np.array, weights: tuple):
    """normalized a numpy array of an image to 0-255 interval , returning middle gray if all values are equal

    Args:
        image (np.array): input image
        weights (tuple): tuple of len 3, with weights of the channels

    Returns:
        np.array: normalized array, same size as input image
    """
    # Convert image to float
    image = image.astype(float)

    H, W, _ = image.shape
    # Convert image to grayscale
    image_gray = np.zeros((H, W))
    for x in range(H):
        for y in range(W):
            image_gray[x, y] = np.sum(image[x, y] * weights)

    # Normalize the image
    image_gray -= (image_gray.min())
    max_value = image_gray.max()

    if max_value == 0:
        return np.zeros((H, W)) + 127.5
    image_gray *= (255.0/image_gray.max())

    return image_gray


# Create sample image
img = np.array([[[255, 0, 0], [0, 255, 0], [0, 0, 255]],
                [[0, 0, 255], [255, 0, 0], [0, 255, 0]],
                [[255, 0, 0], [0, 255, 0], [0, 0, 255]]])

weights = (1, 2, 3)

normalize_to_grayscale(img, weights)

It returns a result like this.

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

Upvotes: 0

Related Questions