PV Solar module anomaly detection interactive application

Shuvam Das
deepkapha notes
Published in
10 min readMar 14, 2023

Utilizing Different Libraries in Python to Perform a Specific Task

import os
import io
import cv2
import matplotlib.pyplot as plt
import numpy as np
import requests
import streamlit as st
from PIL import Image

The code snippet provided in Python is a great example of how different libraries can be used together to perform a specific task. The code imports several libraries, each of which provides specific functionalities to the code. For instance, the os library is used to interact with the operating system, allowing the code to access and manipulate files and directories on the computer.

Similarly, the io library is used to handle binary data in a convenient way, allowing the code to read and write bytes from and to memory buffers, files, and sockets. The cv2 library is used for image and video processing, object detection, and machine learning algorithms, while the matplotlib.pyplot library is used for data visualization in various forms such as line plots, scatter plots, and histograms.

The numpy library is used for numerical computing, providing a way to perform mathematical and logical operations on arrays and matrices. The requests library is used to send HTTP requests, allowing the code to send GET, POST, PUT, DELETE, etc. requests to web servers and receive responses.

Utilizing Libraries to Develop a Class for Image Prediction using API Endpoint

The streamlit library is used for creating interactive web applications in just a few lines of code, making it easier to develop and deploy web-based applications. Finally, the PIL library is used for opening, manipulating, and saving various image file formats.

class JUA():
def __init__(self, image1, url='https://1ei5j2kto9.execute-api.us-east-1.amazonaws.com/prod/predict',
headers={'accept': 'application/json'}):
self.url = url
self.image1 = image1
self.headers = headers
def predict(self):
with open(self.image1, 'rb') as image:
response = requests.post(self.url, headers=self.headers,
files={'file': (self.image1, image, 'image/png')})
if response.status_code == 200:
try:
result = response.json()['prediction']
return result
except JSONDecodeError as e:
print("Error decoding JSON:", e)
print("Response content:", response.content)
else:
print('Failed to call the API, status code:', response.status_code)
print('Response content:', response.content)

The code defines a class named JUA, which takes three parameters: image1, url, and headers. The class has a constructor method init() which initializes the instance variables url, image1, and headers with the values passed as parameters. The predict() method of the class is responsible for sending the API request to the specified endpoint and returning the predicted result.

The predict() method first opens the image file in binary mode using the open() function and then sends a POST request to the API endpoint using the requests.post() function. The headers and files parameters are passed to the requests.post() function to send the HTTP headers and the image file respectively.

If the response status code is 200 (i.e., the API request was successful), the method tries to decode the JSON response and return the ‘prediction’ value. If the JSON decoding fails, the method prints an error message along with the response content. If the response status code is not 200, the method prints an error message along with the response content.

Overall, the code is designed to predict an outcome using an API endpoint and an image file as input. The JUA class encapsulates the logic for sending the API request and parsing the response, making it easier to use the API in other parts of the code. The other libraries such as numpy, matplotlib, and streamlit provide additional functionalities for data processing, visualization, and web application development.

Developing a Function to Analyze and Plot Histograms of Anomaly Values in Images

def plot_histograms(anomalies, img):
# Sort the anomaly types by frequency in descending order
anomalies_sorted = dict(sorted(anomalies.items(), key=lambda item: item[1], reverse=True))
# Plot the histogram
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(20, 8), facecolor='#f5f5f5')
fig.subplots_adjust(wspace=0.3, hspace=0.1)
fig.patch.set_facecolor('#FFDDE1')
# Load the image and display it in the left subplot
img = cv2.imread(img)
ax1.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
ax1.set_title('Image', fontsize=16, fontweight='bold')
ax1.set_xticks([])
ax1.set_yticks([])

The code snippet provided describes a function named plot_histograms that is used to analyze an image and plot histograms of the anomaly values. The function takes two arguments: anomalies, which is a dictionary containing the frequency of each anomaly type in the image, and img, which is the path of the image file to be analyzed.

To begin with, the function sorts the anomalies dictionary in descending order based on the frequency of occurrence of each anomaly type in the image. This sorted dictionary is stored in the variable anomalies_sorted. Next, the function creates a figure with three subplots using the subplots function of the matplotlib.pyplot library. The first subplot is used to display the input image, the second subplot displays a bar chart of the anomaly types and their frequency, and the third subplot displays a pie chart of the anomaly type percentage.

The cv2.imread function is then used to read the input image file specified by the img parameter, and cv2.cvtColor is used to convert the color space of the image from BGR to RGB. The image is then displayed in the left subplot using the imshow function.

Creating Bar and Pie Charts to Analyze Anomalies in Images

