front-end

Contents

Front-end was created with streamlit. The Folder contains : pages, textureGen

pages

ImageWeave

import streamlit as st

st.set_page_config(
   page_title="ImageWeave",
)

st.title("ImageWeave")
tab1 , tab2, tab3 = st.tabs(["Get Started" , "How to Use" , "About"])
with tab1:

   st.header(":red[Welcome!]")
   st.divider()
   st.subheader("ImageWeave is a minimal texture Generator. It let's you create any image you want to a map.")

with tab2:
   st.header(":red[How to Use.]")
   st.subheader("Upload your image using the Upload mode on left. Then choose the map you want and enjoy the generated image on our Gallery!")
   st.divider()
   st.header(":red[Dont have an image?]")
   st.subheader("Dont worry we got photos for you! Just select an image from our Gallery by choosing the mode on the left and downloading it.")

with tab3:
   st.header(":red[PyxelCollective]")
   st.subheader("PyxelCollective is the creator of this app. The team consists of 3 members (Sfinarolakis Stefanos (front-end), Tripakis Nikos(design,documentation), Kafteranis Konstantinos(back-end.textureGen)).")
   st.divider()
   st.header(":red[Github and Documentation]")
   st.subheader("Github: https://github.com/PYxelcollective/Django")
   st.subheader("Documentation:")

st.sidebar.success("Select a mode above.")

This is a Python script that uses the Streamlit library to create a web application for ImageWeave.

The st.set_page_config function sets the page title to “ImageWeave”.

The st.title function sets the main title of the web page to “ImageWeave”.

The st.tabs function creates tabs for “Get Started”, “How to Use”, and “About”. The contents of each tab are defined within a with tab: block.

Within the with tab: block, st.header is used to create a header, and st.subheader is used to create a subheader. st.divider() is used to create a horizontal line separator.

The st.sidebar.success function sets the content of the sidebar to “Select a mode above”.

app

import streamlit as st
from PIL import Image
import numpy as np
import cv2
from textureGen import height_map, normals_map, bump_map, ambient_occlusion_map

# Title of the app
st.title("Image Maps Generator")

# Upload an image
uploaded_image = st.file_uploader("Choose an image...", type=["jpg", "jpeg", "png"])

# Check if an image was uploaded
if uploaded_image is not None:
   # Display the uploaded image
   image = Image.open(uploaded_image)
   st.image(image, caption="Uploaded Image", use_column_width=True)

      # Define the options for the dropdown menu
   options = ["Select category", "Floor", "Terrain", "Metal", "Other"]

   # Add a dropdown menu for selecting the category
   category = st.selectbox("Select category", options)

   # If the user has selected "Other", display a text input for a new category
   if category == "Other":
      category = st.text_input("Enter new category")

   # If the user has selected a category, display the form
   if category != "Select category":
      name = st.text_input("Name")
      caption = st.text_input("Caption")
      category = st.write(f"Category: {category}")

   # Sidebar menu to select the maps to generate
   st.sidebar.title("Select Maps")
   height_map_checkbox = st.sidebar.checkbox("Height Map")
   normals_map_checkbox = st.sidebar.checkbox("Normals Map")
   bump_map_checkbox = st.sidebar.checkbox("Bump Map")
   ambient_occlusion_map_checkbox = st.sidebar.checkbox("Ambient Occlusion Map")

   # Generate and display the selected maps
   if st.button("Generate Maps"):
      # Convert the image to a numpy array
      img_array = np.array(image)

      # Generate the height map
      if height_map_checkbox:
            height = height_map.generate_height_map(img_array)
            st.image(height, caption="Height Map", use_column_width=True)

      # Generate the normals map
      if normals_map_checkbox:
            normals = normals_map.generate_normal_map(img_array)
            st.image(normals, caption="Normals Map", use_column_width=True)

      # Generate the bump map
      if bump_map_checkbox:
            bump = bump_map.generate_bump_map(img_array)
            st.image(bump, caption="Bump Map", use_column_width=True)

      # Generate the ambient occlusion map
      if ambient_occlusion_map_checkbox:
            ao = ambient_occlusion_map.generate_ambient_occlusion_map(img_array,0.5)
            st.image(ao, caption="Ambient Occlusion Map", use_column_width=True)

This is a Streamlit app that generates different types of image maps from an uploaded image.

The app first displays a file uploader that allows the user to upload an image. Then, it shows a dropdown menu where the user can select the category of the image. If the user selects “Other,” a text input appears so they can enter a new category. After the user selects a category, they can enter a name and caption for the image.

