Data preprocessing#

# Imports
import cv2
import glob
import numpy as np
import matplotlib.pyplot as plt
# Get all image path names
path_names = glob.glob('../data/resistor_images/*jpg')

# Select image
image = cv2.imread(path_names[0])

# Label
label = path_names[0].split('_')[-1][0:3]

# Show image
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()
../_images/3d411e76bf0aa1954e63dd290288b9492f6a5eb8bb3098d0e8e24e9cff82cc9c.png
# Convert to gray to threshold background
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Threshold background
_, threshed = cv2.threshold(image_gray, 254, 255, cv2.THRESH_BINARY_INV)

# Show threshed mask
plt.imshow(threshed, cmap='gray')
plt.show()
../_images/2e113e946a745240e42e03fd8b03acb9dc5bb5a2e88776408efe56decd8239d3.png

To remove the sticks, we use some morphological transformations.

# The kernel is chosen to be larger than the sticks, and smaller than the resistor
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15, 15))

# We open the image in order to remove the sticks
morphed_open = cv2.morphologyEx(threshed, cv2.MORPH_OPEN, kernel)

# Show opened mask
plt.imshow(morphed_open, cmap='gray')
plt.show()
../_images/c379017c5685dba5d595b31aa0befb461163a4f5323666864991fb307e727b13.png

We want to find the bounding box of the resistor. Using the binary mask, we find the contour of the resistor and obtain its bounding box.

# Find contour of resistor
contours = cv2.findContours(morphed_open, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]

# Filter contours
#contours = list(filter(lambda x: (cv2.contourArea(x) < 20000), contours)) 
#contours = list(filter(lambda x: (cv2.contourArea(x) > 5000), contours)) 

# Get largest contour
maxcontour = max(contours, key=cv2.contourArea)

# Get minimal area rectangle
rect = cv2.minAreaRect(maxcontour)

# Draw bounding box
debug_image = cv2.drawContours(image.copy(),[np.int0(cv2.boxPoints(rect))], 0, (0,0,255), 2)

# Show bounding box
plt.imshow(cv2.cvtColor(debug_image, cv2.COLOR_BGR2RGB), cmap='gray')
plt.show()
C:\Users\matth\AppData\Local\Temp\ipykernel_12240\938441542.py:15: DeprecationWarning: `np.int0` is a deprecated alias for `np.intp`.  (Deprecated NumPy 1.24)
  debug_image = cv2.drawContours(image.copy(),[np.int0(cv2.boxPoints(rect))], 0, (0,0,255), 2)
../_images/86629480a9e4c425a5451f4390564ede3167b1cb9a38511771e353646c10d877.png
# Get rectangle properties
angle = rect[2]
rows, cols = image.shape[0], image.shape[1]

# Rotate image
M = cv2.getRotationMatrix2D((rect[0][0],rect[0][1]), angle-90, 1)
image_aligned = cv2.warpAffine(image,M,(cols,rows))

# Rotate bounding box 
box = cv2.boxPoints((rect[0], rect[1], angle))
pts = np.intp(cv2.transform(np.array([box]), M))[0]    
pts[pts < 0] = 0

# Cropping
image_cropped = image_aligned[pts[0][1]:pts[3][1], pts[0][0]:pts[2][0]]

# Show cropped image
plt.imshow(cv2.cvtColor(image_cropped, cv2.COLOR_BGR2RGB), cmap='gray')
plt.show()
../_images/f21e9f9af38534d2811c87f6cccaa6c3a3e33b89d22142e0fc690a990ad28615.png

Next, we will detect the color bands using a combination of two thresholding masks.

# Get HSV calibration params 
hsvfile1 = np.load('../data/demo3_hsv_resistor.npy')
hsvfile2 = np.load('../data/demo3_hsv_background.npy')

# Convert image to HSV to simplify thresholding
hsv = cv2.cvtColor(image_cropped, cv2.COLOR_BGR2HSV)

# Remove area in between color bands
mask1 = cv2.bitwise_not(cv2.inRange(hsv, np.array([hsvfile1[0], hsvfile1[2], hsvfile1[4]]), np.array([hsvfile1[1], hsvfile1[3], hsvfile1[5]])))