# Create a bar chart in the right subplot
x_pos = np.arange(len(anomalies_sorted))
ax2.bar(x_pos, anomalies_sorted.values(), color=['#FA8072', '#87CEFA', '#90EE90', '#FFDAB9', '#C6E2FF'])
ax2.set_xticks(x_pos)
ax2.set_xticklabels(anomalies_sorted.keys(), fontsize=14, fontweight='bold', rotation=45, ha='right')
ax2.set_xlabel('Anomaly Types', fontsize=14, fontweight='bold')
ax2.set_ylabel('Percentage', fontsize=14, fontweight='bold')
ax2.set_title(' Anomaly Types of PV type', fontsize=16, fontweight='bold')
# Create a pie chart in the right subplot
total_anomalies = sum(anomalies.values())
anomaly_percentages = [(anomaly_freq / total_anomalies) * 100 for anomaly_freq in anomalies_sorted.values()]
ax3.pie(anomaly_percentages, labels=anomalies_sorted.keys(), autopct='%1.1f%%', startangle=90,
colors=['#FA8072', '#87CEFA', '#90EE90', '#FFDAB9', '#C6E2FF'])
ax3.set_title('Anomaly Type Percentage', fontsize=16, fontweight='bold')
plt.tight_layout(pad=3)
plt.draw()
plt.pause(0.001)
# Clear the output
from IPython.display import clear_output
clear_output(wait=True)

In the right subplot, a bar chart is created using the bar function of matplotlib.pyplot. The x_pos variable contains an array of integers ranging from 0 to the number of anomaly types in the anomalies_sorted dictionary. The anomalies_sorted.values() function is used to get the frequency of each anomaly type, and the color parameter is used to specify the color of each bar in the chart. The set_xticks function is used to set the location of the x-ticks, and the set_xticklabels function is used to set the labels of the x-ticks to the keys of the anomalies_sorted dictionary. The set_xlabel, set_ylabel, and set_title functions are used to set the labels and title of the chart.

In the third subplot, a pie chart is created using the pie function of matplotlib.pyplot. The anomaly_percentages variable contains a list of the percentage of each anomaly type, calculated by dividing the frequency of each anomaly type by the total number of anomalies and multiplying by 100. The labels parameter is used to set the labels of the pie chart to the keys of the anomalies_sorted dictionary. The autopct parameter is used to set the format of the percentage values displayed in the chart. The startangle parameter is used to set the angle at which the first wedge is drawn, and the colors parameter is used to set the color of each wedge in the chart. The set_title function is used to set the title of the chart.

After creating the three subplots, the plt.tight_layout function is used to adjust the spacing between them, and plt.draw and plt.pause functions are used to display the plot. Finally, the clear_output function of the IPython.display library is used to clear the output of the previous plot.

Building a Solar Panel Anomaly Detection Web Application using Streamlit Library in Python

The code provided is a Python script for a web application that detects anomalies in solar panels using image analysis. The script uses the Streamlit library to build a user interface for the web application. Streamlit is a powerful open-source framework that enables the creation of interactive web applications in Python with minimal effort.

The first section of the code sets the page configuration of the application. The set_page_config() function sets the title of the page, the icon that appears in the browser tab, and the layout of the page. In this case, the title is set to “JUA Image Anomaly Detection”, and the icon is set to a camera with flash. The layout of the page is set to “wide”, which means that the page will have more horizontal space.

def main():
# Set the title and page layout
st.set_page_config(page_title="JUA Image Anomaly Detection", page_icon=":camera_with_flash:", layout="wide")
import base64
def add_bg_from_local(image_file):
with open(image_file, "rb") as image_file:
encoded_string = base64.b64encode(image_file.read())
st.markdown(
f"""
<style>
.stApp {{
background-image: url(data:image/{"png"};base64,{encoded_string.decode()});
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}}
.icon {{
background-image: url('https://cdn-icons-png.flaticon.com/512/7976/7976202.png');
background-size: contain;
background-repeat: no-repeat;
width: 48px;
height: 48px;
display: inline-block;
margin-right: 10px;
}}
</style>
""",
unsafe_allow_html=True
)
st.markdown(
"<div class='icon'></div><p style='color: white; font-weight: bold;font-family: Times New Roman, sans-serif: display: inline;'>Assen, Netherlands</p>",
unsafe_allow_html=True)

The next section of the code defines a function called add_bg_from_local(). This function takes an image file as an input and adds it as the background image of the web application. The function uses the base64 library to encode the image file in base64 format, which is required to add it to the web application. The function then adds the encoded image to the CSS style of the web application using the background-image property. The background-size, background-position, and background-repeat properties are also set to control the appearance of the background image. Finally, the function adds an icon and a text element to the web application using the markdown() function. The icon is a camera, and the text is the name of a city.

The add_bg_from_local() function is called with the argument “field.png”. This means that the “field.png” image file will be used as the background image of the web application.