The app also has a sidebar menu that allows the user to select which maps they want to generate: height map, normals map, bump map, and ambient occlusion map. After the user selects the maps they want, they can click the “Generate Maps” button to generate and display the maps.

To generate the maps, the app uses functions from the textureGen module, which contains functions for generating different types of image maps, such as height maps and normal maps. The app converts the uploaded image to a NumPy array, passes it to the appropriate function to generate the selected map, and displays the resulting map using Streamlit’s st.image() function.

Editor

import streamlit as st
from PIL import Image
import numpy as np
import requests
from io import BytesIO
from textureGen import height_map, normals_map, bump_map, ambient_occlusion_map, displacement_map, diffusion_map
import base64

generated_images = []

# Title of the app
st.title("Image Maps Generator")

# URL of the Django app
django_url = "http://localhost:8000/"

# Define the options for the dropdown menu
options = ["Select category", "Floor", "Terrain", "Metal", "Other"]

# Upload an image
uploaded_image = st.file_uploader("Choose an image...", type=["jpg", "jpeg", "png"])

# Check if an image was uploaded
if uploaded_image is not None:
   # Display the uploaded image
   image = Image.open(uploaded_image)
   st.image(image, caption="Uploaded Image", use_column_width=True)

   # Add a dropdown menu for selecting the category
   category = st.selectbox("Select category", options)

   # If the user has selected "Other", display a text input for a new category
   if category == "Other":
      category = st.text_input("Enter new category")

   # If the user has selected a category, display the form
   if category != "Select category":
      name = st.text_input("Name")
      caption = st.text_input("Caption")
      if st.button("Submit"):
            # Convert the image to a file-like object
            img_bytes = BytesIO()
            image.save(img_bytes, format='JPEG')
            img_bytes.seek(0)

            # Submit the form data and the image to the Django app
            data = {
               "name": name,
               "category": category,
               "caption": caption,
            }
            files = {"image": ("image.jpg", img_bytes)}
            response = requests.post(django_url + "image-upload/", data=data, files=files)

            # Display the response from the Django app
            if response.ok:
               parent_image_id = response.json()["id"]
               print(response.content)###
               st.success("Image Map created!")
            else:
               st.error("Failed to create Image Map")



   # Sidebar menu to select the maps to generate
   st.sidebar.title("Select Maps")
   height_map_checkbox = st.sidebar.checkbox("Height Map")
   normals_map_checkbox = st.sidebar.checkbox("Normals Map")
   bump_map_checkbox = st.sidebar.checkbox("Bump Map")
   ambient_occlusion_map_checkbox = st.sidebar.checkbox("Ambient Occlusion Map")
   displacement_map_checkbox = st.sidebar.checkbox("Displacement Map")
   diffusion_map_checkbox = st.sidebar.checkbox("Diffusion Map")
   #generated_images = []

   # Generate and display the selected maps
   if st.button("Generate Maps"):
      def get_image_download_link(img, filename, text):
            pil_img = Image.fromarray(np.uint8(img))
            buffered = BytesIO()
            pil_img.save(buffered, format="JPEG", quality=100)
            img_str = base64.b64encode(buffered.getvalue()).decode()
            href = f'<a href="data:file/jpg;base64,{img_str}" download="{filename}">{text}</a>'
            return href
      # Convert the image to a numpy array
      img_array = np.array(image)

      # generated_images = []

      # Generate the height map
      if height_map_checkbox:
            height = height_map.generate_height_map(img_array)
            st.image(height, caption="Height Map", use_column_width=True)
            generated_images.append(("height_map", height))
            # Add a download button for the generated texture maps
            for map_type, image in generated_images:
               st.markdown(get_image_download_link(image, f"{name}_{map_type}.jpg", f"Download {map_type.capitalize()} Map"), unsafe_allow_html=True)

      # Generate the normals map
      if normals_map_checkbox:
            normals = normals_map.generate_normal_map(img_array)
            st.image(normals, caption="Normals Map", use_column_width=True)
            generated_images.append(("normals_map", normals))

      # Generate the bump map
      if bump_map_checkbox:
            bump = bump_map.generate_bump_map(img_array)
            st.image(bump, caption="Bump Map", use_column_width=True)
            generated_images.append(("bump_map", bump))

      # Generate the ambient occlusion map
      if ambient_occlusion_map_checkbox:
            ao = ambient_occlusion_map.generate_ambient_occlusion_map(img_array, 0.5)
            st.image(ao, caption="Ambient Occlusion Map", use_column_width=True)
            generated_images.append(("ambient_occlusion_map", ao))
            # Generate the displacement map
      if displacement_map_checkbox:
            displacement_map = displacement_map.generate_displacement_map(img_array)
            st.image(displacement_map, caption="Displacement Map", use_column_width=True)
            generated_images.append(("displacement_map", displacement_map))

      # Generate the diffusion map
      if diffusion_map_checkbox:
            diffusion_map = diffusion_map.generate_diffusion_map(img_array)
            st.image(diffusion_map, caption="Diffusion Map", use_column_width=True)
            generated_images.append(("diffusion_map", diffusion_map))
      else:
         st.warning("Please upload an image")

      # Gallery redirect
      st.subheader("or select from our Gallery")
      if st.button("Click me!"):
         js = f"window.location.href='http://localhost:8501/Gallery'"
         html = f"<head><meta http-equiv='refresh' content='0; URL=http://localhost:8501/Gallery' /></head>"
         st.markdown(html, unsafe_allow_html=True)

