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:

I also have tried using the canny edge detection so that I could get rid of manually setting the hsv range. Though, I don’t know what syntax or function should I use to set the color sequence by getting the pixels on each wire.

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

Is it okay if you can expound on how do I work out your suggestion on " looks between edges what color is present and make an array[ wire color 1, wirecolor 2, … ]." Thanks for these detailed suggestion.

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.

1 Like

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)

@2ant I would like to ask if what function have you used to locate the coordinate of the middle part of pair points of wire. In this part,

10

I have been trying to figure that out. As you can see, I don’t think the code I tried in getting the pixel at horizontal row is correct basing from the picture of my output. I was confused as to why the output is like that.

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.

@2ant Thank you for the help, I tried to run your code but I have this output instead.

May I ask for some breakdown with the syntax you have made? I do get the pre-processing code but the logic for the indices and while loop some I still don’t fully comprehend.

Will surely update here once I tried to successfully math both the input and reference image. Again, thanks for your response it helped a lot.

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

I’m really grateful for your help. I am currently taking courses on basics of python so I now understood the logic especially the listings and dictionaries that you have presented. I have this project on hold for now, will surely update you with my finished code soon. Again, thank you so much for being generous and helpful.

1 Like