Home > Mobile >  Count pixel color in an image
Count pixel color in an image

Time:03-09

I have images with only 4 colors. The colors are described in a numpy array.

self.colors = np.array([[255,255,255], [0,0,255], [255, 0, 0], [0,255,0]])

I want to count the occurence of the color in every image. For example, in one image, i have 5550 pixels with color [255,255,255], 3521 with colors [0,0,255] and so on.

I've tried different thing by looking at stackoverflow or opencv forum, but nothing seems to work.

I somehow managed to do something, but it's slow.

def countColors(self, image): 
    start_time = time.time()

    colors_Count = {}
    for color in self.colors:
        colors_Count[str(color)] = 0   
    for y in range(0, image.shape[1]):
        for x in range(0, image.shape[0]):
            try:
                colors_Count[str(image[x][y])] = colors_Count[str(image[x][y])]   1
            except:
                print('Error at pixel :', x, y)  
                return
    print(time.time() - start_time, "seconds")
    return colors_Count

It returns me a dict, which is perfect.

{'[255 255 255]': 35741,
'[  0   0 255]': 5020,
'[255   0   0]': 3869,
'[  0 255   0]': 5616}

The problem is.. it takes like 3-4 seconds per image on a big CPU. It's such a waste of time.

What could I use to improve this ?

CodePudding user response:

With the help of crackanddie, I was able to improve my solution.

If anybody is looking to count pixel like me very fast, here is my new code :

    def countColors(self, image): 
    start_time = time.time()
    colors_Count = {}

    for i in range(len(self.colors)):
        tmp = cv.inRange(image, self.colors[i], self.colors[i])
        count = cv.countNonZero(tmp)
        colors_Count[str(self.colors[i])] = count
        
    print(time.time() - start_time, "seconds")
    return colors_Count

Thank you again crackanddie, I was so stuck ahah

CodePudding user response:

PIL package has a function that counts all colors really fast. if you care only to count specific colors, just filter the response. As for run time, on small images both function (PIL and yours) are almost the same but on big images (I checked 1000,1000,3) PIL is a bit faster. The big advantage of using PIL is that there's no need to specify colors.

def count_colors_2(cv_img: np.array) -> list:  # no need to give colors
    from PIL import Image
    start_time = time.time()
    pil_image = Image.fromarray(cv_img)
    colors_count_list = pil_image.getcolors()
    print('count_colors_2 time elapsed: {:.10f}s'.format(time.time() - start_time))
    for count, c_bgr in colors_count_list:
        print('\tcolor {} appeared {} times'.format(c_bgr, count))
    return colors_count_list

time and output check (yours is count_colors_1 and PIL is 2)

image dims (1000, 1000, 3)
count_colors_1 time elapsed: 0.0039894581s
    color [0 0 0] appeared 500000 times
    color [255 255 255] appeared 250000 times
    color [  0   0 255] appeared 250000 times
count_colors_2 time elapsed: 0.0029892921s
    color (255, 255, 255) appeared 250000 times
    color (0, 0, 0) appeared 500000 times
    color (0, 0, 255) appeared 250000 times
  • Related