It looks like this is a Streamlit app for generating image maps. The user can upload an image, select a category, and generate different types of texture maps from the uploaded image. The app also has a button to redirect to a gallery page. Here’s a brief summary of what the code is doing:

Import necessary libraries

Define a list to store generated images

Set the title of the Streamlit app to “Image Maps Generator”

Define the URL of the Django app to submit the image data

Create a dropdown menu to select the category of the image

If the category is “Other”, add a text input field for the new category name

If a category is selected, add text input fields for image name and caption, and a button to submit the form

If an image is uploaded, display the uploaded image and show the sidebar menu to select the maps to generate

If the “Generate Maps” button is clicked, generate the selected maps and display them, and add a download button for each generated map

If no image is uploaded, display a warning message

Add a button to redirect to the gallery page.

textureGen

ambientocclusionmap

import cv2
import numpy as np


def generate_ambient_occlusion_map(image, bias):
   """
   Generates an ambient occlusion map from an input image.
   """
   # Convert image to grayscale
   grayscale = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

   # Normalize the grayscale image to [0, 1]
   normalized = grayscale / 255.0

   # Create a depth map from the normalized image
   depth_map = cv2.Laplacian(normalized, cv2.CV_64F)

   # Compute the ambient occlusion map from the depth map
   kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
   occlusion_map = np.ones_like(depth_map)
   for i in range(3):
      dilated = cv2.dilate(normalized, kernel, iterations=i)
      occlusion_map -= dilated
   occlusion_map = np.clip(occlusion_map + depth_map, 0, 1)

   # Normalize the occlusion map to [0, 255]
   occlusion_map = (occlusion_map * 255).astype(np.uint8)

   # Apply bias to the occlusion map
   occlusion_map = cv2.addWeighted(occlusion_map, 1 - bias, np.zeros_like(occlusion_map), bias, 0)

   return occlusion_map

generate_ambient_occlusion_map generates an ambient occlusion map from the input image.

bumpmap

import cv2
import numpy as np


def generate_bump_map(image):
   """
   Generates a bump map from an input image.
   """
   # Convert image to grayscale
   grayscale = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

   # Calculate the gradient of the grayscale image
   gradient_x = cv2.Sobel(grayscale, cv2.CV_64F, 1, 0)
   gradient_y = cv2.Sobel(grayscale, cv2.CV_64F, 0, 1)

   # Normalize the gradient
   magnitude = np.sqrt(gradient_x**2 + gradient_y**2)
   gradient_x /= magnitude
   gradient_y /= magnitude

   # Adjust the range of the gradient to [0, 255]
   gradient_x = 0.5 * (gradient_x + 1.0) * 255
   gradient_y = 0.5 * (gradient_y + 1.0) * 255

   # Apply a Sobel filter to the grayscale image to calculate the edges
   edges = cv2.Sobel(grayscale, cv2.CV_64F, 1, 1)

   # Combine the edges and the gradient to create a bump map
   bump_map = np.sqrt(edges**2 + gradient_x**2 + gradient_y**2)

   # Normalize the bump map to [0, 255]
   bump_map = (bump_map / bump_map.max()) * 255

   # Convert the bump map to an 8-bit image and return it
   bump_map = bump_map.astype(np.uint8)
   return bump_map

generate_bump_map generates a bump map from the input image.

diffusionmap

import cv2
import numpy as np

