MikeStone
MikeStone

Reputation: 31

Obtain a color from a image and represent it

I want to know if X color appears in an image. In this case, the color of the study will be green, therefore its RGB value is (0.255.0).

I apply the following code:

    img = cv2.imread('img.jpg')

    L1 = [0, 255, 0]

    matches = np.all(img == L1, axis=2)
    result = np.zeros_like(img)

    print(result.any())
    result[matches] = [255, 0, 255]

    cv2.imwrite('resultado.jpg', result)

Basically:

  1. I load the image that I want to analyze.
  2. I describe the RGB value I want to obtain.
  3. I check if this color (green) appears in the image.
  4. I create an image of mine's size completely black and call it "result".
  5. I show by screen if that color appears through Boolean.
  6. I DRAW THE GREEN AREA OF RED IN RESULT.
  7. Finally I keep this last step.

Below is shown the studio image and then what is painted red.

Image to study:

Image to study

Result:

Result

Why is not a box painted the same as green but in red? Why just that little dots?

Thank you!

Upvotes: 3

Views: 205

Answers (3)

Mark Setchell
Mark Setchell

Reputation: 207903

I is often more appropriate to use the "Hue, Saturation and Lightness" system rather than RGB to separate out colours in images - see Wikipedia article here.

So you might consider something like this:

#!/usr/local/bin/python3
import numpy as np
from PIL import Image

# Open image and make RGB and HSV versions
RGBim = Image.open("seaside.jpg")
HSVim = RGBim.convert('HSV')

# Make numpy versions
RGBna = np.array(RGBim)
HSVna = np.array(HSVim)

# Extract Hue
H = HSVna[:,:,0]

# Find all green pixels, i.e. where 110 < Hue < 130
lo,hi = 110,130
# Rescale to 0-255, rather than 0-360 because we are using uint8
lo = int((lo * 255) / 360)
hi = int((hi * 255) / 360)
green = np.where((H>lo) & (H<hi))

# Make all green pixels red in original image
RGBna[green] = [255,0,0]

count = green[0].size
print("Pixels matched: {}".format(count))
Image.fromarray(RGBna).save('result.png')

enter image description here

Upvotes: 1

Beno&#238;t P
Beno&#238;t P

Reputation: 3265

here is a script that does what you want, I used numpy too so it won't be difficult to adapt it for your needs.

This script will find a colour and replace it by another:

import numpy
from PIL import Image
im = numpy.array(Image.open("/path/to/img.jpg"))

tol = 4     # tolerence (0 if you want an exact match) 
target_color = [0, 255, 0, 255]  # color to change
replace_color = [255, 0, 255, 255]  # color to use to paint the zone
for y, line in enumerate(im):
    for x, px in enumerate(line):
        if all((abs(px[i] - target_color[i]) < tol for i in range(3))):
            im[y][x] = replace_color
Image.fromarray(im).save("./Desktop/img.png")

This one will be black with only the match coloured in the replace colour:

import numpy
from PIL import Image
im = numpy.array(Image.open("/path/to/img.jpg"))
new_im = numpy.zeros_like(im)

tol = 4     # tolerence (0 if you want an exact match) 
target_color = [0, 255, 0, 255]  # color to change
replace_color = [255, 0, 255, 255]  # color to use to paint the zone
for y, line in enumerate(im):
    for x, px in enumerate(line):
        if all((abs(px[i] - target_color[i]) < tol for i in range(3))):
            new_im[y][x] = replace_color
Image.fromarray(new_im).save("./Desktop/img.png")

What is missing from your script is some tolerance, because your green might not be a perfect green.

Upvotes: 1

Daweo
Daweo

Reputation: 36735

Problem is caused by that green area is NOT build only from [0, 255, 0] as do you think, OT21t.jpg is your input image, when I did:

import cv2
img = cv2.imread('OT21t.jpg')
print(img[950,1300])

I got [ 2 255 1], so it is not [0,255,0]. Keep in mind that when .jpg images are saved, most often it is lossy process - part of data might be jettisoned allowing smaller file size (for more about that search for lossy compression).

Upvotes: 1

Related Questions