import streamlit as st import torch from PIL import Image import matplotlib.pyplot as plt from safetensors.torch import load_model from transformers import pipeline import torch, cv2 from torch import nn import numpy as np from torch.nn import functional as func_nn from einops import rearrange from huggingface_hub import PyTorchModelHubMixin from torchvision import models def read_image(img, img_size=100): img = np.array(img) img = cv2.resize(img, (img_size, img_size)) # resize to mathc model input here img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = img / 255.0 return img # main model network class SiameseNetwork(nn.Module, PyTorchModelHubMixin): def __init__(self): super().__init__() # convolutional layer/block # self.convnet = MobileNet() self.convnet = models.mobilenet_v2(pretrained=True) # pretrained backbone num_ftrs = self.convnet.classifier[1].in_features # get the first deimnesion of model head self.convnet.classifier[1] = nn.Linear(num_ftrs, 512) # change/switch backbone linear head # fully connected layer for classification self.fc_linear = nn.Sequential( nn.Linear(512, 128), nn.ReLU(inplace=True), # actvation layer nn.Linear(128, 2) ) def single_pass(self, x) -> torch.Tensor: # sinlge Forward pass for each image x = rearrange(x, 'b h w c -> b c h w') # rearrange to (batch, channels, height, width) to match model input output = self.convnet(x) output = self.fc_linear(output) return output def forward(self, input_1: torch.Tensor, input_2: torch.Tensor) -> torch.Tensor: # forward pass of first image output_1 = self.single_pass(input_1) # forward pass of second contrast image output_2 = self.single_pass(input_2) return output_1, output_2 # pretrained model file model_file = 'model.safetensors' #config.safetensor_file # Function to compute similarity def compute_similarity(output1, output2): return torch.nn.functional.cosine_similarity(output1, output2).item() # Function to visualize feature heatmaps def visualize_heatmap(model, image): model.eval() x = image#.unsqueeze(0) # remove batch dimension features = model.convnet.features(x) # feature heatmap learnt by model heatmap = features.detach().numpy() #.squeeze() normalize heatmap to ndarray plt.imshow(heatmap, cmap="hot") # display heatmap as plot plt.axis("off") return plt # Load the pre-trained model from safeetesor file def load_pipeline(): model_file = 'model.safetensors' #config.safetensor_file # model_id = 'tensorkelechi/signature_mobilenet' model = SiameseNetwork() # model class/skeleton # model.load_state_dict(torch.load(model_file)) load_model(model, model_file) # model = pipeline('image-classification', model=model_id, device='cpu') # model.eval() print(model) return model #.to('cpu') # Streamlit app UI template st.title("Signature Forgery Detection") st.write('Application to run/test signature forgery detecton model') st.subheader('Compare signatures') # File uploaders for the two images original_image = st.file_uploader( "Upload the original signature", type=["png", "jpg", "jpeg"] ) comparison_image = st.file_uploader( "Upload the signature to compare", type=["png", "jpg", "jpeg"] ) def run_model_pipeline(model, original_image, comparison_image, threshold=0.3): if original_image is not None and comparison_image is not None: # ensure both images are uploaded # Preprocess images img1 = Image.open(original_image).convert("RGB") # load images from file paths to PIL Image img2 = Image.open(comparison_image).convert("RGB") # read/reshape and normalize as numpy array img1 = read_image(img1) img2 = read_image(img2) # convert to tensors and add batch dimensions to match model input shape img1_tensor = torch.unsqueeze(torch.as_tensor(img1), 0) img2_tensor = torch.unsqueeze(torch.as_tensor(img2), 0) st.success('images loaded') # Get model embeddings/probabilites output1, output2 = model(img1_tensor.float(), img2_tensor.float()) st.success('outputs extracted') # Compute similarity similarity = compute_similarity(output1, output2) # Determine if it's a forgery based on determined threshold is_forgery = similarity < threshold # Display results st.subheader("Results") st.write(f"Similarity: {similarity:.2f}") st.write(f"Classification: {'Forgery' if is_forgery else 'Genuine'}") # Display images col1, col2 = st.columns(2) # GUI columns with col1: st.image(img1, caption="Original Signature", use_column_width=True) with col2: st.image(img2, caption="Comparison Signature", use_column_width=True) # # Visualize heatmaps from extracted model features # st.subheader("Feature Heatmaps") # col3, col4 = st.columns(2) # with col3: # x1 = rearrange(img1_tensor.float(), 'b h w c -> b c h w') # fig1 = visualize_heatmap(model, x1) # st.pyplot(fig1) # with col4: # x2 = rearrange(img2_tensor.float(), 'b h w c -> b c h w') # fig2 = visualize_heatmap(model, x2) # st.pyplot(fig2) else: st.write("Please upload both the original and comparison signatures.") # Run the model pipeline if a button is clicked if st.button("Run Model Pipeline for images"): model = load_pipeline() # button click to process images # if st.button("Process Images"): run_model_pipeline(model, original_image, comparison_image)