0

I would need to verify if and how much of certain predefined color ranges are present in a image file.

each color range is defined by 6 variables and a counter in a colorRange class:

hS (hue start)
hE (hue end)
sS (saturation start)
sE (saturation end)
lS (lightness start)
lE (lightness end)
colorCounter

The image can either be a file, or loaded from the camera. Following code loads the image from the camera buffer:

img1 = np.ndarray(buffer=component.data.copy(), dtype=np.uint8,
                                     shape=(component.height, component.width, 1))
img2 = cv2.cvtColor(img1, cv2.COLOR_BayerBG2BGR)

what I would need to do is to scan every n-th pixel (5 is a good starting value), and compare it to every color range. if it falls into that color range, then add +1 to that specific colorCounter. In the end I go over the Counter of each color range and calculate the presence of that color range in %. The goal is to check the % of analized pixels that fall into each color range. The sum of the colorranges can be greater than 100 since a pixel can fall into multiple colorranges as tehy can be overlapping. (for example a color ragne could be all the reds, and another could be only the dark reds.. a dark red pixel would fall into both ranges, a bright red only in the first one.)

The way I would do it is to check every fifth pixel one by one, convert its rgb value to HSL, and then compare it with all the color ranges. (where if hS > hE then it is wrapping around in the reds)

But it seems a very complicated way to do it and was wondering if there are some premade functions that can do this, or at least partially do this.

So the question is: How can this be done in a smart way?

UPDATE:

this is what I have so far:

    hls = cv2.cvtColor(img2, cv2.COLOR_BGR2HLS)
    
    GreenLo = np.array([75, 0, 0])
    GreenHi = np.array([155, 1, 1])

    pxGreen = cv2.inRange(hls[0:620:5, 0:620:5], GreenLo, GreenHi)
    cGreen = cv2.countNonZero(pxGreen)
Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
sharkyenergy
  • 3,842
  • 10
  • 46
  • 97
  • How many colours in your list please? – Mark Setchell Jun 09 '22 at 06:36
  • @MarkSetchell that is not defined. can be 10 or 20.. or even 30.. more than 30 is very unlikely... – sharkyenergy Jun 09 '22 at 09:43
  • 1
    Just run `cv2.inRange()` for each colour in your list and count True (non-zero) pixels https://docs.opencv.org/4.x/d2/de8/group__core__array.html#gaa4b89393263bb4d604e0fe5986723914 – Mark Setchell Jun 09 '22 at 09:47
  • @MarkSetchell thanks for your comment, but i am not sure I understand what you mean. the pixel has to be within 3 boundries.. (h, s and l). could you please post a short sample code as answer? – sharkyenergy Jun 09 '22 at 11:29
  • 1
    It's just the same as this... https://stackoverflow.com/a/50215020/2836621 Except you change this line `image[mask>0]=(0,0,255)` to `cv2.countNonZero(...)` – Mark Setchell Jun 09 '22 at 11:51
  • @MarkSetchell thank you. I updated the first post with some code. Is this how you meant= if yes, please post it as answer so i can accept it. (code not tested yet) – sharkyenergy Jun 09 '22 at 13:07
  • 1
    1) You need an outer `for` loop to iterate over your list of colours. 2) Your ranges of 0..1 for Saturation and Lightness are only going go pick up very unsaturated and dark colours - the range is 0..255. 3) Why are you only checking every 5th pixel? 4) Omit the `[0:620:5]` and do the whole image. – Mark Setchell Jun 09 '22 at 13:53
  • @MarkSetchell 1) yep working on that. it was jsut a qucik test. 2) i have read that the range is 0-1 somehwere. that is already fixed in the meantime. 3) to speed things up. i do not need a very precise value, but just to understand what colors are present in what percentage approx. 4) i have to check only a part of an image, that is why I added that – sharkyenergy Jun 09 '22 at 14:08
  • @MarkSetchell, your idea worked great in the end. could you please post it as answer, so I can accept it? thank you! – sharkyenergy Jun 13 '22 at 06:24
  • 1
    As I don't have the details of what you are trying to do, nor what you came up with as a solution, I think you are far better placed to write up the answer and grab the points yourself. You're welcome to use my suggestions obviously. – Mark Setchell Jun 13 '22 at 07:49
  • @MarkSetchell posted it. no score for me as i am the OP. I upvote your comments here. Thanks for yourhelp! – sharkyenergy Jun 13 '22 at 09:41

1 Answers1

1

I followed the advice of @Mark Setchell and came up with this solution:

The color class:

class crateColor(QObject):
cName: str
cId: int
pId: int
hHi: int
hLo: int
lHi: int
lLo: int
sHi: int
sLo: int
pxCnt: int
perc: float

The adopted solution:

    green = crateColorClass.crateColor()
    green.cName = "EU green"
    green.cId = 1
    green.pId = 1
    green.hLo = 65
    green.hHi = 165
    green.lLo = 20
    green.lHi = 95
    green.sLo = 20
    green.sHi = 100
    colorList.append(green)   # REPEATING THIS FOR EACH COLOR.


    x1 = 170 # DEFINING THE AREA AND POSITION I AM INTERESTED IN AND EVERY Nth. PIXEL
    x2 = 470
    y1 = 520
    y2 = 610
    i = 5

    dx = x2-x1
    dy = y2-y1
    a = int(dx/i)*int(dy/i)


    for c in colorList:
         if c.hLo > c.hHi: # wrap around 360 for red.
             Lo = np.array([c.hLo, c.lLo*2.55, c.sLo*2.55]) # *2.55 to have S and L 0 to 100
             Hi = np.array([359, c.lHi*2.55, c.sHi*2.55])
             px = cv2.inRange(hls[y1:y2:i, x1:x2:i], Lo, Hi)
             c.pxCnt = cv2.countNonZero(px)
             Lo = np.array([0, c.lLo * 2.55, c.sLo * 2.55])
             Hi = np.array([c.hHi, c.lHi * 2.55, c.sHi * 2.55])
             px = cv2.inRange(hls[y1:y2:i, x1:x2:i], Lo, Hi)
             c.pxCnt = c.pxCnt + cv2.countNonZero(px)
             c.perc = (c.pxCnt/a)*100
         else:
             Lo = np.array([c.hLo, c.lLo*2.55, c.sLo*2.55])
             Hi = np.array([c.hHi, c.lHi*2.55, c.sHi*2.55])
             px = cv2.inRange(hls[y1:y2:i, x1:x2:i], Lo, Hi)
             c.pxCnt = cv2.countNonZero(px)
             c.perc = (c.pxCnt/a)*100
         print("cName, cId, perc, pxCnt: ", c.cName, c.cId, c.perc, c.pxCnt)
sharkyenergy
  • 3,842
  • 10
  • 46
  • 97