def generate_diffusion_map(image):
   # Convert the image to grayscale
   gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

   # Apply bilateral filtering to the grayscale image
   filtered = cv2.bilateralFilter(gray, 9, 75, 75)

   # Compute the difference between the filtered image and the grayscale image
   diff = cv2.absdiff(filtered, gray)

   # Normalize the difference to the range [0, 255]
   diff_norm = cv2.normalize(diff, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)

   # Create the diffusion map by setting the x and y channels to the difference
   diffusion_map = cv2.merge((diff_norm, diff_norm, np.full_like(diff_norm, 255, dtype=np.uint8)))

   return diffusion_map

The generate_diffusion_map function takes in an RGB image and returns a diffusion map.

displacementmap

import cv2
import numpy as np

def generate_displacement_map(image):
   # Convert the image to grayscale
   gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

   # Apply Laplacian edge detection
   laplacian = cv2.Laplacian(gray, cv2.CV_64F)

   # Normalize the Laplacian to the range [0, 255]
   laplacian_norm = cv2.normalize(laplacian, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)

   # Create the displacement map by setting the x and y channels to the Laplacian
   displacement_map = cv2.merge((laplacian_norm, laplacian_norm, np.full_like(laplacian_norm, 255, dtype=np.uint8)))

   return displacement_map

The generate_displacement_map function takes an input image and generates a displacement map.

heightmap

import cv2
import numpy as np

def generate_height_map(image):
   # Convert the image to grayscale
   gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

   # Apply Sobel edge detection in the x and y directions
   sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
   sobel_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)

   # Compute the gradient magnitude
   magnitude = np.sqrt(sobel_x**2 + sobel_y**2)

   # Normalize the magnitude to the range [0, 255]
   normalized_magnitude = cv2.normalize(magnitude, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)

   # Invert the image so that white areas correspond to higher heights
   inverted = cv2.bitwise_not(normalized_magnitude)

   return inverted

This function generates a height map from an input image by computing the gradient magnitude of the image using Sobel edge detection in the x and y directions. The resulting magnitude image is then normalized to the range [0, 255] and inverted so that white areas correspond to higher heights.

The generated height map can be used to simulate a 3D terrain from a 2D image, where the height of each point on the terrain corresponds to the intensity of the corresponding pixel on the height map. This technique is commonly used in video games and other computer graphics applications to generate realistic-looking terrain.

loadimage

import cv2

def load_image(file_path):
   img = cv2.imread(file_path)
   return img

normals_map

import cv2
import numpy as np

def generate_normal_map(image):
   # Convert the image to grayscale
   gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

   # Apply Sobel edge detection in the x and y directions
   sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
   sobel_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)

   # Compute the normal vectors
   normal_x = cv2.normalize(sobel_x, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
   normal_y = cv2.normalize(sobel_y, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
   normal_z = np.full_like(normal_x, 255, dtype=np.uint8)

   # Combine the normal vectors into a 3-channel image
   normal_map = cv2.merge((normal_x, normal_y, normal_z))

   return normal_map

This code generates a normal map from an input image.

roughnessmap

import cv2
import numpy as np

def generate_roughness_map(image):
   # Convert the image to grayscale
   gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

   # Apply the Laplacian operator
   laplacian = cv2.Laplacian(gray, cv2.CV_64F)

   # Compute the variance of the Laplacian
   variance = np.var(laplacian)

   # Normalize the variance to the range [0, 255]
   normalized_variance = cv2.normalize(variance, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)

   # Invert the image so that white areas correspond to rough surfaces
   inverted = cv2.bitwise_not(normalized_variance)

   return inverted

The generate_roughness_map() function takes an input image and generates a roughness map based on the variance of the Laplacian of the grayscale version of the input image.

specularmap

import cv2
import numpy as np


def generate_specular_map(image):
   """
   Generates a specular map from an input image.
   """
   # Convert image to grayscale
   grayscale = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

   # Apply a bilateral filter to smooth the image
   smoothed = cv2.bilateralFilter(grayscale, 9, 75, 75)

   # Calculate the gradient of the smoothed image
   gradient_x = cv2.Sobel(smoothed, cv2.CV_64F, 1, 0)
   gradient_y = cv2.Sobel(smoothed, cv2.CV_64F, 0, 1)

   # Normalize the gradient
   magnitude = np.sqrt(gradient_x**2 + gradient_y**2)
   gradient_x /= magnitude
   gradient_y /= magnitude

   # Calculate the specular map using the normalized gradient
   specular_map = np.power(np.maximum(0, gradient_y), 4)

   # Normalize the specular map to [0, 255]
   specular_map = (specular_map / specular_map.max()) * 255

   # Convert the specular map to an 8-bit image and return it
   specular_map = specular_map.astype(np.uint8)
   return specular_map

This code defines a function generate_specular_map that takes an input image as a parameter and returns a specular map.