Creating a Sidebar and Image Upload Functionality in a Solar Panel Anomaly Detection Web Application.

The next section of the code creates a sidebar for the web application using the sidebar() function. The sidebar contains a title, a header, and a text element. The title is “GS Solar”, which is the name of the application. The header is “Module Anomaly Detection”, which describes the purpose of the application. The text element provides instructions to the user on how to use the application. The selectbox() function creates a dropdown menu with two options: “Upload an image” and “Choose from preloaded images”.

st.sidebar.title('GS Solar')
st.sidebar.header("Module Anomaly Detection")
st.sidebar.text(" Upload your module's image \n or select from the preloaded images \n to view it and detect the possible \n anomalies that your module might \n be facing")
option = st.sidebar.selectbox("Select an option:", ["Upload an image", "Choose from preloaded images"])
# Add a file uploader and a dropdown for preloaded images
if option == "Upload an image":
uploaded_file = st.sidebar.file_uploader("Upload an image", type=["jpg", "jpeg", "png"])
if uploaded_file is not None:
# Open the uploaded image file
img = Image.open(uploaded_file)
img = img.resize((512, 512))
st.markdown("<p style='color: white; font-weight : 'bold'; text-align: center;'>Selected Image</p>",
unsafe_allow_html=True)
st.image(img, use_column_width=False)
st.markdown("<p style='color: white; font-weight : 'bold'; text-align: center;'>As you can see the green border in the image shows the part of the full image where the analysis is being done and the error is being detected</p>", unsafe_allow_html=True)
# Save the uploaded image to a temporary file
tmp_file_path = f"/tmp/{uploaded_file.name}"
with open(tmp_file_path, "wb") as f:
f.write(uploaded_file.getbuffer())

If the user selects “Upload an image”, the code displays a file uploader using the file_uploader() function. The file_uploader() function allows the user to select an image file from their computer. If the user uploads an image, the code opens the image file using the Image.open() function from the PIL library. The Image.open() function reads the image file and returns an Image object. The resize() function is called on the Image object to resize the image to 512x512 pixels. The st.image() function is used to display the image in the web application. The caption argument is set to “Uploaded Image”, which adds a caption to the image. The use_column_width argument is set to False, which means that the image will be displayed at its actual size. The markdown() function is used to add a text element below the image that says “Uploaded Image”.

The code then saves the uploaded image to a temporary file using the with open() statement. The temporary file is saved in the “/tmp/” directory with the same name as the uploaded file. The JUA() function is called with the path of the temporary file as an argument. The JUA() function is a custom function that analyzes the image and returns a dictionary of anomaly detection results. The predict() method is called on the JUA() object to run the anomaly detection algorithm.

A Closer Look at the main() Function in the JUA Image Anomaly Detection App

The main() function plays a crucial role in the JUA Image Anomaly Detection app, providing a user-friendly interface for detecting anomalies in solar panel images using the JUA algorithm. This function comprises several key components, including setting the title, icon, and background of the page, creating a sidebar with interactive buttons, running the JUA algorithm on the uploaded or selected image, and displaying the results in the form of a histogram and a table of anomalies.

To begin with, the main() function sets the title, icon, and background of the page to create a visually appealing and consistent user interface. It then creates a sidebar with interactive buttons that allow the user to either upload an image or select from a set of preloaded images. The sidebar is an important aspect of the app as it enables the user to quickly and easily access the app’s functionalities.

The functionality of the JUA Image Anomaly Detection App

The function then proceeds to run the JUA algorithm on the uploaded or selected image, depending on the user’s selection. This is done using various libraries and tools such as Streamlit, PIL, and base64, which help to process and analyze the image. The JUA algorithm is used to detect anomalies such as cracks, stains, and dislocations in solar panel images, which are common issues that can affect the performance of solar panels.

Once the JUA algorithm has been run on the image, the function displays the results in the form of a histogram and a table of anomalies. The histogram provides a visual representation of the distribution of anomalies in the image, while the table displays the specific details of each anomaly, including its location, size, and type. To enhance the visual presentation of the table, the function defines a custom style for the table using HTML and CSS, which is then passed to the st.write() function with the unsafe_allow_html=True parameter.

In conclusion, the main() function is a crucial component of the JUA Image Anomaly Detection app, providing an intuitive and informative user experience for detecting anomalies in solar panel images. The function utilizes a variety of tools and libraries to process and analyze the image, and the results are displayed in a clear and concise manner using a histogram and a table of anomalies. Overall, the JUA Image Anomaly Detection app represents a powerful tool for identifying and addressing issues that can affect the performance and efficiency of solar panels.

Here is the video of the working application:

Here’s the live link to the application http://3.145.64.26:8503/

Do use it, and if you find any errors feel free to contact: tannistha.maiti@deepkapha.com

--

--