File size: 7,286 Bytes
fb60ae4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14f7288
384bc42
2c4ccb2
fb60ae4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a63244f
 
 
 
 
 
 
fb60ae4
be03b9c
fb60ae4
 
 
 
 
9cae907
fb60ae4
dee92a9
 
 
 
9cae907
dee92a9
 
 
 
 
 
 
fb60ae4
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import streamlit as st
from PIL import Image
from transformers import pipeline
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import xlsxwriter
import io

# Initialize session state for results, image names, and image sizes if not already present
if 'results' not in st.session_state:
    st.session_state['results'] = []
if 'image_names' not in st.session_state:
    st.session_state['image_names'] = []
if 'image_sizes' not in st.session_state:
    st.session_state['image_sizes'] = []

# Disable PyplotGlobalUseWarning
st.set_option('deprecation.showPyplotGlobalUse', False)

# Create an image classification pipeline with scores
pipe = pipeline("image-classification", model="trpakov/vit-face-expression", top_k=None)

# Streamlit app
st.title("Emotion Recognition with vit-face-expression")

# Upload images
uploaded_images = st.file_uploader("Upload images", type=["jpg", "png"], accept_multiple_files=True)

# Display thumbnail images alongside file names and sizes in the sidebar
selected_images = []
if uploaded_images:
    # Reset the image names and sizes lists each time new images are uploaded
    st.session_state['image_names'] = [img.name for img in uploaded_images]
    st.session_state['image_sizes'] = [round(img.size / 1024.0, 1) for img in uploaded_images]

    # Add a "Select All" checkbox in the sidebar
    select_all = st.sidebar.checkbox("Select All", False)
    
    for idx, img in enumerate(uploaded_images):
        image = Image.open(img)
        checkbox_key = f"{img.name}_checkbox_{idx}"  # Unique key for each checkbox
        # Display thumbnail image and checkbox in sidebar
        st.sidebar.image(image, caption=f"{img.name} {img.size / 1024.0:.1f} KB", width=40)
        selected = st.sidebar.checkbox(f"Select {img.name}", value=select_all, key=checkbox_key)         
        
        if selected:
            selected_images.append(image)

if st.button("Predict Emotions") and selected_images:
    # Predict emotion for each selected image using the pipeline
    st.session_state['results'] = [pipe(image) for image in selected_images]

# Initialize an empty DataFrame outside of the button press condition
df_emotions = pd.DataFrame()

# Generate DataFrame from results
if st.button("Generate HeatMap & DataFrame"):
    # Access the results, image names, and sizes from the session state
    results = st.session_state['results']
    image_names = st.session_state['image_names']
    image_sizes = st.session_state['image_sizes']
    if results:
        # Initialize an empty list to store all the data
        data = []

        # Iterate over the results and populate the list with dictionaries
        for i, result_set in enumerate(results):
            # Initialize a dictionary for the current set with zeros
            current_data = {
                'Happy': 0,
                'Surprise': 0,
                'Neutral': 0,
                'Sad': 0,
                'Disgust': 0,
                'Angry': 0,
                'Fear': 0,
                'Image Name': image_names[i],
                'Image Size (KB)': f"{image_sizes[i]:.1f}"  # Format the size to one decimal place
            }
            
            for result in result_set:
                # Capitalize the label and update the score in the current set
                emotion = result['label'].capitalize()
                score = round(result['score'], 4)  # Round the score to 4 decimal places
                current_data[emotion] = score
            
            # Append the current data to the data list
            data.append(current_data)

        # Convert the list of dictionaries into a pandas DataFrame
        df_emotions = pd.DataFrame(data)

        # Add a placeholder for the 'Image View' column
        df_emotions['Image View'] = [''] * len(df_emotions)
        # Add a sequence of numbers for the 'Image Num' column
        df_emotions['Image Num'] = list(range(len(df_emotions)))

        # Display the DataFrame
        st.write(df_emotions)

        # Plotting the heatmap for the first seven columns
        plt.figure(figsize=(10, 10))
        sns.heatmap(df_emotions.iloc[:, :7], annot=True, fmt=".1f", cmap='viridis')
        plt.title('Heatmap of Emotion Scores')
        plt.xlabel('Emotion Categories')
        plt.ylabel('Data Points')
        st.pyplot(plt)

        # Save the DataFrame to a CSV file without the 'Image View' and 'Image Num' columns
        df_emotions.drop(columns=['Image View', 'Image Num']).to_csv('emotion_scores.csv', index=False)
        st.success('DataFrame generated and saved as emotion_scores.csv')

        with open('emotion_scores.csv', 'r') as f:
            csv_file = f.read()

        st.download_button(
            label='Download Emotion Scores as CSV',
            data=csv_file,
            file_name='emotion_scores.csv',
            mime='text/csv',
        )

        # Create a BytesIO buffer for the Excel file
        output = io.BytesIO()

        # Create a new Excel writer object using the buffer as the file
        writer = pd.ExcelWriter(output, engine='xlsxwriter')
        df_emotions.to_excel(writer, index=False, header=True)

        # Access the xlsxwriter workbook and worksheet objects
        workbook  = writer.book
        worksheet = writer.sheets['Sheet1']

        # Set the column width and row height
        worksheet.set_column('A:G', 8)  # Set width for columns A-G
        worksheet.set_column('H:H', 22)  # Set width for column H (Image Name)   
        worksheet.set_column('I:I', 14)  # Set width for column I (Image Size)   
        worksheet.set_column('J:J', 12)  # Set width for column J (Image View)   
        worksheet.set_column('K:K', 12)  # Set width for column K (Image Num)

        
        for row_num in range(len(df_emotions) + 1):  # +1 to include the header row
            worksheet.set_row(row_num, 52)  # Set the row height to 38

        # Iterate over the images and insert them into the 'Image View' column
        for idx, image in enumerate(selected_images):
            # Convert the image to a format that can be inserted into Excel
            image_stream = io.BytesIO()
            image.save(image_stream, format='JPEG')  # image.save(image_stream, format='JPEG')  # Save the image as JPEG; or PNG
            image_stream.seek(0)
            # Calculate the scaling factor to fit the image inside the cell
            cell_width = 64
            scale_factor = cell_width / image.width
            # Insert the image into the cell
            worksheet.insert_image(f'J{idx + 2}', 'image.jpg', {      #or image.png
                'image_data': image_stream,
                'x_scale': scale_factor,
                'y_scale': scale_factor,
                'x_offset': 2,
                'y_offset': 2,
                'positioning': 1
            })

        # Close the writer object
        writer.close()

        # Rewind the buffer
        output.seek(0)

        # Use Streamlit's download button to offer the Excel file for download
        st.download_button(
            label='Download Emotion Scores as Excel',
            data=output,
            file_name='emotion_scores.xlsx',
            mime='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        )