# Show mask 1
plt.imshow(mask1, cmap='gray')
plt.show()

# Remove background
mask2 = cv2.inRange(hsv, np.array([hsvfile2[0], hsvfile2[2], hsvfile2[4]]), np.array([hsvfile2[1], hsvfile2[3], hsvfile2[5]]))

# Show mask 2
plt.imshow(mask2, cmap='gray')
plt.show()

# Combine effects
mask = cv2.bitwise_and(mask1, mask2)

# Show cropped image
plt.imshow(mask, cmap='gray')
plt.show()

# Morphological transformations to remove sticks
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10, 10))
morphed_open = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.morphologyEx(morphed_open, cv2.MORPH_CLOSE, kernel)

# Show cropped image
plt.imshow(mask, cmap='gray')
plt.show()
../_images/7408451900da2da7139bc239733aba66b1b8dc474124eb8fbee20d964aaac9bc.png ../_images/fd91ca8c03f1ff0989d80201eefb17954e923e9a2ade2d72fd0b8c68fe16d08f.png ../_images/484b3520a7b672b0876f527f5545044ab0ead3f8d7a235b0d1b62e3b66663105.png ../_images/3e5ba84db48e5c8f09fb9b2a96b2daf65a3081df4bc71a148d88e67e9f846500.png
# Find the three largest contours of the color bands
contours = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]

# Get three largest contours
largest_contours = sorted(contours, key=cv2.contourArea, reverse=True)[0:3]

# Sort contours from left to right
sorted_contours = sorted(largest_contours, key=lambda ctr: cv2.boundingRect(ctr)[0])

# Plot
image_cropped = cv2.drawContours(image_cropped.copy(), sorted_contours, -1, (0,255,0), 3)

# Show cropped image
plt.imshow(cv2.cvtColor(image_cropped, cv2.COLOR_BGR2RGB))
plt.show()
../_images/d599e952ab3d6ddcc8d6600f0c0cf26beeb0d7c3a14f05082fa3fbfdf7f2c33a.png
# Iterate over the three contours
color_bands = []
for ctr in sorted_contours:

    # Get roi
    x,y,w,h = cv2.boundingRect(ctr)
    roi_rgb = image_cropped[y+10:y+h-10, x+5:x+w-5]
    roi_hsv = hsv[y+10:y+h-10, x+5:x+w-5]

    # Show cropped image
    plt.imshow(cv2.cvtColor(roi_rgb, cv2.COLOR_BGR2RGB))
    plt.show()

    # Get hsv
    roi_h = [i for i in roi_hsv[:,:,0].ravel() if i != 0]  
    roi_s = [i for i in roi_hsv[:,:,1].ravel() if i != 0]  
    roi_v = [i for i in roi_hsv[:,:,2].ravel() if i != 0]  

    # Get means of HSV data
    mean_hsv = [np.mean(roi_h), np.mean(roi_s), np.mean(roi_v)]

    # Add to data
    color_bands.append(mean_hsv)
../_images/6f3e6853ce70e3a41dbce1623786648e9e6c8c3038f05114d1dab5a574317413.png ../_images/c3a802c2d5c09ebf91b8469e44d8ce384273b6a3c8fdad90caf0dda16e6f7158.png ../_images/6753c01ecf8403c53ffff702c6073bf804c2796261d0dd8acccc0c68f0aeaf81.png
# Create empty dataset
print(color_bands)

# Plot
colors = {'x':'gray','r':'red','z':'brown','k':'black','b':'blue','v':'magenta','g':'green'}
c = list(map(lambda x: colors[str(x)], list(label)))
fig = plt.figure(figsize=(12, 9))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(color_bands[:][0], color_bands[:][1], color_bands[:][2], c=c, alpha=.6, edgecolor='k', lw=0.3)
ax.set_xlabel('H', fontsize=14)
ax.set_ylabel('S', fontsize=14)
ax.set_zlabel('V', fontsize=14)
plt.show()
[[8.359375, 118.14756944444444, 127.21006944444444], [115.1256038647343, 38.64251207729468, 54.21634615384615], [2.9509954058192958, 152.59467455621302, 191.13757396449705]]
../_images/3a73dc98aab09f1fc907c193ba96e095597632412ff817cf29f6642a06f7fec1.png