# imports
import streamlit as st
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import image
from PIL import Image
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.preprocessing import image
# import subprocess
# import sys
# def install(package):
# subprocess.check_call([sys.executable, "-m", "pip", "install", package])
# install('opencv-python')
# install('imutils')
import cv2
import imutils
st.set_page_config(page_title="PCB Inspector",
page_icon="🔍",
# initial_sidebar_state="expanded",
# layout="wide"
)
st.markdown("
🔍 PCB Inspector 🔍
", unsafe_allow_html=True)
# st.image("https://github.com/simonmayer90/python-deep-learning-image-recognition/raw/4d89104da41a027d2d6730f70761eb7e23e37fe1/pcb-image.jpg")
st.markdown("""
### Please upload the image of the template PCB:
"""
)
uploaded_template_img = st.file_uploader("Choose a file", key=1)
st.markdown("""
### Please upload the image of the test PCB:
"""
)
uploaded_test_img = st.file_uploader("Choose a file", key=2)
# transformNeeded = st.checkbox('The test PCB is rotated / has another image size.')
inspectButton = st.button('Inspect!')
cnn = keras.models.load_model("cnn_model2.h5", compile=False)
if inspectButton == 1:
template_img = Image.open(uploaded_template_img)
test_img = Image.open(uploaded_test_img)
converted_template_img = np.array(template_img.convert('RGB'))
converted_test_img = np.array(test_img.convert('RGB'))
cv2.imwrite("template.jpg", converted_template_img)
cv2.imwrite("test.jpg", converted_test_img)
rgb_template_img = cv2.imread('template.jpg')
rgb_test_img = cv2.imread('test.jpg')
# read images as grayscale
gray_template_img = cv2.cvtColor(rgb_template_img, cv2.COLOR_BGR2GRAY)
gray_test_img = cv2.cvtColor(rgb_test_img, cv2.COLOR_BGR2GRAY)
# Rotation
MAX_FEATURES = 500
GOOD_MATCH_PERCENT = 0.2
# Detect ORB features and compute descriptors.
orb = cv2.ORB_create(MAX_FEATURES)
keypoints1, descriptors1 = orb.detectAndCompute(gray_test_img, None)
keypoints2, descriptors2 = orb.detectAndCompute(gray_template_img, None)
# Match features. Matcher takes normType, which is set to cv2.NORM_L2 for SIFT and SURF, cv2.NORM_HAMMING for ORB, FAST and BRIEF
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(descriptors1, descriptors2)
# sort matches
matches = sorted(matches, key=lambda x: x.distance)
# Remove not so good matches
numGoodMatches = int(len(matches) * GOOD_MATCH_PERCENT)
matches = matches[:numGoodMatches]
# Draw top matches
imMatches = cv2.drawMatches(rgb_test_img, keypoints1, rgb_template_img, keypoints2, matches, None)
# Extract location of good matches
points1 = np.zeros((len(matches), 2), dtype=np.float32)
points2 = np.zeros((len(matches), 2), dtype=np.float32)
for i, match in enumerate(matches):
points1[i, :] = keypoints1[match.queryIdx].pt
points2[i, :] = keypoints2[match.trainIdx].pt
# Find homography
h, mask = cv2.findHomography(points1, points2, cv2.LMEDS)
# Use homography
height, width, channels = rgb_template_img.shape
rgb_test_img_transf = cv2.warpPerspective(rgb_test_img, h, (width, height))
# cut border
width = rgb_template_img.shape[1]
height = rgb_template_img.shape[0]
rgb_template_img = rgb_template_img[10:height-10, 10:width-10]
rgb_test_img_transf = rgb_test_img_transf[10:height-10, 10:width-10]
rgb_test_img_transf_show = rgb_test_img_transf.copy()
# read images as grayscale
gray_template_img = cv2.cvtColor(rgb_template_img, cv2.COLOR_BGR2GRAY)
gray_test_img_transf = cv2.cvtColor(rgb_test_img_transf, cv2.COLOR_BGR2GRAY)
# Gaussian blur to blur the image before thresholding
blur_template_img = cv2.GaussianBlur(gray_template_img, (3,3),0)
blur_test_img = cv2.GaussianBlur(gray_test_img_transf, (3,3),0)
# Adaptive thresholding(mean)
# Thresholding is used to turn a grayscale image into a binary image based on a
# specific threshold value
template_adap_thresh = cv2.adaptiveThreshold(blur_template_img, 255,
cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY, 11, 2)
test_adap_thresh = cv2.adaptiveThreshold(blur_test_img, 255,
cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY, 11, 2)
# Image subtraction (template - test)
sub_img= cv2.subtract(template_adap_thresh, test_adap_thresh)
# Median blur to eliminate background noise
blur_img = cv2.medianBlur(sub_img, 9)
# diff = cv2.absdiff(template_adap_thresh, test_adap_thresh)
# diff = cv2.absdiff(template_img_resize, test_img)
# thresh = cv2.threshold(final_img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
# dilation to make defected areas bigger
kernel = np.ones((5,5), np.uint8)
dilate_img = cv2.dilate(blur_img, kernel, iterations=14)
contours = cv2.findContours(dilate_img.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = imutils.grab_contours(contours)
for contour in contours:
if cv2.contourArea(contour) > 100:
x, y, w, h = cv2.boundingRect(contour)
cv2.rectangle(rgb_template_img, (x,y), (x+w, y+h), (255,0,0), 3)
cv2.rectangle(rgb_test_img_transf, (x,y), (x+w, y+h), (255,0,0), 3)
crop_defect = rgb_test_img_transf[y:y+h, x:x+w]
cv2.imwrite("crop_defect.jpg", crop_defect)
test_image = image.load_img("crop_defect.jpg", target_size = (64, 64))
test_image = image.img_to_array(test_image)
test_image = np.expand_dims(test_image, axis = 0)
result = cnn.predict(test_image)
if np.argmax(result) == 0:
prediction = 'Missing_hole'
elif np.argmax(result) == 1:
prediction = 'Mouse_bite'
elif np.argmax(result) == 2:
prediction = 'Open_circuit'
elif np.argmax(result) == 3:
prediction = 'Short'
elif np.argmax(result) == 4:
prediction = 'Spur'
elif np.argmax(result) == 5:
prediction = 'Spurious_copper'
else:
prediction = 'Unknown_defect'
cv2.putText(rgb_test_img_transf, prediction, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (255,0,0), 3)
# x = np.zeros((360, 10, 3), np.uint8)
# result = np.hstack((rgb_template_img, x, rgb_test_img))
# st.markdown("""
# ## Template PCB:
# """
# )
# st.image(converted_template_img)
# st.markdown("""
# ## Test PCB:
# """
# )
# st.image(converted_test_img)
# st.markdown("""
# ## Matches between Template and Test PCB:
# """
# )
# st.image(imMatches)
# st.markdown("""
# ## Transformed Template PCB:
# """
# )
# st.image(blur_template_img)
# st.image(template_adap_thresh)
# st.markdown("""
# ## Transformed Test PCB:
# """
# )
# st.image(rgb_test_img_transf_show)
# st.image(blur_test_img)
# st.image(test_adap_thresh)
# st.markdown("""
# ## Substraction of Images:
# """
# )
# st.image(sub_img)
# st.image(blur_img)
# st.image(dilate_img)
# st.markdown("""
# ## Areas of defects:
# """
# )
# st.image(rgb_template_img)
# contour detection to get the count of defects
cnts = cv2.findContours(dilate_img, cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)[-2]
blobs = []
for cnt in cnts:
if 0Oh no! ☹ There are {len(blobs)} defects in your PCB:
"""
st.markdown(html_str, unsafe_allow_html=True)
# st.text("Number of defects in Test PCB:")
# st.text(len(blobs))
st.image(rgb_test_img_transf)