Verifying and Matching the Color Sequence of Wires using Python

I am new to coding and not that familiar with working with opencv and python but right now, I have this progress with my project where I have detected each wire. I was able to do this by coding the hsv color range of each wire, mask and label them with their respective color.
So what I wanted to ask help is how do I match and say that the sequence is correct.

Note that my input is coming from a real-time video camera and I’ll be getting the frame and compare it with a reference image which contains the correct color sequence.

As we can see, from the reference image, the last wire should be gray, but the input has an orange wire. Therefore, the output frame labeled the last wire of orange as “incorrect wire”

Here’s my sample code where red wire is detected.

import cv2
import numpy as np
import imutils

frame = cv2.imread('Template.jpg')
frame = cv2.resize(frame, (450,450))
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

***#Identifying HSV Range***
***#RED***
lr = np.array([0, 150, 0],np.uint8)
ur = np.array ([3, 255, 255],np.uint8)

***#THRESHOLDING***
red_mask = cv2.inRange(hsv, lr, ur)
resultr = cv2.bitwise_and(frame,frame, mask=red_mask)

***#CONTOURING***
contours_r = cv2.findContours(red_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours_r = imutils.grab_contours(contours_r)
for c in contours_r:
    area_r= cv2.contourArea(c)
    if area_r>2000:
        M = cv2.moments(c)
        cx = int(M['m10']/M['m00'])
        cy = int(M['m01']/M['m00'])
        cv2.circle(frame, (cx,cy), 4, (0, 255, 0), -1) #Defines the size of the white circle
        cv2.putText(frame, 'Red', (cx-20, cy-20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 1)

cv2.imshow("Result", np.hstack([frame, resultr]))
cv2.waitKey(0)

related:

If the wire are always vertical like this you could look between each edge what color are the pixels.

-detect edges
-looks between edges what color is present and make an array[ wire color 1, wirecolor 2, … ]
-loop throught the array ands compare each wirecolor to the expected color
-in the loop, if not correct do your red circle + text

I spent some time on it and i found a solution.

My idea was that when you have your canny image:

If you look at one horizontal line you have pairs of white points.

If you look at the coordinate in the middle of each pair of points in your color image you can check the color of the pixel.

I get those kind of results:

Wire 1
BGR color : [ 54  93 225]
RGB color : (225, 93, 54)
Wire 2
BGR color : [153  72  97]
RGB color : (97, 72, 153)
Wire 3
BGR color : [222 152  61]
RGB color : (61, 152, 222)
Wire 4
BGR color : [ 51  70 113]
RGB color : (113, 70, 51)
Wire 5
BGR color : [ 69  76 225]
RGB color : (225, 76, 69)
Wire 6
BGR color : [53 55 56]
RGB color : (56, 55, 53)
Wire 7
BGR color : [ 83 121  25]
RGB color : (25, 121, 83)
Wire 8
BGR color : [ 72 112 248]
RGB color : (248, 112, 72)

You can do that for both your images and compare the hsv values.

if color of wire 1 of image A is in range of color of wire 1 of image B then wire 1 is OK.

2 Likes

Thanks for the effort of trying this out. I would like to share that I am also working on right now with getting the wire pixels by trying to get the horizontal row of pixels (in the vertical center of the image).

I have tried using this code:

rows =image.shape[0]
middle_row =image[rows//2]
midrow =cv2.resize(middle_row,(600,360))
cv2.imshow("MidRow", midrow)

and this is the output:
9

This is the code of my entire work for the canny edge detection btw.

import cv2
image= cv2.imread('Template.jpg')
gray= cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5,5),0)
_, bin = cv2.threshold(gray,120,255,1) 
bin = cv2.dilate(bin, None)  
bin = cv2.dilate(bin, None)
bin = cv2.erode(bin, None)   
bin = cv2.erode(bin, None)
edges= cv2.Canny(gray, 50,200)

cv2.imshow("Image", original_image)
cv2.imshow("Grayscale", gray)
cv2.imshow("Edges", edges)

When you have your canny image you have an array of black and white pixels, if you look at only one row you can get the coordinate of each edge of the wire and deduce the coordinate that is equally distant from each edge.

You do that x number of times where X is your number of contours.

import cv2
import numpy as np

image = cv2.imread("wire.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

blurred = cv2.GaussianBlur(gray, (5,5), 0)
edged = cv2.Canny(blurred, 50, 200)

indices = np.where(edged == [255])

coordinates = zip(indices[0], indices[1])
listing = list(coordinates)
mylist = list(dict.fromkeys(listing))

i = 0
j = 1

x = 100

contours, _ = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
image_copy = image.copy()

cv2.drawContours(image_copy, contours, -1, (0, 255, 0), 2)
print(len(contours), "objects were found in this image.")

number_of_egdes = len(contours) + 1

while i < number_of_egdes:

  print("Wire " + str(j))

  middle = int((mylist[i][0]) + (mylist[i + 1][1] - mylist[i][1]) / 2)

  middle_point = (20, mylist[i][1] + middle)

  cv2.circle(edged, (middle_point[1], middle_point[0]), 3, (251, 3, 213), 2)

  x = middle_point[0]

  y = middle_point[1]

  bgrcolor = image[x, y]

  print("BGR color : " + str(bgrcolor))

  rgbcolor = (bgrcolor[2], bgrcolor[1], bgrcolor[0])

  print("RGB color : " + str(rgbcolor))

  i += 2
  j += 1

cv2.imshow("Dilated image", edged)
cv2.imshow("contours", image_copy)
#cv2.imshow("contours", image)
cv2.waitKey(0)

This code gave me the output that i posted.

Tell me if you need more help.

I am interested in your complete solution, if you could post it it would be nice.

My method to come up with the logic was to use a simpler image where i know what the results are :

white2

and i used print() a LOT


import cv2
import numpy as np

image = cv2.imread("white2.png")

indices = np.where(image == [255])  # check for a value of 255 ( white ) in the entire image

coordinates = zip(indices[0], indices[1]) # assemble the Y and X like this (y,x)
listing = list(coordinates)           # make a list so i can use indexes 1/2  ( i don't know why values are each present 3 times )
mylist = list(dict.fromkeys(listing)) # make a list so i can use indexes 2/2  ( fixe the triple values )
#print(listing)
#print(mylist)

i = 0

number_of_egdes = 4

while i < number_of_egdes:
  print(mylist[i])    # coordinates of first white point of the first line ( left edge of first wire )
  print(mylist[i+1])  # coordinates of second white point of the first line ( right edge of first wire )

  #print(mylist[i][0])
  #print(mylist[i+1][0])

  print(mylist[i][1])   # X coordinate of first white point of the first line ( 3 )
  print(mylist[i+1][1]) # X coordinate of second white point of the first line ( 7 )

  print((mylist[i + 1][1] - mylist[i][1]) / 2) # distance between the points divided by 2 ( 4px space / 2 = 2.0)

  print((mylist[i][1]) + (mylist[i + 1][1] - mylist[i][1]) / 2) # X coordinate of middle point in float ( 7 - 2.0 = 5.0 )

  middle = int((mylist[i][0]) + (mylist[i + 1][1] - mylist[i][1]) / 2) # distance between the points divided by 2 but cast as integer

  print(middle)

  middle_point = (mylist[i][0], mylist[i][1]+ middle) # X coordinate of the actual middle point ( 0,7 - 2 on the X axis = 0,5 )

  print(middle_point)

  x = middle_point[0]

  y = middle_point[1]

  bgrcolor = image[x,y]

  print(bgrcolor)

  rgbcolor = (bgrcolor[2],bgrcolor[1],bgrcolor[0] ) #invert the color manually

  print(rgbcolor)

  i += 2

1 Like