George Ponta
George Ponta

Reputation: 313

Python and OpenCV colour inspecting routine is very slow

I have a program which iterates over a set of images with black background and has 7 objects of different colours.

I need to iterate over each pixel in order to find the middle x and y points by using the lower and upper boundaries of each coordinate then use these values to compute some distances.

The images are 640x480 in size and it takes about 2 seconds for each image which seems quite a lot. I have attached the code of how I am iterating through the pixels below.

def isBlack(r, g, b): return r == 0 and g == 0 and b == 0
def isRed(r, g, b): return r > 0 and g == 0 and b == 0
def isYellow(r, g, b): return r > 0 and g > 0 and b == 0 and r == g
def isOrange(r, g, b): return r > 0 and g > 0 and b == 0 and r != g
def isBlue(r, g, b): return r == 0 and g == 0 and b > 0
def isCyan(r, g, b): return r == 0 and g > 0 and b > 0
def isGreen(r, g, b): return r == 0 and g > 0 and b == 0
def isWhite(r, g, b): return r == g == b and r != 0

def getAbsoluteValues (im, side, frame):
    sizes = im.shape
    ny, nx, nc = sizes

    array_of_maxes_x = np.empty((14,))
    array_of_maxes_x[::2] = nx + 1
    array_of_maxes_x[1::2] = -1

    array_of_maxes_x = array_of_maxes_x.reshape(7, 2)
    array_of_maxes_y = array_of_maxes_x.copy()

    for idx_y, y in enumerate(im):
        for idx_x, x in enumerate(y):
            b, g, r = x
            if isBlack(r, g, b):
                continue
            elif isRed(r, g, b):
                array_of_maxes_x[0] = compareLoAndHi(idx_x, array_of_maxes_x[0])
                array_of_maxes_y[0] = compareLoAndHi(idx_y, array_of_maxes_y[0])
            elif isYellow(r, g, b):
                array_of_maxes_x[1] = compareLoAndHi(idx_x, array_of_maxes_x[1])
                array_of_maxes_y[1] = compareLoAndHi(idx_y, array_of_maxes_y[1])
            elif isOrange(r, g, b):
                array_of_maxes_x[2] = compareLoAndHi(idx_x, array_of_maxes_x[2])
                array_of_maxes_y[2] = compareLoAndHi(idx_y, array_of_maxes_y[2])
            elif isBlue(r, g, b):
                array_of_maxes_x[3] = compareLoAndHi(idx_x, array_of_maxes_x[3])
                array_of_maxes_y[3] = compareLoAndHi(idx_y, array_of_maxes_y[3])
            elif isCyan(r, g, b):
                array_of_maxes_x[4] = compareLoAndHi(idx_x, array_of_maxes_x[4])
                array_of_maxes_y[4] = compareLoAndHi(idx_y, array_of_maxes_y[4])
            elif isGreen(r, g, b):
                array_of_maxes_x[5] = compareLoAndHi(idx_x, array_of_maxes_x[5])
                array_of_maxes_y[5] = compareLoAndHi(idx_y, array_of_maxes_y[5])
            elif isWhite(r, g, b) and not isStray(im, idx_x, idx_y):
                array_of_maxes_x[6] = compareLoAndHi(idx_x, array_of_maxes_x[6])
                array_of_maxes_y[6] = compareLoAndHi(idx_y, array_of_maxes_y[6])

def compareLoAndHi(coord, current):
    if coord < current[0]: current[0] = coord
    if coord > current[1]: current[1] = coord

    return current

def isStray(im, x, y):
    values = np.array([[x, y - 1],[x, y + 1],[x - 1, y],[x + 1, y]])

    for i in range(0, 4):
        b, g ,r = im[values[i][1], values[i][0]]
        if(not isBlack(r, g, b) and not isWhite(r, g, b)):
            return True

    return False
                

I am not sure how to make this faster I've been looking at matrix routines and everything but I can't find an answer that fits my problem.

An example image is below.

enter image description here

Upvotes: 0

Views: 399

Answers (2)

Vatsal Parsaniya
Vatsal Parsaniya

Reputation: 899

You can check the colour of only detected contour.

import numpy as np
import cv2

image = cv2.imread('image.png')
cv2.imshow("image", image)

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, threshold = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)
cv2.imshow('threshold', threshold)

contours, hierarchy = cv2.findContours(threshold, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

blank_image = np.zeros_like(image)
for cnt in contours:
    M = cv2.moments(cnt)
    cX = int(M["m10"] / M["m00"])
    cY = int(M["m01"] / M["m00"])

    colour = (int(image[cY, cX, 0]), int(image[cY, cX, 1]), int(image[cY, cX, 2]))
    print(f'point: ({cX},{cY}),  color (BGR): {colour}')

    cv2.circle(blank_image, (cX, cY), 2, colour, 2)

cv2.imshow('contour_image', blank_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Output:

point: (464,219),  color (BGR): (0, 156, 213)
point: (368,220),  color (BGR): (0, 215, 0)
point: (388,197),  color (BGR): (217, 217, 217)
point: (384,176),  color (BGR): (211, 0, 0)
point: (338,176),  color (BGR): (111, 238, 238)
point: (333,171),  color (BGR): (215, 215, 0)
point: (366,143),  color (BGR): (2, 2, 216)

enter image description here


Also, you can iterate only non zero points

import numpy as np
import cv2

image = cv2.imread('image.png')
cv2.imshow("image", image)

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
X_Cordinates,Y_Cordinates = np.nonzero(gray)

print("X_Cordinates : \n", X_Cordinates)
print("\nY_Cordinates : \n", Y_Cordinates)

Output:

X_Cordinates : 
 [105 105 106 106 106 106 107 107 107 107 108 108 108 108 109 109 109 109
 110 110 126 126 126 127 127 127 127 128 128 128 128 128 129 129 129 129
 130 130 130 130 130 130 130 131 131 131 131 131 131 131 131 132 132 132
 132 132 132 132 132 133 133 133 133 133 133 133 133 134 134 134 134 134
 146 147 147 147 147 147 148 148 148 148 148 149 149 149 149 149 163 163
 163 163 163 163 163 163 164 164 164 164 164 164 164 164 164 165 165 165
 165 165 165 165 165 165 165 166 166 166 166 166 166 166 166 166 167 167
 167 167 167 167 167 167]

Y_Cordinates : 
 [274 275 273 274 275 276 273 274 275 276 273 274 275 276 273 274 275 276
 274 275 249 250 251 249 250 251 252 248 249 250 251 252 249 250 251 252
 249 250 251 253 254 288 289 252 253 254 255 287 288 289 290 252 253 254
 255 287 288 289 290 252 253 254 255 287 288 289 290 252 253 254 288 289
 291 289 290 291 292 293 289 290 291 292 293 289 290 291 292 293 275 276
 277 278 347 348 349 350 275 276 277 278 346 347 348 349 350 274 275 276
 277 278 346 347 348 349 350 275 276 277 278 346 347 348 349 350 275 276
 277 278 347 348 349 350]

Upvotes: 2

dendane djalil
dendane djalil

Reputation: 1

try to use smaller resolution for the same images like a 320x240 and see the time needed for the the iteration i think this will cut the time to the half.

Upvotes: -1

Related Questions