Home > Software design >  Change colors that do not match specific color(s) to white using opencv
Change colors that do not match specific color(s) to white using opencv

Time:11-24

I'm trying to use opencv to grab specific elements out of the image. So far what I have done is reduced the number of colors in the image, and gotten a dictionary of colors with their counts. What I want to do now is replace all colors which do not match this specific color to white, so that I can iterate over the image and create different images where each image only has one object of that particular color.

This is what I've done so far:

def showOnlyOneColor(img, rgb_key):
    print("Getting only one color")
    rgb_key = rgb_key.split("-")
    r = int(rgb_key[0])
    g = int(rgb_key[1])
    b = int(rgb_key[2])

    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    rgb_low = np.array([r,g,b])
    rgb_high = np.array([r,g,b])
    mask = cv2.inRange(hsv, rgb_low, rgb_high)
    contours = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    contours = contours[0] if len(contours) == 2 else contours[1]
    cv2.fillPoly(mask, contours, (255, 255, 255))
    result = cv2.bitwise_and(img,img,mask=mask)


    return result

Second attempt:

def showOnlyOneColor(img, rgb_key):
    print("Getting only one color")
    rgb_key = rgb_key.split("-")
    r = int(rgb_key[0])
    g = int(rgb_key[1])
    b = int(rgb_key[2])

    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    rgb_low = np.array([r,g,b])
    rgb_high = np.array([r,g,b])
    mask = cv2.inRange(hsv, rgb_low, rgb_high)

    img[mask!=255] = (255, 255, 255)

    return img

This results in a white image for all iterations

This is what I'm using to reduce the number of colors in the image:

def reduceNumberOfColors(img):
    div = 128
    return img // div * div   div // 2

Latest attempt:

def showOnlyOneColor(img, rgb_key):
    print("Getting only one color")
    rgb_key = rgb_key.split("-")
    r = int(rgb_key[0])
    g = int(rgb_key[1])
    b = int(rgb_key[2])
    hsv_color = colorsys.rgb_to_hsv(r,g,b)

    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    rgb_low = np.array(hsv_color)
    rgb_high = np.array(hsv_color)
    mask = cv2.inRange(hsv, rgb_low, rgb_high)

    img[mask!=255] = (255, 255, 255)

    return img

One of the resulting images shows something, the rest of the images are white

How I organize rgb:

def getColorCount(img):
    color_dict = {}
    print("Getting color count")
    for i in tqdm(range(img.shape[0])):
        for j in range(img.shape[1]):
            color = img[i,j]
            r = color[0]
            g = color[1]
            b = color[2]
            rgb_askey = str(r) "-" str(g) "-" str(b)
            if rgb_askey not in color_dict.keys():
                color_dict[rgb_askey] = 1
            else:
                color_dict[rgb_askey]  = 1
    return color_dict

CodePudding user response:

Here is one way to do what you want in Python/OpenCV. Note colors are in the order B,G,R.

Input:

enter image description here

import cv2
import numpy as np

# read image
img = cv2.imread('corn.jpg')

# do simple color reduction
imgcopy = img.copy()
div = 128
imgcopy = div * ( imgcopy // div )   div // 2

# get list of unique colors
list_bgr_colors = np.unique(imgcopy.reshape(-1, imgcopy.shape[2]), axis=0)
print(list_bgr_colors)
print(list_bgr_colors[1])

# save reduced color image
cv2.imwrite("corn_reduced_colors.png", imgcopy)

# display reduced color image
cv2.imshow("reduced_colors", imgcopy)
cv2.waitKey(0)   

# loop over colors in list and change all non-specified colors to white
i = 1
for color in list_bgr_colors:

    # threshold on the specified color
    lower=np.array((color))
    upper=np.array((color))
    mask = cv2.inRange(imgcopy, lower, upper)

    # change all non-specified color to white
    result = imgcopy.copy()
    result[mask!=255] = (255, 255, 255)

    # save results
    cv2.imwrite("corn_color_{0}.png".format(i), result)

    # display result
    cv2.imshow("result", result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    # increment
    i  = 1

List of Reduced Colors:

[[ 64  64  64]
 [ 64  64 192]
 [ 64 192  64]
 [ 64 192 192]
 [192 192 192]]

Reduced Color Image:

enter image description here

Individual Color Images:

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

CodePudding user response:

Colors in OpenCV are in the order B,G,R.

So try this in Python/OpenCV.

def showOnlyOneColor(img, bgr_key):
    print("Getting only one color")
    bgr_key = bgr_key.split("-")
    b = int(bgr_key[0])
    g = int(bgr_key[1])
    r = int(bgr_key[2])
    bgr_low = np.array((b,g,r))
    bgr_high = np.array((b,g,r))
    mask = cv2.inRange(img, bgr_low, bgr_high)

    img[mask!=255] = (255, 255, 255)

    return img

ADDITION

I think your issue is in your assumption that you have RGB colors when you use colorsys to convert from RGB to HSV. Your colors are actually B, G, R. So to use colorsys you need to convert your image to RGB first or better reverse the order of the colors that you extract from B,G,R to R,G,B before using colorsys.

Your dictionary colors are actually B, G, R not R, G, B. So reverse them or reverse them later when using colorsys.

CodePudding user response:

This works for me in Python/OpenCV. Note that OpenCV colors are in the order B,G,R.

enter image description here

import cv2
import numpy as np

# read image
img = cv2.imread('corn.jpg')

# threshold on yellow color
lower=(0,170,215)
upper=(70,255,255)
mask = cv2.inRange(img, lower, upper)

# change all non-yellow to white
result = img.copy()
result[mask!=255] = (255, 255, 255)

# save results
cv2.imwrite('corn_yellow.jpg',result)

# display result
cv2.imshow("mask", mask)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

enter image description here

  • Related