1

I'm currently working on a project which uses color detection (OpenCV). I'm very new to Python and OpenCV so I'm not getting it work exactly as I want it to.

I have a class ColourDetection(any suggestions for fine tuning the HSV values?) which contains the static method detect_color which we use to detect a certain color. Here it is:

#!/usr/bin/env python
import  cv2
import  numpy   as  np

class ColourDetection(object):

    #HSV 180-255-255 max values openCV (recalculate from GIMP)
    #these need adjusting
    BOUNDARIES = {
    'red': ([170, 160, 60], [180, 255, 255]),
    'blue': ([110, 50, 50], [130, 255, 255]),
    'green': ([38, 50, 50], [75, 255, 255]),
    'yellow':([103, 50, 50], [145, 255, 255])
    }

    @staticmethod
    def detect_color(detection_image):
        img_hsv =   cv2.cvtColor(detection_image,   cv2.COLOR_BGR2HSV)
        #loop for all defined colours
        for k,v in ColourDetection.BOUNDARIES.iteritems():
            #convert to numpy arrays
            lower_color = np.array(v[0])
            upper_color = np.array(v[1])
            #create mask from colour bounds
            mask    =   cv2.inRange(img_hsv,    lower_color,    upper_color)
            #count found colour pixels
            amount_not_zero = cv2.countNonZero(mask)
            if amount_not_zero > 9000:
                return k
            else:
                return "No colour found"

The first 2 tests are working correctly. However the last test should return red using these RGB values. It seems I need some fine tuning with the HSV values. Can anyone help me?

from unittest import TestCase
from ColourDetection import ColourDetection
import numpy as np

__author__ = 'user'


class TestColourDetection(TestCase):
    def test_detect_color_not_found(self):
        image = np.zeros((512, 512, 3), np.uint8)
        color = ColourDetection.detect_color(image)
        self.assertEqual("No colour found", color)

    def test_detect_color_is_red(self):
        image = np.zeros((512, 512, 3), np.uint8)
        image[:,0:512] = (0, 0, 255)
        color = ColourDetection.detect_color(image)
        self.assertEqual("red", color)

    def test_detect_color_is_blue(self):
        image = np.zeros((512, 512, 3), np.uint8)
        image[:,0:512] = (255, 0, 0)
        color = ColourDetection.detect_color(image)
        self.assertEqual("blue", color)

def test_detect_color_is_green(self):
    image = np.zeros((512, 512, 3), np.uint8)
    image[:,0:512] = (0, 255, 0)
    color = ColourDetection.detect_color(image)
    self.assertEqual("green", color)

def test_detect_color_is_yellow(self):
    image = np.zeros((512, 512, 3), np.uint8)
    image[:,0:512] = (0, 255, 255)
    color = ColourDetection.detect_color(image)
    self.assertEqual("yellow", color)
DNA
  • 42,007
  • 12
  • 107
  • 146
Redesign1991
  • 137
  • 1
  • 3
  • 12
  • I've found it works using: image[:,0:512] = (0, 0, 100). Nevertheless could I still get some feedback on whether this is the best way to approach it? – Redesign1991 Jan 15 '15 at 09:26
  • OpenCV default color space is BGR. In general use `cv2.cvtColor(detection_image, cv2.COLOR_BGR2HSV)`. Although in your example you do it manually so it should be fine to use `cv2.COLOR_RGB2HSV` as you do. – Arnaud P Jan 15 '15 at 09:49
  • I changed it to cv2.COLOR_BGR2HSV and added some more unit tests for the other colors but the only 2 I get to work are those for blue and black. So I suppose I need some help with tuning the HSV values in the array – Redesign1991 Jan 15 '15 at 10:53
  • according to http://upload.wikimedia.org/wikipedia/commons/thumb/a/ad/HueScale.svg/743px-HueScale.svg.png Green for example is around 120. So let's say from H = 100 to H = 140. Now OpenCV divides the H values by 2 to fit 360 Degrees to 0..255 byte range (so 0..180 hue values). So set your range from H = 50 to H = 70 to detect green color. S and V values can be anything in theory, but probably you have to ignore too low values. – Micka Jan 15 '15 at 10:57
  • For some reason, god knows why, I can't get it to detect red, green or yellow. I can only get it to detect blue (using my test methods). I've tossed and turned with the BGR values, calculating the hue according to your calculations. But it's not working sadly. I also look at the hue values of basic colors from OpenCV and tried those, but that's not working either. To be certain I also let it display the image to me, to be a 100% sure the image I'm creating is red or blue, etc. – Redesign1991 Jan 15 '15 at 14:55

1 Answers1

0

The reason why you're only detecting blue might be because of a bug in your detect_color function.

@staticmethod
def detect_color(detection_image):
    for k,v in ColourDetection.BOUNDARIES.iteritems():
    # . . .
        if amount_not_zero > 9000:
            return k
        else:
            return "No colour found"

Notice that you will always return a value in your first iteration over the k,v pairs.

That is, either the first k that iteritems() gives you, or "No colour found".

gvlasov
  • 18,638
  • 21
  • 74
  • 110
ronh
  • 51
  • 3